Compare commits

..

128 Commits

Author SHA1 Message Date
Michael Niedermayer 239f2c733d Bump micro for 8.1.1
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-04 00:07:35 +02:00
James Almer 6266867e7b avcodec/av1dec: check that primary_ref_frame is within range
Fixes CVE-2026-30997

Fixes: Out-of-Bounds Access
Found-by: Xinghang Lv
Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit 1a2c16fe51)
2026-05-03 15:58:37 -03:00
Michael Niedermayer 2c28491579 Preparing 8.1.1 release
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:42:27 +02:00
Michael Niedermayer 140d581786 avcodec/aac/aacdec_usac_mps212: fix attach_lsb() OOB after huff_decode
Fixes: VS-FF-2026-0001/poc.wav

Reported-by: Vuln Seeker Cyber Security Team
(cherry picked from commit 2e32276872)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:25:01 +02:00
Michael Niedermayer e2c6836694 avcodec/dfpwmdec: Check nb_samples
Fixes: integer overflow

Found-by: Dhiraj Mishra <mishra.dhiraj95@gmail.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 118bddf0ce)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:25:01 +02:00
Michael Niedermayer d2597ecda6 avcodec/alsdec: do not set nbits invalidly
note that the spec actually disallows the 0 case too but we are
a little lenient here so the full 24bit twos-complement range can be handled

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 7ae36ceba9)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:25:00 +02:00
Michael Niedermayer 0a69adf4ee swscale/swscale_unscaled: adjust last line copy
Fixes: out of array access
Fixes: DFVULN-694

*Reporter: Zhenpeng (Leo) Lin at depthfirst*

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 43a0715e30)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:25:00 +02:00
Michael Niedermayer 1d24758bd1 swscale/swscale: Check srcSliceY and srcSliceH
Obviously noone should pass negative values, they make no sense, but better to
explicitly check

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 7d0837a742)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:25:00 +02:00
Michael Niedermayer 0a752b7913 avformat/avidec: check LIST size in avi_load_index()
This avoids an unsigned integer underflow and passing that large value to ff_read_riff_info()

(cherry picked from commit 2678bce860)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:25:00 +02:00
depthfirst-dev[bot] 847b2afc9c avformat/avidec: validate INFO list size before parsing
Reject INFO list chunks that are too small to contain the expected
4-byte list type field before calling ff_read_riff_info().

The parser subtracts 4 from the list size when handing the remaining
payload to ff_read_riff_info(). If the chunk is smaller than 4 bytes,
that underflows the expected structure and should be treated as invalid
input.

Fixes: DFVULN-607

*Vulnerability reported by Zhenpeng (Leo) Lin at depthfirst*
*Patch validated by Zheng Yu at depthfirst*

(cherry picked from commit f1c3f1cae1)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:25:00 +02:00
Michael Niedermayer bad324bd68 avformat/matroskadec: Check audio.sub_packet_h * audio.frame_size
Fixes: out of array access
Fixes: poc_matroska.mkv

This issue requires manually increasing the malloc limit
(-max_alloc 4294967296)

Found-by: Guanni Qu <qguanni@gmail.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit f47ca0a5e6)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:59 +02:00
Michael Niedermayer eaf5015aa8 libavformat/xwma: fix overflow in seek position
Fixes: signed integer overflow

Found-by: Marius Momeu <marius.momeu@berkeley.edu>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 2d4ec46345)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:59 +02:00
Michael Niedermayer e483eb921d avformat/pcm: Use 64bit for byte_rate
Fixes: integer overflow

Found-by: Marius Momeu <marius.momeu@berkeley.edu>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 9d9250e5da)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:59 +02:00
Michael Niedermayer 76dddbc961 avcodec/adpcm: signed integer overflow in ADPCM_N64
Fixes: signed integer overflow

Found-by: Marius Momeu <marius.momeu@berkeley.edu>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit b45a6d3f76)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:59 +02:00
Michael Niedermayer af2a176fd2 avcodec/hevc/ps: validate rep_format dimensions in multi-layer SPS
When an SPS uses the multi-layer extension (nuh_layer_id > 0 with
sps_max_sub_layers_minus1 == 7), width and height are taken from the
VPS rep_format without the av_image_check_size() validation that the
direct path performs.  HEVC F.7.4.3.1.1 requires rep_format pic
dimensions to satisfy the constraints in 7.4.3.2.1, including
"pic_width_in_luma_samples shall not be equal to 0".

Run the same av_image_check_size() check in the multi-layer-extension
path so the SPS is rejected before it reaches setup_pps().

Fixes: VS-FF-2026-0003/poc.flv
Fixes: out of array access

Found-by: Vuln Seeker Cyber Security Team
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 0f5705959d)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:59 +02:00
Marius Momeu 698000f5bd avfilter/vf_kerndeint: Check for minimum height
Fixes: out of array access

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit e32b2c8886)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:59 +02:00
Marius Momeu f6dd450a26 avcodec/ralf: Add the missing return statement after the error log
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit ff3223b5d6)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:58 +02:00
Michael Niedermayer 31855e032c avfilter/vf_codecview: Clamp block to the visible frame region
Fixes: write into the padding area of the frame

Found-by: Marius Momeu <marius.momeu@berkeley.edu>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit c568f40597)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:58 +02:00
Michael Niedermayer 77f2c227c2 avcodec/zmbv: reject XOR data that overruns the decompression buffer
Add a per-block bounds check at the start of each XOR block so the
read is rejected before src crosses decomp_len, and propagate the
error from decode_frame().

Fixes: out of array read

Found-by: Seung Min Shin
(cherry picked from commit 2a991a3475)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:58 +02:00
Michael Niedermayer 102c590a5f avcodec/rasc: fix heap use-after-free in decode_move()
Use a separate scratch buffer (s->mv_scratch) for the type-0 pixel
copy so s->delta and mc are not disturbed for the lifetime of
decode_move().  The new buffer is freed in decode_close().

Found-by: Seung Min Shin
Patch based on suggsted fix by Seung Min Shin

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 2f60af465a)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:58 +02:00
depthfirst-dev[bot] ad62419fb8 avformat/rtpdec_mpeg4: reject zero-length AU header sections
Reject AU header sections with a signaled length of zero in
rtp_parse_mp4_au().

The AU-headers-length field specifies the length in bits of the AU header
section that immediately follows. A zero-length section is not useful input
for this parser and can lead to invalid downstream state, so reject it
up front together with oversized values.

*Vulnerability reported by Zhenpeng (Leo) Lin at depthfirst*
*Patch validated by Zheng Yu at depthfirst*

Fixes: OOB read
(cherry picked from commit 8010aa2193)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:58 +02:00
Niels Provos 874f26fe96 avcodec/hevc/refs: Check multiplication in alloc_frame()
Fixes: integer overflow on 32bit
(cherry picked from commit fd5023053a)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:57 +02:00
depthfirst-dev[bot] dc3742fd7f fftools/ffmpeg_opt: validate stream index in negative map handling
Negative -map processing iterates previously parsed stream map entries
and dereferences input_files[m->file_index]->ctx->streams[m->stream_index]
without validating that stream_index is in range.

A malformed earlier map can leave m->stream_index negative, which causes
an out-of-bounds read when a later negative map walks existing entries.
Check that stream_index is non-negative and below nb_streams before
calling stream_specifier_match().

*Vulnerability reported by Zhenpeng (Leo) Lin at depthfirst*
*Patch validated by Zheng Yu at depthfirst*

Fixes: DFVULN-695
(cherry picked from commit 25a98586cc)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:57 +02:00
Flavio Milan cdd6df0104 avformat/rtmpproto: prevent integer overflow accumulating FLV buffer size
Fixes: out of array access
(cherry picked from commit a45a91b23b)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:57 +02:00
depthfirst-dev[bot] 2d646e5584 avformat/rtmpproto: validate compressed SWF header length
Reject truncated compressed SWF input before attempting to read the
8-byte header in rtmp_calc_swfhash().

Compressed SWF data identified by the "CWS" signature must be at least
8 bytes long to contain the fixed header. Bail out early when the input
is shorter to avoid operating on malformed data.

*Vulnerability reported by Zhenpeng (Leo) Lin at depthfirst*
*Patch validated by Zheng Yu at depthfirst*

Fixes: DFVULN-612
(cherry picked from commit 52b78cd3fe)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:57 +02:00
depthfirst-dev[bot] 62a87e5516 avformat/rtsp: Fix out-of-bounds read in SDP parser when control_url is empty
Guard against empty string before reading the last byte in control_url.
When parsing relative a=control: paths, if no base control URL was set,
the code would access control_url[strlen(control_url)-1] which on an
empty string causes a size_t underflow and out-of-bounds read.

Now compute the length first and check for len == 0 before array access.

*Vulnerability reported by Zhenpeng (Leo) Lin at depthfirst*
*Patch validated by Zheng Yu at depthfirst*

Fixes: DFVULN-611
(cherry picked from commit 1a00ea51cb)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:57 +02:00
depthfirst-dev[bot] 19fc59fde6 avformat/rtpdec_latm: avoid integer overflow in LATM length parsing
latm_parse_packet() accumulated attacker-controlled AU length bytes in
a signed int and later checked data->pos + cur_len against data->len.
That addition could overflow, allowing malformed packets to bypass the
bounds check and drive memcpy() far past the end of the LATM buffer.

Reject length-byte accumulation that would exceed the remaining packet
size, and compare cur_len against the remaining buffer space using
subtraction so the bounds check cannot overflow.

Fixes: DFVULN-610

*Vulnerability reported by Zhenpeng (Leo) Lin at depthfirst*
*Patch validated by Zheng Yu at depthfirst*

(cherry picked from commit 664d44a825)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:57 +02:00
Michael Niedermayer 0ba002f92d avcodec/h264: recompute per-slice direct mode state for every slice
Regression since: 7f05c5cea0
Fixes: poc10
Fixes: null pointer dereference

Reported-by: Dale Curtis <dalecurtis@chromium.org>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 1772386392)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:56 +02:00
Michael Niedermayer 8462c37595 avcodec/h264_refs: Clear stale pointers from ref_list
Testcase: poc10.bin

Reported-by: Dale Curtis <dalecurtis@chromium.org>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 1886c3269d)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:56 +02:00
Michael Niedermayer 6c2e9930b2 avcodec/pdvdec: Check input space before buffer allocation
this rejects packets whose claimed decompressed frame would require a deflate ratio beyond the format's theoretical 1032:1 limit

Fixes: Timeout
Fixes: 474457186/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_PDV_fuzzer-5366108782919680

Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit b801f1fe6d)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:56 +02:00
Kacper Michajłow 5bb3c22021 avformat/concat: guard total_size overflow
Fixes: 466797413/clusterfuzz-testcase-minimized-fuzzer_options_parser-6015183727427584
Signed-off-by: Kacper Michajłow <kasper93@gmail.com>
(cherry picked from commit 702b0784b7)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:56 +02:00
Michael Niedermayer d26ce3ec60 avformat/iamf_parse.c: Fix potential integer overflow in opus_decoder_config()
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 016a241102)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:56 +02:00
Michael Niedermayer d1b0069077 avcodec/wmaenc: Fix missing padding in extradata
Reported-by: Kenan Alghythee <kalghy2@uic.edu>
(cherry picked from commit 23227a444d)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:55 +02:00
Michael Niedermayer 7d612d27ae avformat: Fix various extradata padding issues
Reported-by: Kenan Alghythee <kalghy2@uic.edu>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 8439e02037)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:55 +02:00
Michael Niedermayer 031fae5c41 avcodec/tdsc: remove double stride adjustment
Fixes: out of array access

Found-by: Seung Min Shin
Patch based on suggested fix by Seung Min Shin
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 242ff799c7)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:55 +02:00
depthfirst-dev[bot] f9a9fae557 avformat/cafdec: fix negative index use in read_seek
av_index_search_timestamp() returns a negative value when a seek target
cannot be resolved from the stream index. Bail out before using that
result as an index into sti->index_entries to avoid out-of-bounds reads.

Fixes: Buffer underflow

Fixes: DFVULN-608

*Vulnerability reported by Zhenpeng (Leo) Lin at depthfirst*
*Patch validated by Zheng Yu at depthfirst*

(cherry picked from commit 5408059eb7)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:55 +02:00
Michael Niedermayer 3e57f240cc avcodec/notchlc: Check 255 loops
Fixes: integer overflow

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 05817dc7dd)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:55 +02:00
Michael Niedermayer b5489087f3 avformat/rtpdec_jpeg: check qtable_len
Fixes: out of array access
Fixes: 605/pc.py

Based-on patch by depthfirst

*Reporter: Zhenpeng (Leo) Lin at depthfirst*

(cherry picked from commit 91d29be49a)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:55 +02:00
ASTRA 66d96bd65e avformat/vividas: use-of-uninitialized-value in keybuffer
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 26732641fb)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:54 +02:00
Michael Niedermayer cdfa960ddf avcodec/tdsc: Check jpeg size
Fixes: out of array read
Fixes: tdsc_tile_dim_mismatch.avi

Found-by: Ante Silovic <asilovic155@gmail.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit bb69a090a7)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:54 +02:00
Michael Niedermayer ee35cdda74 avcodec/tdsc: Better input size check
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit bf4eb194cf)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:54 +02:00
Michael Niedermayer e9fc881384 avcodec/tdsc: Check tile_size
Fixes: out of array read
Fixes: tdsc_war_groom_far4096.avi

Found by: Ante Silovic <asilovic155@gmail.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit e9e6fb8798)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:54 +02:00
Michael Niedermayer df197112c2 avcodec/decode: Better documentation for ff_set_dimensions()
Clarify what is checked and that it avoids explicit generic overflow checks

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 9572ab7f45)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:54 +02:00
Dale Curtis 76fd415fce avformat/mov: Limit maximum box size for mov_read_lhvc()
Signed-off-by: Dale Curtis <dalecurtis@chromium.org>
(cherry picked from commit a7d42bfba8)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:53 +02:00
depthfirst-dev[bot] dd2a960971 avformat/mov: reject dimg references with zero entries
Reject dimg entries with a zero reference count in mov_read_iref_dimg().
This is the earliest point where the parser learns how many input images
a derived HEIF item references, so it is the right place to enforce the
invariant.

If entries == 0 is accepted here, the value is stored in HEIFGrid.nb_tiles,
later propagated by read_image_iovl() into AVStreamGroupTileGrid.nb_tiles,
and finally consumed in istg_parse_tile_grid(), which assumes at least one
tile and reads tg->offsets[tg->nb_tiles - 1]. With zero tiles, that
assumption breaks and leads to the out-of-bounds access seen in ASan.

Fixing the problem at the parser boundary is preferable to adding a later
workaround because it prevents creation of an invalid derived-image state
and stops that malformed state from reaching downstream consumers.

This is also consistent with the HEIF specification. Both iovl and grid
derived images are formed from one or more input images, and for grid the
dimg reference count must equal rows * columns; since rows and columns are
encoded as *_minus_one + 1, that count cannot be zero. A zero dimg entry
count is therefore invalid input and should be rejected when parsed.

(cherry picked from commit 68ea660d83)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:53 +02:00
Michael Niedermayer 9e5a493d71 avformat/mov: check extradata in mov_read_dops()
We do want to limit an attackers ability to change once parsed structures.
So once extradata (or another array) is finished and possibly has been used we do not
want to allow an attacker to change it.

This reduces the attack surface

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 7c67748537)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:53 +02:00
Ted Meyer 797504295b avformat/mov: Check read size for opus extradata
in mov_read_dops, `size` bytes is allocated for
`st->codecpar->extradata`, but ff_alloc_extradata doesn't memset, so the
contents of that buffer are just old heap data. If `avio_read` reads
fewer bytes than were requested, uninitialized data can still be left in
the extradata buffer, which is operated on by AV_WL16A and AV_WL32A.

I think the best solution here is to just check the read size and ensure
it's filling the extradata buffer in it's entirety, or erroring out if
there isn't enough data left.

(cherry picked from commit 53cd2c9f2a)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:53 +02:00
depthfirst-dev[bot] a3abd79fde avformat/rtspdec: reject non-positive ANNOUNCE Content-Length
rtsp_read_announce() treated any non-zero Content-Length as valid,
including negative values parsed via strtol(). This could send invalid
sizes into allocation, body reads and trailing NUL writes.

Accept only strictly positive SDP body lengths and reject invalid
Content-Length values with AVERROR_INVALIDDATA.

Found-by: Seung Min Shin (was reported to us on 10th April)
CC: 신승민 <guncraft2000@naver.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit eec78bdac1)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:53 +02:00
ASTRA 01d380bdb2 avformat/wavdec: Fix use-of-uninitialized-value in find_guid()
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 163ba704b7)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:52 +02:00
Marvin Scholz 9cbd7e2589 lavfi: vf_drawtext: check memory allocation
Switch to av_calloc and check the allocation.

Fix #22867

(cherry picked from commit 69072fe8d8)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:52 +02:00
Michael Niedermayer 9601014f1e avcodec/svq1dec: Check input space for minimum
We reject inputs that are significantly smaller than the smallest frame.
This check raises the minimum input needed before time consuming computations are performed
it thus improves the computation per input byte and reduces the potential DoS impact

Fixes: Timeout
Fixes: 472769364/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_SVQ1_DEC_fuzzer-5519737145851904

Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit d538a71ad5)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:52 +02:00
Paul Adenot 5fe5d2a13b avcodec/vp9: Rollback dimensions when format is rejected
Fixes: BMO#2029296

Found-by: Mozilla Security Team, Paul Adenot for the write variant
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 6c114bd6fa)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:52 +02:00
Michael Niedermayer 44fe8891c8 avformat/rtpdec_qdm2: Check block_size
Fixes: out of array access
no testcase

Found-by: Joshua Rogers <joshua@joshua.hu> with ZeroPath
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 29a0973855)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:52 +02:00
Zhao Zhili 5a1dc812b1 avfilter/vf_ssim360: fix integer overflow in tape_length allocation
tape_length * 8 overflows 32-bit int for large input widths. Then
av_malloc_array() allocates a tiny buffer while the subsequent
loop writes tape_length*8 BilinearMap entries, causing
heap-buffer-overflow.

Validate the value in float before converting to int and left
shifting, to avoid both float-to-int and signed left shift
overflow UB. Also split av_malloc_array() arguments to avoid
the multiplication overflow.

Fixes: #21511

Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
(cherry picked from commit b62ae766c1)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:52 +02:00
Michael Niedermayer fa1ac7bd8a avcodec/escape130: Initialize old_y_avg
Fixes: use of uninitialized memory

Found-by: Carl Sampson <carl.sampson@gmail.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit d0761626cf)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:51 +02:00
Michael Niedermayer ea84befff6 avutil/samplefmt: Dont claim that av_get_sample_fmt_string checks sample_fmt
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit b11729f154)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:51 +02:00
Hankang Li d5d2f063ff swscale: fix signed integer overflow in color conversion arithmetic
Fixes: #22331

Signed-off-by: Hankang Li <hankang201222@gmail.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit e33b3962e5)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:51 +02:00
Sankalpa Sarkar 08a31e67af avformat: check avio_read() return values in dss/dtshd/mlv
Multiple demuxers call avio_read() without checking its return
value. When input is truncated, destination buffers remain
uninitialized but are still used for offset calculations, memcmp,
and metadata handling. This results in undefined behavior
(detectable with Valgrind/MSan).

Fix this by checking the return value of avio_read() in:
- dss.c: dss_read_seek() — check before using header buffer
- dtshddec.c: FILEINFO chunk — check before using value buffer
- mlvdec.c: check_file_header() — check before memcmp on version

Fixes: #21520
(cherry picked from commit 65eed0732c)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:51 +02:00
Ruikai Peng 8c7ec4b4b5 avformat/whip: check RTP history packet size before RTX retransmission
handle_rtx_packet() constructs an RTX packet by shifting the payload
of a history entry to insert the original sequence number. It uses
memmove with length (ori_size - 12), but never checks that ori_size
is at least 12 bytes (the minimum RTP header size).

Zero-initialized history slots have seq == 0 and size == 0.
rtp_history_find() only compares sequence numbers, so an RTCP NACK
requesting seq 0 early in a session matches such a slot. The
subtraction then wraps to a huge value when converted to size_t,
causing a stack buffer overflow in memmove().

Add a little size check to reject history entries smaller than and
valid RTP header before any arithmetic on their size.

Found-by: Pwno
(cherry picked from commit 7466d8a850)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:51 +02:00
Michael Niedermayer 0b0a2d236d avcodec/aac/aacdec_usac: Implement missing bits of otts_bands_phase and residual_bands computation
Fixes: out of array access
Fixes: matejsmycka/poc.mp4

Introducing commit: `baad75cafa6bac298b72c177f657a2eb8e31cff1` — "aacdec_usac: add support for parsing Mpsp212 (MPEG surround)", 2025-11-17.

Found-by: Matěj Smyčka <matejsmycka@gmail.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit ddcb9dd3b5)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:50 +02:00
Priyanshu Thapliyal 71818d86ae avcodec/alsdec: preserve full float value in zero-truncated samples
Signed-off-by: Priyanshu Thapliyal <priyanshuthapliyal2005@gmail.com>
(cherry picked from commit d1bcaab230)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:50 +02:00
Priyanshu Thapliyal e927c11cfc avcodec/alsdec: propagate read_diff_float_data() errors in read_frame_data()
The return value of read_diff_float_data() was previously ignored,
allowing decode to continue silently with partially transformed samples
on malformed floating ALS input. Check and propagate the error.

All failure paths in read_diff_float_data() already return
AVERROR_INVALIDDATA, so the caller fix is sufficient without
any normalization inside the function.

Signed-off-by: Priyanshu Thapliyal <priyanshuthapliyal2005@gmail.com>
(cherry picked from commit febc82690d)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:50 +02:00
Priyanshu Thapliyal f5e4bf6dbd avcodec/alsdec: fix mantissa unpacking in compressed Part A path
Signed-off-by: Priyanshu Thapliyal <priyanshuthapliyal2005@gmail.com>
(cherry picked from commit ae6f233988)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:50 +02:00
Zhao Zhili c47b33c61c avfilter/vf_drawtext: fix newline rendered as .notdef glyph
GET_UTF8 advances the pointer past the newline byte before the
newline check, so shape_text_hb receives text that includes the
newline character. Since HarfBuzz does not treat U+000A as
default-ignorable, it gets shaped into a .notdef glyph.

Fixes #21565

Reported-by: scriptituk <info@scriptit.uk>
Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
(cherry picked from commit fd9f1e9c52)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:50 +02:00
Priyanshu Thapliyal f7103aa69e avcodec/pngdec: fix dead overflow check in decode_text_to_exif()
The expression (exif_len & ~SIZE_MAX) is always 0 for size_t,
making the overflow guard permanently dead code.

Reported-by: Guanni Qu <qguanni@gmail.com>
Signed-off-by: Priyanshu Thapliyal <priyanshuthapliyal2005@gmail.com>
(cherry picked from commit e7b4ddc9d6)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:50 +02:00
Kacper Michajłow b81bc90e0c avcodec/vp9: fix cbs fragment leak on error
Fixes: c0bf1382a7
Fixes: 490257166/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_VP9_fuzzer-6185031050788864
Fixes: 490131106/clusterfuzz-testcase-minimized-fuzzer_loadfile-5438205762797568
Signed-off-by: Kacper Michajłow <kasper93@gmail.com>
(cherry picked from commit e17d84ac8a)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:49 +02:00
marcos ashton c3fa0d869b libavfilter/vf_v360: fix operator precedence in stereo loop condition
The loop condition in the DEFINE_REMAP macro:

  stereo < 1 + s->out_stereo > STEREO_2D

is parsed by C as:

  (stereo < (1 + s->out_stereo)) > STEREO_2D

Since STEREO_2D is 0 and relational operators return 0 or 1, the
outer comparison against 0 is a no-op for STEREO_2D and STEREO_SBS.
But for STEREO_TB (value 2) the loop runs 3 iterations instead of 2,
producing an out-of-bounds stereo pass.

Add parentheses so the comparison is evaluated first:

  stereo < 1 + (s->out_stereo > STEREO_2D)

This gives 1 iteration for 2D and 2 for any stereo format (SBS or TB),
matching the actual number of stereo views.

Signed-off-by: marcos ashton <marcosashiglesias@gmail.com>
(cherry picked from commit 9559a6036d)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:49 +02:00
Priyanshu Thapliyal ff129c8f04 avcodec/alsdec: fix abs(INT_MIN) UB in read_diff_float_data()
Replace abs() with FFABSU() to avoid undefined behavior when
raw_samples[c][i] == INT_MIN. Per libavutil/common.h, FFABS()
has the same INT_MIN UB as abs(); FFABSU() is the correct
helper as it casts to unsigned before negation.

Reported-by: Guanni Qu <qguanni@gmail.com>
Signed-off-by: Priyanshu Thapliyal <priyanshuthapliyal2005@gmail.com>
(cherry picked from commit 1853c80e20)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:49 +02:00
Weidong Wang 097668f94c avformat/rsd: reject short ADPCM_THP extradata reads
Use ffio_read_size() to enforce exact-length reads of the per-channel
ADPCM_THP coefficient tables. Previously the return value of
avio_read() was unchecked, silently accepting truncated extradata.

(cherry picked from commit 06d19d000d)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:49 +02:00
Ted Meyer 355269a9f0 avformat/mov: Handle integer overflow in MOV parser
A chromium UBSAN fuzzer caught this instance.

(cherry picked from commit fc7cab6be3)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:49 +02:00
Michael Niedermayer 059489977b avcodec/dvdsub_parser: Fix buf_size check
Fixes: signed integer overflow
Fixes: out of array access
Fixes: dvdsub_int_overflow_mixed_ps.mpg

Found-by: Quang Luong of Calif.io in collaboration with OpenAI Codex
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 1bde76da89)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:48 +02:00
marcos ashton 93b8ad91bf avfilter/af_pan: fix sscanf() return value checks in parse_channel_name
sscanf() returns EOF (-1) on input failure, which is non-zero and
passes a bare truthy check. When this happens, the %n directive is
never processed, so len stays uninitialized. Using that value to
advance the arg pointer causes an out-of-bounds read and crash.

Check for >= 1 instead, matching the fix applied to the other
sscanf() call in init() by commit b5b6391d64.

Fixes: https://code.ffmpeg.org/FFmpeg/FFmpeg/issues/22451
Signed-off-by: marcos ashton <marcosashiglesias@gmail.com>
(cherry picked from commit a43ea8bff7)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:48 +02:00
marcos ashton ff47e29b10 avutil/bswap: fix implicit conversion warning in av_bswap64
Explicitly cast uint64_t arguments to uint32_t before passing them
to av_bswap32(). The truncation is intentional (extracting low and
high halves), but clang on macOS 26 warns about it.

Fixes: https://code.ffmpeg.org/FFmpeg/FFmpeg/issues/22453
Signed-off-by: marcos ashton <marcosashiglesias@gmail.com>
(cherry picked from commit dfa53aae5f)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:48 +02:00
James Almer 3127b0db72 avcodec/h2645_sei: don't use provider_code uninitialized
Regression since 8172be423e.
Fixes Coverity issue CID 1689618.

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit e22a1ed712)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-05-03 19:24:48 +02:00
AdityaTeltia 75d37c499d avformat/hls_sample_encryption: add missing padding for audio setup buffer
Fixes ticket #22890.

The ff_hls_senc_parse_audio_setup_info function passes setup_data to
parsers like avpriv_ac3_parse_header and init_get_bits8 which require
the buffer to be padded with AV_INPUT_BUFFER_PADDING_SIZE bytes at the end.

(cherry picked from commit 71d5fa8d4d)
Signed-off-by: Marvin Scholz <epirat07@gmail.com>
2026-04-28 11:41:32 +02:00
Jun Zhao 7f5c90f77e lavc/videotoolbox_vp9: fix vpcC flags offset
Write the 24-bit vpcC flags field at the current cursor position after
the version byte. The previous code wrote to p+1 instead of p, leaving
one byte uninitialized between version and flags and shifting all
subsequent fields (profile, level, bitdepth, etc.) by one byte.

Signed-off-by: Jun Zhao <barryjzhao@tencent.com>
(cherry picked from commit 19c4bcae68a16ea893b0558d720dd4a2ecd58f0f)
2026-04-15 23:13:24 +08:00
Jun Zhao 0fa756d03d lavc/videotoolboxenc: return SEI parse errors
Return the actual find_sei_end() error when SEI appending fails instead of
reusing the previous status code. This preserves the real parse failure for
callers instead of reporting malformed SEI handling as success.

Signed-off-by: Jun Zhao <barryjzhao@tencent.com>
(cherry picked from commit f7c04283367269c7aef2505a1839fb3ea9362330)
2026-04-15 23:13:24 +08:00
Stéphane Cerveau 735c84b57f vulkan: fix encode feedback query handling
Check that the driver supports both BUFFER_OFFSET and BYTES_WRITTEN
encode feedback flags before creating the query pool, failing with
EINVAL if either is missing.

Set these flags explicitly instead of masking off HAS_OVERRIDES with a
bitwise NOT, which could pass unrecognized bits from newer drivers to
vkCreateQueryPool causing validation errors and
crashes.

(cherry picked from commit 3f9e04b489)
2026-04-14 23:32:41 +02:00
James Almer a3475e2554 avcodec/cbs_lcevc: fix writing process blocks with size 6
6 is an undefined value for payload_size_type. For those, 7 is used to signal
a custom_byte_size synxtax element.

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit 35a1e43a6a)
2026-03-24 18:06:22 -03:00
James Almer bd7f101bda avformat/mov: don't try to create an LCEVC group if there's a single track
In this scenario, as it's the case with DASH segments, the lcevc track will be
alone but potentially have a sbas tref entry referencing itself, which will
make avformat_stream_group_add_stream() fail.

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit e1158301f0)
2026-03-23 10:51:59 -03:00
Martin Storsjö 3ec48e4bc6 aarch64: Add Armv9.3-A GCS (Guarded Control Stack) support
Signal that our assembly is compliant with the GCS feature, if
the GCS feature is enabled in the compiler (available since Clang
18 and GCC 15) - this is enabled by -mbranch-protection=standard
with a new enough compiler.

GCS doesn't require any specific modifications to the assembly
code, but requires that all functions return to the expected call
address (checked through a shadow stack).

(cherry picked from commit 846746be4b)
2026-03-20 13:12:08 +02:00
Martin Storsjö 2bb6264105 aarch64: hevcdsp: Make returns match the call site
For cases when returning early without updating any pixels, we
previously returned to return address in the caller's scope,
bypassing one function entirely. While this may seem like a neat
optimization, it makes the return stack predictor mispredict
the returns - which potentially can cost more performance than
it gains.

Secondly, if the armv9.3 feature GCS (Guarded Control Stack) is
enabled, then returns _must_ match the expected value; this feature
is being enabled across linux distributions, and by fixing the
hevc assembly, we can enable the security feature on ffmpeg as well.

(cherry picked from commit 1f7ed8a78d)
2026-03-20 13:12:04 +02:00
James Almer 9abdfda6f2 avcodec/lcevcdec: don't try to derive final dimensions from SAR
Not only do some sources not provide an aspect ratio, as is the case of
MPEG-TS, but also some enhanced streams have no change in dimensions, and this
heuristic would generate bugus values.
Instead, we need to parse the LCEVC bitstream for a Global Config process block
in order to get the actual dimensions. This add a little overhead, but it can't
be avoided.

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit 49d75d81f6)
2026-03-18 13:35:56 -03:00
James Almer 395dc6fa27 avcodec/lcevc_parser: move the resolution type table to a header
Will be useful in the following commit.

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit c5aa31d252)
2026-03-18 13:35:56 -03:00
James Almer a2e15f15b0 avcodec/cbs_lcevc: don't look for process blocks if the unit was not decomposed
Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit ce7375fc17)
2026-03-18 13:35:56 -03:00
Marvin Scholz 9047fa1b08 avutil: attributes: fix AV_HAS_STD_ATTRIBUTE checks
Attributes with the language-supported [[attr]] style are only supported
since C++11 and C23 respectively, so this needs to be accounted for in
these checks.

This solves a huge amount of warning spam of:
  warning: [[]] attributes are a C23 extension [-Wc23-extensions]
when using --enable-extra-warnings.

(cherry picked from commit cce545a74b)
Signed-off-by: Marvin Scholz <epirat07@gmail.com>
2026-03-16 18:46:24 +01:00
Michael Niedermayer e1a84cd003 doc/Doxyfile: set version to 8.1
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-16 17:24:34 +01:00
Michael Niedermayer 5c923e26ab avformat/wsddec: Use ffio_read_size() in get_metadata()
Fixes: use of uninitialized memory
Fixes: 492587173/clusterfuzz-testcase-minimized-ffmpeg_dem_WSD_fuzzer-6596163492184064

Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 4b83833087)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-16 17:23:47 +01:00
Nicholas Carlini c471fce2bf avformat/mpegts: fix descriptor accounting across multiple IOD descriptors
pmt_cb() passes mp4_descr + mp4_descr_count as the output base but
MAX_MP4_DESCR_COUNT (16) as the capacity, not the remaining capacity.
init_MP4DescrParseContext() resets d->descr_count to 0 on every call,
so the bounds check at parse_MP4ESDescrTag compares a fresh 0 against
16 regardless of the shifted base.

A PMT with two IOD descriptors of 16 ESDescrs each will crash. The first
fills the buffer mp4_descr[0..15], and then the second writes
mp4_descr[16..31] -- 1152 bytes past the end of the stack.

This change passes the remaining capacity instead of always passing 16.
The writeback in mp4_read_iods is incremented so the caller's running
count is preserved.

Fixes: stack-buffer-overflow

Found-by: Nicholas Carlini <nicholas@carlini.com>
(cherry picked from commit 3e8bec7871)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-16 17:23:47 +01:00
Weidong Wang 5f3122760f avcodec/xxan: zero-initialize y_buffer
Fixes ticket #22420.

When the first decoded frame is type 1, xan_decode_frame_type1() reads y_buffer as prior-frame state before any data has been written to it.
Since y_buffer is allocated with av_malloc(), this may propagate uninitialized heap data into the decoded luma output.

Allocate y_buffer with av_mallocz() instead.

(cherry picked from commit 236dbc9f82)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-16 17:23:47 +01:00
Anton Khirnov 43a4771cd0 opus/dec_celt: avoid emph_coeff becoming a subnormal
This happens for silence frames, which on many CPUs massively slows down
processing the decoded output.

Cf. https://github.com/Genymobile/scrcpy/issues/6715

(cherry picked from commit 5b112b17c0)
2026-03-16 11:53:14 +01:00
Michael Niedermayer 8a8881d226 RELEASE: prepare for 8.1
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-16 03:42:03 +01:00
Michael Niedermayer 7dad4d2cb5 Changelog, remove "version <next>" 2026-03-16 03:42:03 +01:00
Michael Niedermayer a5a1653a9e RELEASE_NOTES: Based on the version from 8.0
Name suggested by 2 people on ML, all other suggestions had only 1 supporter

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-16 03:42:03 +01:00
James Almer 0a8bf5fcaa avcodec/bsf/extract_extradata: don't use a NULL pointer to initialize an empty PutByteContext
Fixes UB in the form or adding a 0 offset to a NULL pointer, and substracting a
NULL pointer from another.

Signed-off-by: James Almer <jamrial@gmail.com>
2026-03-15 19:44:21 -03:00
James Almer 29e0d0ef13 avcodec/h2645_sei: fix parsing payloads for UK country_code
The correct syntax after country_code is:

t35_uk_country_code_second_octet      b(8)
t35_uk_manufacturer_code_first_octet  b(8)
t35_uk_manufacturer_code_second_octet b(8)

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit 8172be423e)
2026-03-15 17:46:51 -03:00
James Almer 93c915a572 avcodec/h2645_sei: reindent after the previous change
Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit 3af824a540)
2026-03-15 17:46:51 -03:00
James Almer fcbbd8b394 avcodec/h2645_sei: refactor decode_registered_user_data()
Switch statements are cleaner and will be useful for an upcoming change.

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit 64edbb37f1)
2026-03-15 17:46:51 -03:00
Zhao Zhili 7df9a56f0d avformat/rtmpproto: fix listen_timeout conversion for special negative values
rtmpproto converts listen_timeout to milliseconds by multiplying it
by 1000 before passing it to TCP. However, negative values are special
sentinels (e.g., -1 for infinite wait) and should not be multiplied.

This worked prior to commit 49c6e6cc44 because there was no range
validation. Since that commit, ff_parse_opts_from_query_string
validates option values against their declared ranges, causing these
multiplied negative values to fail.

Fixes ticket #22469.

Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
(cherry picked from commit f189657ec6)
Signed-off-by: Marvin Scholz <epirat07@gmail.com>
2026-03-15 03:15:37 +00:00
Michael Niedermayer 6f890cb104 avcodec/exr: Check input space before reverse_lut()
Fixes: use of uninitialized memory
Fixes: 490707906/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_EXR_DEC_fuzzer-6310933506097152

Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 70286d59f1)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:58 +01:00
Nicholas Carlini 42692d0f57 avformat/mpegts: remove JPEG-XS early return on invalid header_size
new_pes_packet() moves a buffer with pkt->buf = pes->buffer before
JPEG-XS validation. If header_size > pkt->size, an early return leaves
pes->buffer as a stale alias of pkt->buf with refcount 1. Later,
mpegts_read_packet() calls av_packet_unref(), freeing the buffer
through pkt->buf. The flush loop then re-enters new_pes_packet() and
dereferences the dangling pes->buffer; a second path hits it via
av_buffer_unref() in handle_packets() after a seek.

Drop the early return. The packet is delivered with AV_PKT_FLAG_CORRUPT
set, matching the PES-size-mismatch case above, and the function falls
through to the normal cleanup path. The else guards the header trim so
pkt->data/pkt->size stay valid for the memset.

Fixes: use after free
Fixes regression since 16f89d342e.

Found-by: Nicholas Carlini <nicholas@carlini.com>
(cherry picked from commit 55bf0e6cd5)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:58 +01:00
Michael Niedermayer 259ee609ac avcodec/aac/aacdec_usac_mps212: Introduce a temporary array for ff_aac_ec_data_dec()
This also reverts: c2364e9222

Fixes: out of array access (testcase exists but did not replicate for me)

Founbd-by: Gil Portnoy <dddhkts1@gmail.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 770bc1c23a)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:58 +01:00
Michael Niedermayer b6a617c8bf avcodec/cbs_h266_syntax_template: Check tile_y
Fixes: invalid state leading to out of array access
Fixes: 490615782/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_VVC_fuzzer-4711353817563136

Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 12303cd922)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:58 +01:00
Nicholas Carlini a5696b44a6 avcodec/h264_slice: reject slice_num >= 0xFFFF
An H.264 picture with 65536 slices makes slice_num collide with the
slice_table sentinel. slice_table is uint16_t, initialized via
memset(..., -1, ...) so spare entries (one per row, mb_stride =
mb_width + 1) stay 0xFFFF. slice_num is an uncapped ++h->current_slice.
At slice 65535 the collision makes slice_table[spare] == slice_num
pass, defeating the deblock_topleft check in xchg_mb_border and the
top_type zeroing in fill_decode_caches.

With both guards bypassed at mb_x = 0, top_borders[top_idx][-1]
underflows 96 bytes and XCHG writes at -88 below the allocation
(plus -72 and -56 for chroma in the non-444 path).

Fixes: heap-buffer-overflow

Found-by: Nicholas Carlini <nicholas@carlini.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 39e1969303)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:57 +01:00
Jun Zhao 5bc4a9898c lavfi/bwdif: fix heap-buffer-overflow with small height videos
Reproduce:
  ffmpeg -i /tmp/bwdif_test_input_160x4_gray16.jpg -vf "bwdif" -f null -

filter_intra accesses rows 3 lines away via cur[mrefs3] and cur[prefs3].
For small height videos (h <= 4), this causes heap-buffer-overflow.

Add boundary check for filter_intra when YADIF_FIELD_END is set.
The boundary condition (y < 3) or (y + 3 >= td->h) precisely matches
filter_intra's 3-line context requirement.

Test file: 160x4 gray16 JPEG
https://code.ffmpeg.org/attachments/db2ace24-bc00-4af6-a53a-5df6b0d51b15

fix #21570

Reviewed-by: Thomas Mundt <tmundt75@gmail.com>
Signed-off-by: Jun Zhao <barryjzhao@tencent.com>
(cherry picked from commit 795bccdaf5)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:57 +01:00
Michael Niedermayer b6faea362a avcodec/wmv2dec: More Checks about reading skip bits
Fixes: out of array read with --disable-safe-bitstream-reader
Fixes: poc_wmv2.avi

Note, this requires the safe bitstream reader to be turned off by the user and the user disregarding the security warning

Change suggested by: Guanni Qu <qguanni@gmail.com>
Found-by: Guanni Qu <qguanni@gmail.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit f73849887c)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:57 +01:00
Gil Portnoy ca6e0ee7aa avcodec/cbs_h266_syntax_template: Fix w/h typo
Fixes: out of array access
Fixes: vvc_poc_subpic_wh_bug.h266

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 26dd9f9b56)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:57 +01:00
Oliver Chang f851191ce6 aacdec_usac: skip FD-specific decoding for LPD channels
`spectrum_decode` currently executes Frequency Domain (FD) decoding steps
for all channels, regardless of their `core_mode`. When a channel is in
Linear Prediction Domain (LPD) mode (`core_mode == 1`), FD-specific
parameters such as scalefactor offsets (`sfo`) and individual channel
stream (`ics`) information are not parsed.

This causes a global-buffer-overflow in `dequant_scalefactors`. Because
`spectrum_scale` is called on LPD channels, it uses stale or
uninitialized `sfo` values to index `ff_aac_pow2sf_tab`. In the reported
crash, a stale `sfo` value of 240 resulted in an index of 440
(240 + POW_SF2_ZERO), exceeding the table's size of 428.

Fix this by ensuring `spectrum_scale` and `imdct_and_windowing` are only
called for channels where `core_mode == 0` (FD).

Co-authored-by: CodeMender <codemender-patching@google.com>
Fixes: https://issues.oss-fuzz.com/486160985
(cherry picked from commit d519ab8993)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:57 +01:00
Michael Niedermayer 60f3904718 avformat/dhav: Fix handling or slightly larger files
Fixes: integer overflow
Fixes: 490241718/clusterfuzz-testcase-minimized-ffmpeg_dem_DHAV_fuzzer-4902512932225024

Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit c5d5fb2309)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:57 +01:00
Michael Niedermayer 56217dccd6 avutil/timecode: Check for integer overflow in av_timecode_init_from_components()
Fixes: integer overflow
Fixes: testcase that calls av_timecode_init_from_components() with hh set explicitly to INT_MAX

Found-by: Youngjae Choi, Mingyoung Ban, Seunghoon Woo
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit eb5d607861)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:56 +01:00
Gil Portnoy 4f72addce1 avcodec/cbs_h266_syntax_template: Fix rows vs columns
Fixes: out of array access
Fixes: vvc_poc_cbs_divergence_max.h266

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 51606de0e9)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:56 +01:00
Ted Meyer 1f217b4b7d avformat/mov: do not allocate out-of-range buffers
There's a possibility here with a well-crafted MP4 file containing only
the nested boxes in order: MOOV.TRAK.MDIA.MINF.STBL.SDTP where the
header size uses the 64 bit large size, and the ending stdp box has some
size value >= 0x100000014.

On a 32 bit build of ffmpeg, av_malloc's size parameter drops the high
order bits of `entries`, and and the allocation is now a controlled size
that is significantly smaller than `entries`. The following loop will
then write off the ended of allocated memory with data that follows the
box fourcc.

(cherry picked from commit 86f53f9ffb)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:56 +01:00
Karl Mogensen 0ce7bd66a7 avfilter/af_lv2: call lilv_instance_activate before lilv_instance_run
Why: the change is done to comply with lilv expectations of hosts.

Added call lilv_instance_activate in the config_output function to abide by lilv documentation that states it must be called before lilv_instance_run:
"This MUST be called before calling lilv_instance_run()" - documentation source (https://github.com/lv2/lilv/blob/main/include/lilv/lilv.h)

Added call lilv_instance_deactivate in the uninit function to abide by lv2 documentation:
"If a host calls activate(), it MUST call deactivate() at some point in the future" - documentation source (https://gitlab.com/lv2/lv2/-/blob/main/include/lv2/core/lv2.h)

Added instance_activated integer to LV2Context struct to track if instance was activated and only do lilv_instance_deactivate if was activated to abide by lv2 documentation:
"Hosts MUST NOT call deactivate() unless activate() was previously called." - documentation source (https://gitlab.com/lv2/lv2/-/blob/main/include/lv2/core/lv2.h)

Regarding the patcheck warning (possibly constant :instance_activated):
This is a false positive since the struct member is zero-initialized.

Fixes: trac issue #11661 (https://trac.ffmpeg.org/ticket/11661)
Reported-by: Dave Flater
Signed-off-by: Karl Mogensen <karlmogensen0@gmail.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit fa281d1394)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:56 +01:00
Zhao Zhili 2803bcd5d5 avformat/rtmpproto: fix listen_timeout conversion for special negative values
rtmpproto converts listen_timeout to milliseconds by multiplying it
by 1000 before passing it to TCP. However, negative values are special
sentinels (e.g., -1 for infinite wait) and should not be multiplied.

This worked prior to commit 49c6e6cc44 because there was no range
validation. Since that commit, ff_parse_opts_from_query_string
validates option values against their declared ranges, causing these
multiplied negative values to fail.

Fixes ticket #22469.

Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
(cherry picked from commit f189657ec6)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:56 +01:00
Michael Niedermayer 2cf15d3fc0 avcodec/aom_film_grain: Remove impossible check
fgp is freshly allocated so it cannot be equal to ref

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit b4b569f922)
2026-03-15 00:49:55 +01:00
Michael Niedermayer c9cf8cf9c3 avcodec/aom_film_grain: avoid duplicate indexes in ff_aom_parse_film_grain_sets()
Fixes: use after free
Fixes: 478301106/clusterfuzz-testcase-minimized-ffmpeg_dem_HEVC_fuzzer-6155792247226368

Found-by:  continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit ebb6ac1bc7)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:55 +01:00
Michael Niedermayer 21719ece26 avformat/hxvs: Do not allow backward steps in hxvs_probe()
Fixes: infinite loop
Fixes: 487632033/clusterfuzz-testcase-minimized-ffmpeg_dem_IMAGE2_fuzzer-4565877872984064

Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 4ccad70d57)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:55 +01:00
Michael Niedermayer b842218402 swscale/output: fix integer overflows in chroma in yuv2rgba64_X_c_template()
Fixes: signed integer overflow: 130489 * 16525 cannot be represented in type 'int'
Fixes: 488950053/clusterfuzz-testcase-minimized-ffmpeg_SWS_fuzzer-4627272670969856

Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 3b98e29da8)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:55 +01:00
Michael Niedermayer c88ae59e31 avcodec/lcldec: Fixes uqvq overflow
Fixes: integer overflow
Fixes: 490241717/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_ZLIB_DEC_fuzzer-4560518961758208

Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 7241b80422)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:55 +01:00
Olivier Laflamme 711b69c615 fftools/ffprobe: Initialize data_dump_format_id
This was used uninitialized previously

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 10d36e5d3d)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:55 +01:00
Michael Niedermayer 511387e49a avformat/aiffdec: Check for partial read
Fixes: read of uninitialized memory
Fixes: 490305404/clusterfuzz-testcase-minimized-ffmpeg_dem_AIFF_fuzzer-6406386140643328

Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit ba0f8083fd)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
2026-03-15 00:49:54 +01:00
Lynne c9a5f7c6ca hwcontext_vulkan: deprecate AVVulkanDeviceContext.lock/unlock_queue
Without replacement, as VK_KHR_internally_synchronized_queues will be required.

(cherry picked from commit c102e89448)
2026-03-14 18:54:46 +01:00
James Almer 680ac1aa32 avcodec/lcevc_parser: check return value of init_get_bits8()
Fixes coverity issue CID 1684198.

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit a9984fec81)
2026-03-13 09:06:53 -03:00
James Almer b013bbf092 avcodec/lcevc_parser: Check that block_size is not negative
Based on 248b481c33

Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit 125bb2e045)
2026-03-13 09:06:53 -03:00
Michael Niedermayer d8d4a96414 avcodec/bsf/extract_extradata: Replace incorrect size accounting
Fixes: out of array writes
Fixes: 492054712/clusterfuzz-testcase-minimized-ffmpeg_BSF_EXTRACT_EXTRADATA_fuzzer-5705993148497920

Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit f84c859ec5)
2026-03-12 23:17:53 -03:00
Lynne b1da475805 ffv1enc_vulkan: fix typo
Fixes a segfault when host mapping is unsupported.

(cherry picked from commit 215e22d1f1)
2026-03-10 19:32:38 +01:00
nyanmisaka b6db764c86 fftools/ffmpeg: fix read_key() always return 255 when there was no input
fixup 08d327e

When an uchar is set to -1, it will become 255 when read as an int.
Duplicate variables for two terminal types can also avoid unused variable warnings.

(cherry picked from commit 3f10a054dc)

Signed-off-by: nyanmisaka <nst799610810@gmail.com>
Signed-off-by: Kacper Michajłow <kasper93@gmail.com>
2026-03-09 17:17:17 +01:00
Michael Niedermayer 0ab823b47a avcodec/bsf/extract_extradata: Check that block_size is not negative
Fixes: out of array access
Fixes: 490576036/clusterfuzz-testcase-minimized-ffmpeg_BSF_EXTRACT_EXTRADATA_fuzzer-4605696279904256

Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
(cherry picked from commit 248b481c33)
Signed-off-by: James Almer <jamrial@gmail.com>
2026-03-08 20:36:52 -03:00
1763 changed files with 33220 additions and 89258 deletions
-24
View File
@@ -57,7 +57,6 @@ libavcodec/.*png.* @Traneptora
libavcodec/.*prores.* @lynne
libavcodec/rangecoder.* @michaelni
libavcodec/ratecontrol.* @michaelni
libavcodec/rkmpp* @quink
libavcodec/rv60.* @pross
libavcodec/sgirle.* @pross
libavcodec/.*siren.* @lynne
@@ -110,7 +109,6 @@ libavfilter/vf_find_rect.* @michaelni
libavfilter/vf_icc.* @haasn
libavfilter/vf_libplacebo.* @haasn
libavfilter/vf_libvmaf.* @kylophone
libavfilter/vf_mpdecimate.* @dana-feng
libavfilter/vf_premultiply.* @haasn
libavfilter/vf_scale.* @haasn
libavfilter/vf_scale_vt.* @quink
@@ -141,8 +139,6 @@ libavformat/electronicarts.* @pross
libavformat/.*exif.* @Traneptora
libavformat/filmstrip.* @pross
libavformat/frm.* @pross
libavformat/hls.* @kasper93
libavformat/hxvs.* @quink
libavformat/iamf.* @jamrial
libavformat/icecast.c @ePirat
libavformat/ico.* @pross
@@ -157,7 +153,6 @@ libavformat/mlv.* @pross
libavformat/mm.* @pross
libavformat/msp.* @pross
libavformat/mv.* @pross
libavformat/ogg.* @toots
libavformat/pp_bnk.* @zane
libavformat/rm.* @pross
libavformat/sauce.* @pross
@@ -198,7 +193,6 @@ libavutil/aarch64/.* @lynne @mstorsjo
libavutil/arm/.* @mstorsjo
libavutil/ppc/.* @sean_mcg
libavutil/riscv/.* @Courmisch
libavutil/wasm/.* @quink
libavutil/x86/.* @lynne
# swresample
@@ -232,26 +226,8 @@ doc/.* @GyanD
# tests
# =====
tests/checkasm/riscv/.* @Courmisch
libavutil/tests/ambient_viewing_environment.* @MarcosAsh
libavutil/tests/buffer.* @MarcosAsh
libavutil/tests/csp.* @MarcosAsh
libavutil/tests/dovi_meta.* @MarcosAsh
libavutil/tests/hdr_dynamic_vivid_metadata.* @MarcosAsh
libavutil/tests/mastering_display_metadata.* @MarcosAsh
libavutil/tests/tdrdi.* @MarcosAsh
libavutil/tests/timestamp.* @MarcosAsh
libavutil/tests/video_hint.* @MarcosAsh
tests/ref/.*drawvg.* @ayosec
tests/ref/fate/ambient_viewing_environment @MarcosAsh
tests/ref/fate/buffer @MarcosAsh
tests/ref/fate/csp @MarcosAsh
tests/ref/fate/dovi_meta @MarcosAsh
tests/ref/fate/hdr_dynamic_vivid_metadata @MarcosAsh
tests/ref/fate/mastering_display_metadata @MarcosAsh
tests/ref/fate/sub-mcc.* @programmerjake
tests/ref/fate/tdrdi @MarcosAsh
tests/ref/fate/timestamp @MarcosAsh
tests/ref/fate/video_hint @MarcosAsh
# Forgejo
# =======
-14
View File
@@ -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
```
-->
-40
View File
@@ -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; }
-174
View File
@@ -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()
+4 -19
View File
@@ -1,14 +1,5 @@
exclude: ^tests/ref/
# This repository keeps its pre-commit config in this nondefault path.
# Install hooks from here with:
# pre-commit install -c .forgejo/pre-commit/config.yaml
# The command above installs both the pre-commit and commit-msg hooks because
# default_install_hook_types includes them below.
default_install_hook_types:
- pre-commit
- commit-msg
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
@@ -29,15 +20,9 @@ repos:
- id: trailing-whitespace
- repo: local
hooks:
- id: check-commit-message
name: validate commit message format
language: script
entry: ./tools/check_commit_msg.sh
stages: [commit-msg]
always_run: true
- id: arm-asm-indent
name: fix arm/aarch64 assembly indentation
files: ^.*/(arm|aarch64)/.*\.S$
- id: aarch64-asm-indent
name: fix aarch64 assembly indentation
files: ^.*/aarch64/.*\.S$
language: script
entry: ./tools/check_arm_indent.sh --apply
pass_filenames: false
@@ -48,4 +33,4 @@ repos:
args:
- --ignore-words=.forgejo/pre-commit/ignored-words.txt
- --ignore-multiline-regex=codespell:off.*?(codespell:on|\Z)
exclude: ^tools/(patcheck|clean-diff)|tests/checkasm/ext/.*$
exclude: ^tools/(patcheck|clean-diff)$
-1
View File
@@ -69,7 +69,6 @@ pEvents
PixelX
Psot
quater
re-use
readd
recuse
redY
-1
View File
@@ -22,7 +22,6 @@ jobs:
with:
configuration-path: .forgejo/labeler/labeler.yml
repo-token: ${{ secrets.AUTOLABELER_TOKEN }}
sync-labels: true
- name: Label by title-match
uses: actions/github-script@v8
with:
-2
View File
@@ -16,8 +16,6 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Rebase onto target branch
uses: ./.forgejo/actions/rebase-pr
- name: Install pre-commit CI
id: install
run: |
+4 -31
View File
@@ -29,8 +29,6 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Rebase onto target branch
uses: ./.forgejo/actions/rebase-pr
- name: Configure
run: |
./configure --enable-gpl --enable-nonfree --enable-memory-poisoning --assert-level=2 \
@@ -60,20 +58,11 @@ jobs:
with:
path: fate-suite
key: fate-suite-${{ steps.fate.outputs.hash }}
- name: Inject PR Samples
id: inject
if: ${{ forge.event_name == 'pull_request' }}
run: SAMPLES=$PWD/fate-suite .forgejo/inject-pr-samples.py ${{ forge.event.pull_request.number }}
- name: Run Fate
run: |
LD_LIBRARY_PATH="$(printf "%s:" "$PWD"/lib*)$PWD" make fate fate-build SAMPLES="$PWD/fate-suite" -j$(nproc) || FATERES=$?
find . -name "*.err" -exec printf '::group::%s\n' {} \; -exec cat {} \; -exec printf '::endgroup::\n' \;
exit ${FATERES:-0}
- name: Fail if new samples were injected
if: ${{ steps.inject.outputs.new_samples == 'true' }}
run: |
echo "New FATE samples were injected from PR attachments. Please add them to the official fate-suite before merging."
exit 1
run_fate_full:
name: Fate (Full, ${{ matrix.target_exec }})
strategy:
@@ -86,16 +75,9 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
with:
path: ffmpeg
- name: Rebase onto target branch
uses: ./ffmpeg/.forgejo/actions/rebase-pr
with:
path: ffmpeg
- name: Configure
run: |
mkdir build && cd build
../ffmpeg/configure --pkg-config-flags="--static" $FFBUILD_TARGET_FLAGS $FF_CONFIGURE \
./configure --pkg-config-flags="--static" $FFBUILD_TARGET_FLAGS $FF_CONFIGURE \
--cc="$CC" --cxx="$CXX" --ar="$AR" --ranlib="$RANLIB" --nm="$NM" \
--extra-cflags="$FF_CFLAGS" --extra-cxxflags="$FF_CXXFLAGS" \
--extra-libs="$FF_LIBS" --extra-ldflags="$FF_LDFLAGS" --extra-ldexeflags="$FF_LDEXEFLAGS" \
@@ -105,7 +87,7 @@ jobs:
cat ffbuild/config.log
exit ${CFGRES:-0}
- name: Build
run: make -C build -j$(nproc)
run: make -j$(nproc)
- name: Restore Cached Fate-Suite
id: cache
uses: actions/cache/restore@v5
@@ -117,7 +99,7 @@ jobs:
- name: Sync Fate-Suite
id: fate
run: |
make -C build fate-rsync SAMPLES=$PWD/fate-suite
make fate-rsync SAMPLES=$PWD/fate-suite
echo "hash=$(find fate-suite -type f -printf "%P %s %T@\n" | sort | sha256sum | cut -d' ' -f1)" >> $FORGEJO_OUTPUT
- name: Cache Fate-Suite
uses: actions/cache/save@v5
@@ -125,21 +107,12 @@ jobs:
with:
path: fate-suite
key: fate-suite-${{ steps.fate.outputs.hash }}
- name: Inject PR Samples
id: inject
if: ${{ forge.event_name == 'pull_request' }}
run: SAMPLES=$PWD/fate-suite ffmpeg/.forgejo/inject-pr-samples.py ${{ forge.event.pull_request.number }}
- name: Run Fate
run: |
if [[ "${{ matrix.target_exec }}" == "wine" ]]; then
export WINEDEBUG=-all
export FREI0R_PATH="$(winepath -w "$FREI0R_PATH")"
fi
LD_LIBRARY_PATH="$(printf "%s:" "$PWD"/lib*)$PWD" make -C build fate fate-build SAMPLES="$PWD/fate-suite" -j$(nproc) || FATERES=$?
LD_LIBRARY_PATH="$(printf "%s:" "$PWD"/lib*)$PWD" make fate fate-build SAMPLES="$PWD/fate-suite" -j$(nproc) || FATERES=$?
find . -name "*.err" -exec printf '::group::%s\n' {} \; -exec cat {} \; -exec printf '::endgroup::\n' \;
exit ${FATERES:-0}
- name: Fail if new samples were injected
if: ${{ steps.inject.outputs.new_samples == 'true' }}
run: |
echo "New FATE samples were injected from PR attachments. Please add them to the official fate-suite before merging."
exit 1
-6
View File
@@ -26,9 +26,6 @@
*.spv
*.spv.c
*.spv.gz
*.gen.asm
*.gen.c
*.gen.S
*.ptx
*.ptx.c
*.ptx.gz
@@ -40,9 +37,6 @@
/ffmpeg
/ffplay
/ffprobe
/checkasm_config_generated.asm
/checkasm_config_generated.h
/checkasm_header_config_generated.h
/config.asm
/config.h
/config_components.asm
-1
View File
@@ -1,5 +1,4 @@
# Note to Github users
Patches should be submitted to [Forgejo](https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls) or the [ffmpeg-devel mailing list](https://ffmpeg.org/mailman/listinfo/ffmpeg-devel) using `git format-patch` or `git send-email`. Github pull requests should be avoided because they are not part of our review process and **will be ignored**.
See [https://ffmpeg.org/developer.html#Contributing](https://ffmpeg.org/developer.html#Contributing) for more information.
+83 -26
View File
@@ -1,32 +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.1:
avcodec/aac/aacdec_usac_mps212: fix attach_lsb() OOB after huff_decode
avcodec/dfpwmdec: Check nb_samples
avcodec/alsdec: do not set nbits invalidly
swscale/swscale_unscaled: adjust last line copy
swscale/swscale: Check srcSliceY and srcSliceH
avformat/avidec: check LIST size in avi_load_index()
avformat/avidec: validate INFO list size before parsing
avformat/matroskadec: Check audio.sub_packet_h * audio.frame_size
libavformat/xwma: fix overflow in seek position
avformat/pcm: Use 64bit for byte_rate
avcodec/adpcm: signed integer overflow in ADPCM_N64
avcodec/hevc/ps: validate rep_format dimensions in multi-layer SPS
avfilter/vf_kerndeint: Check for minimum height
avcodec/ralf: Add the missing return statement after the error log
avfilter/vf_codecview: Clamp block to the visible frame region
avcodec/zmbv: reject XOR data that overruns the decompression buffer
avcodec/rasc: fix heap use-after-free in decode_move()
avformat/rtpdec_mpeg4: reject zero-length AU header sections
avcodec/hevc/refs: Check multiplication in alloc_frame()
fftools/ffmpeg_opt: validate stream index in negative map handling
avformat/rtmpproto: prevent integer overflow accumulating FLV buffer size
avformat/rtmpproto: validate compressed SWF header length
avformat/rtsp: Fix out-of-bounds read in SDP parser when control_url is empty
avformat/rtpdec_latm: avoid integer overflow in LATM length parsing
avcodec/h264: recompute per-slice direct mode state for every slice
avcodec/h264_refs: Clear stale pointers from ref_list
avcodec/pdvdec: Check input space before buffer allocation
avformat/concat: guard total_size overflow
avformat/iamf_parse.c: Fix potential integer overflow in opus_decoder_config()
avcodec/wmaenc: Fix missing padding in extradata
avformat: Fix various extradata padding issues
avcodec/tdsc: remove double stride adjustment
avformat/cafdec: fix negative index use in read_seek
avcodec/notchlc: Check 255 loops
avformat/rtpdec_jpeg: check qtable_len
avformat/vividas: use-of-uninitialized-value in keybuffer
avcodec/tdsc: Check jpeg size
avcodec/tdsc: Better input size check
avcodec/tdsc: Check tile_size
avcodec/decode: Better documentation for ff_set_dimensions()
avformat/mov: Limit maximum box size for mov_read_lhvc()
avformat/mov: reject dimg references with zero entries
avformat/mov: check extradata in mov_read_dops()
avformat/mov: Check read size for opus extradata
avformat/rtspdec: reject non-positive ANNOUNCE Content-Length
avformat/wavdec: Fix use-of-uninitialized-value in find_guid()
lavfi: vf_drawtext: check memory allocation
avcodec/svq1dec: Check input space for minimum
avcodec/vp9: Rollback dimensions when format is rejected
avformat/rtpdec_qdm2: Check block_size
avfilter/vf_ssim360: fix integer overflow in tape_length allocation
avcodec/escape130: Initialize old_y_avg
avutil/samplefmt: Dont claim that av_get_sample_fmt_string checks sample_fmt
swscale: fix signed integer overflow in color conversion arithmetic
avformat: check avio_read() return values in dss/dtshd/mlv
avformat/whip: check RTP history packet size before RTX retransmission
avcodec/aac/aacdec_usac: Implement missing bits of otts_bands_phase and residual_bands computation
avcodec/alsdec: preserve full float value in zero-truncated samples
avcodec/alsdec: propagate read_diff_float_data() errors in read_frame_data()
avcodec/alsdec: fix mantissa unpacking in compressed Part A path
avfilter/vf_drawtext: fix newline rendered as .notdef glyph
avcodec/pngdec: fix dead overflow check in decode_text_to_exif()
avcodec/vp9: fix cbs fragment leak on error
libavfilter/vf_v360: fix operator precedence in stereo loop condition
avcodec/alsdec: fix abs(INT_MIN) UB in read_diff_float_data()
avformat/rsd: reject short ADPCM_THP extradata reads
avformat/mov: Handle integer overflow in MOV parser
avcodec/dvdsub_parser: Fix buf_size check
avfilter/af_pan: fix sscanf() return value checks in parse_channel_name
avutil/bswap: fix implicit conversion warning in av_bswap64
avcodec/h2645_sei: don't use provider_code uninitialized
(fforge/pr/22943) avformat/hls_sample_encryption: add missing padding for audio setup buffer
(fforge/pr/22826) lavc/videotoolbox_vp9: fix vpcC flags offset
lavc/videotoolboxenc: return SEI parse errors
vulkan: fix encode feedback query handling
avcodec/cbs_lcevc: fix writing process blocks with size 6
avformat/mov: don't try to create an LCEVC group if there's a single track
(fforge/pr/22563) aarch64: Add Armv9.3-A GCS (Guarded Control Stack) support
aarch64: hevcdsp: Make returns match the call site
(fforge/pr/22545) avcodec/lcevcdec: don't try to derive final dimensions from SAR
avcodec/lcevc_parser: move the resolution type table to a header
avcodec/cbs_lcevc: don't look for process blocks if the unit was not decomposed
version 8.1:
- ffprobe -codec option
+10 -6
View File
@@ -1,4 +1,4 @@
# Installing FFmpeg
## Installing FFmpeg
0. If you like to include source plugins, merge them before configure
for example run tools/merge-all-source-plugins
@@ -14,11 +14,15 @@ path when launching `configure`, e.g. `/ffmpegdir/ffmpeg/configure`.
3. Type `make install` to install all binaries and libraries you built.
## NOTICE
NOTICE
------
- Non system dependencies (e.g. libx264, libvpx) are disabled by default.
- Non system dependencies (e.g. libx264, libvpx) are disabled by default.
## NOTICE for Package Maintainers
NOTICE for Package Maintainers
------------------------------
- It is recommended to build FFmpeg twice, first with minimal external dependencies so that 3rd party packages, which depend on FFmpegs libavutil/libavfilter/libavcodec/libavformat
can then be built. And last build FFmpeg with full dependencies (which may in turn depend on some of these 3rd party packages). This avoids circular dependencies during build.
- It is recommended to build FFmpeg twice, first with minimal external dependencies so
that 3rd party packages, which depend on FFmpegs libavutil/libavfilter/libavcodec/libavformat
can then be built. And last build FFmpeg with full dependencies (which may in turn depend on
some of these 3rd party packages). This avoids circular dependencies during build.
+8 -17
View File
@@ -65,14 +65,14 @@ Communication
=============
website (T: https://git.ffmpeg.org/ffmpeg-web) Deby Barbara Lepage
fate.ffmpeg.org (L: fate-admin@ffmpeg.org) (W: https://fate.ffmpeg.org) (P: https://ffmpeg.org/fate.html) (S: https://git.ffmpeg.org/fateserver) Timo Rothenpieler
Trac bug tracker [X] (W: https://trac.ffmpeg.org) Alexander Strasser, Michael Niedermayer, Carl Eugen Hoyos
Forgejo issue tracker (W: https://code.ffmpeg.org/FFmpeg/FFmpeg/issues)
Trac bug tracker (W: https://trac.ffmpeg.org) Alexander Strasser, Michael Niedermayer, Carl Eugen Hoyos
Patchwork [2] (W: https://patchwork.ffmpeg.org) Andriy Gelman
mailing lists (W: https://ffmpeg.org/contact.html#MailingLists) Baptiste Coudurier
Twitter Reynaldo H. Verdejo Pinochet
Launchpad Timothy Gu
ffmpeg-security [2] (L: ffmpeg-security@ffmpeg.org) (W: https://ffmpeg.org/security.html) Michael Niedermayer, Reimar Doeffinger
libavutil
=========
@@ -93,7 +93,6 @@ Other:
hash Reimar Doeffinger
hwcontext_cuda* Timo Rothenpieler
hwcontext_d3d12va* Wu Jianhua
hwcontext_oh* Zhao Zhili
hwcontext_vulkan* [2] Lynne
intfloat* Michael Niedermayer
integer.c, integer.h Michael Niedermayer
@@ -159,7 +158,7 @@ Codecs:
asv* Michael Niedermayer
atrac3plus* Maxim Poliakovski
audiotoolbox* rcombs
avs2* Huiwen Ren, Zhao Zhili
avs2* Huiwen Ren
bgmc.c, bgmc.h Thilo Borgmann
binkaudio.c Peter Ross
cavs* Stefan Gehrer
@@ -233,7 +232,7 @@ Codecs:
msvideo1.c Mike Melanson
nuv.c Reimar Doeffinger
nvdec*, nvenc* Timo Rothenpieler
oh* Zhao Zhili
omx.c Martin Storsjo, Aman Gupta
opus* Rostislav Pehlivanov
pcx.c Ivo van Poorten
pgssubdec.c Reimar Doeffinger
@@ -244,7 +243,6 @@ Codecs:
qtrle.c Mike Melanson
ra144.c, ra144.h, ra288.c, ra288.h Roberto Togni
resample2.c Michael Niedermayer
rkmppenc* Zhao Zhili
rl2.c Sascha Sommer
rpza.c Roberto Togni
rtjpeg.c, rtjpeg.h Reimar Doeffinger
@@ -252,6 +250,7 @@ Codecs:
sanm.c Manuel Lauss
smc.c Mike Melanson
snow* Michael Niedermayer, Loren Merritt
sonic.c Alex Beregszaszi
speedhq.c Steinar H. Gunderson
srt* Aurelien Jacobs
sunrast.c Ivo van Poorten
@@ -318,10 +317,6 @@ libavfilter
===========
Generic parts:
Framework and orphaned filters Nicolas George
(except hardware acceleration)
graphdump.c Nicolas George
motion_estimation.c Davinder Singh
@@ -353,9 +348,7 @@ Filters:
vf_minterpolate.c Davinder Singh
vf_readvitc.c Tobias Rapp (CC t.rapp at noa-archive dot com)
vf_scale.c [2] Michael Niedermayer
vf_scale_vt.c Zhao Zhili
vf_tonemap_opencl.c Ruiling Song
vf_transpose_vt.c Zhao Zhili
vf_yadif.c [2] Michael Niedermayer
vf_xfade_vulkan.c [2] Marvin Scholz (CC <epirat07@gmail.com>)
@@ -413,9 +406,7 @@ Muxers/Demuxers:
flvenc.c Michael Niedermayer, Steven Liu
gxf.c Reimar Doeffinger
gxfenc.c Baptiste Coudurier
hls.c Kacper Michajłow
hlsenc.c Christian Suloway, Steven Liu
hxvs.c Zhao Zhili
iamf* [2] James Almer
idcin.c Mike Melanson
idroqdec.c Mike Melanson
@@ -451,9 +442,9 @@ Muxers/Demuxers:
nsvdec.c Francois Revol
nut* Michael Niedermayer
nuv.c Reimar Doeffinger
oggdec.c, oggdec.h David Conrad, Romain Beauxis
oggenc.c Baptiste Coudurier, Romain Beauxis
oggparse*.c David Conrad, Romain Beauxis
oggdec.c, oggdec.h David Conrad
oggenc.c Baptiste Coudurier
oggparse*.c David Conrad
oma.c Maxim Poliakovski
pp_bnk.c Zane van Iperen
psxstr.c Mike Melanson
+4 -7
View File
@@ -106,7 +106,7 @@ ffbuild/.config: $(CONFIGURABLE_COMPONENTS)
@-printf '\nWARNING: $(?) newer than config_components.h, rerun configure\n\n'
@-tput sgr0 2>/dev/null
SUBDIR_VARS := CLEANFILES FFLIBS DEVPROGS HOSTPROGS TESTPROGS TOOLS \
SUBDIR_VARS := CLEANFILES FFLIBS HOSTPROGS TESTPROGS TOOLS \
HEADERS ARCH_HEADERS BUILT_HEADERS SKIPHEADERS \
ARMV5TE-OBJS ARMV6-OBJS ARMV8-OBJS VFP-OBJS NEON-OBJS \
ALTIVEC-OBJS VSX-OBJS X86ASM-OBJS \
@@ -143,10 +143,8 @@ ifeq ($(STRIPTYPE),direct)
else
$(RM) $@
$(CP) $< $@
ifneq ($(STRIPTYPE),nostrip)
$(STRIP) $@
endif
endif
%$(PROGSSUF)_g$(EXESUF): $(FF_DEP_LIBS)
$(call LINK,$(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $(OBJS-$*) $(FF_EXTRALIBS))
@@ -189,8 +187,7 @@ clean::
$(RM) -rf coverage.info coverage.info.in lcov
distclean:: clean
$(RM) .version config.asm config.h config_components.* mapfile \
checkasm_config_generated.* checkasm_header_config_generated.h \
$(RM) .version config.asm config.h config_components.* mapfile \
ffbuild/.config ffbuild/config.* libavutil/avconfig.h \
version.h libavutil/ffversion.h libavcodec/codec_names.h \
libavcodec/bsf_list.c libavformat/protocol_list.c \
@@ -205,8 +202,8 @@ endif
config:
$(SRC_PATH)/configure $(value FFMPEG_CONFIGURATION)
build: all alltools devprogs examples testprogs
check: all alltools devprogs examples testprogs fate
build: all alltools examples testprogs
check: all alltools examples testprogs fate
include $(SRC_PATH)/tests/Makefile
+2 -1
View File
@@ -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.
+1 -1
View File
@@ -1 +1 @@
8.0.git
8.1.1
+15
View File
@@ -0,0 +1,15 @@
┌──────────────────────────────────────┐
│ RELEASE NOTES for FFmpeg 8.1 "Hoare" │
└──────────────────────────────────────┘
The FFmpeg Project proudly presents FFmpeg 8.1 "Hoare", about 7
months after the release of FFmpeg 8.0.
A complete Changelog is available at the root of the project, and the
complete Git history on https://git.ffmpeg.org/gitweb/ffmpeg.git
We hope you will like this release as much as we enjoyed working on it, and
as usual, if you have any questions about it, or any FFmpeg related topic,
feel free to join us on the #ffmpeg IRC channel (on irc.libera.chat) or ask
on the mailing-lists.
-1
View File
@@ -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); }
-5
View File
@@ -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
Vendored
+111 -298
View File
File diff suppressed because it is too large Load Diff
+2 -68
View File
@@ -1,77 +1,11 @@
The last version increases of all libraries were on 2026-06-23.
The last version increases of all libraries were on 2025-03-28
API changes, most recent first:
2026-06-23 - 61693f6c35f - lavu 60.34.100 - hwcontext_vulkan.h
Switch AVVkFrame.access to VkAccessFlagBits2.
2026-06-23 - 191be14fb6d - lavc 62.37.100 - packet.h
av_packet_pack_dictionary() now accepts const AVDictionary*.
2026-06-10 - 12dc67b6fe0 - lavu 60.33.100 - frame.h
Add AV_FRAME_DATA_RAW_COLOR_PARAMS.
2026-06-03 - 972c0cf91f4 - lsws 9.8.100 - swscale.h
Add enum SwsBackend and SwsContext.backends
2026-06-02 - 9fe5758da5c - lavu 60.32.100 - hwcontext_vulkan.h
Add AVVulkanDeviceContext.queue_flags.
2026-05-31 - 1e3883df9f0 - lavf 62.19.100 - avformat.h
Add AVStreamGroupLayeredVideo
Add AVStreamGroup.params.layered_video
Add AV_STREAM_GROUP_PARAMS_DOLBY_VISION
Deprecate AVStreamGroupLCEVC
Deprecate AVStreamGroup.params.lcevc
2026-05-30 - 5f6dff5e7db - lavc 62.35.100 - packet.h
Add AV_PKT_DATA_HEVC_CONF side data type.
2026-05-14 - xxxxxxxxxxx - lavf 62.18.100 - avformat.h
Add AV_FDEBUG_ID3V2 debug flag, deprecate FF_FDEBUG_TS in favor of
AV_FDEBUG_TS.
2026-05-17 - a5822fca94f - lavf 62.17.100 - avformat.h
Add AV_STREAM_GROUP_PARAMS_TREF.
Add AVStreamGroupTREF.
2026-05-16 - c0bdc3b62a5 - lavf 62.16.100 - avformat.h
Add AVFMT_FIXED_FRAMESIZE.
2026-05-16 - b1120b1ed80 - lavc 62.33.100 - avcodec.h
Add AV_CODEC_FLAG2_FIXED_FRAME_SIZE.
2026-05-12 - 99908c6e05e - lavu 60.31.100 - frame.h
Add IAMF frame side data types to enum AVFrameSideDataType:
- AV_FRAME_DATA_IAMF_MIX_GAIN_PARAM
- AV_FRAME_DATA_IAMF_DEMIXING_INFO_PARAM
- AV_FRAME_DATA_IAMF_RECON_GAIN_INFO_PARAM
2026-05-05 - 5c557dd5d55 - lavf 62.15.100 - avformat.h
Add av_program_copy().
2026-05-05 - 7623379a770 - lavf 62.14.100 - avformat.h
Add av_program_add_stream_index2().
2026-04-14 - 7faa6ee2aa - lavc 62.30.100 - packet.h
Add AV_PKT_DATA_DYNAMIC_HDR_SMPTE_2094_APP5 side data type.
2026-04-09 - 6ba6db4f19 - lavu 60.30.100 - hdr_dynamic_metadata.h frame.h
Add AVDynamicHDRSmpte2094App5 struct and functions.
Add AV_FRAME_DATA_DYNAMIC_HDR_SMPTE_2094_APP5 side data type.
2026-03-14 - c102e89448a - lavu 60.29.100 - hwcontext_vulkan.h
2026-03-14 - xxxxxxxxxx - lavu 60.26.100 - hwcontext_vulkan.h
Deprecate AVVulkanDeviceContext.lock_queue and
AVVulkanDeviceContext.unlock_queue without replacement.
2026-03-12 - 3503b19711c - lsws 9.7.100 - swscale.h
Add enum SwsScaler, and SwsContext.scaler/scaler_sub.
2026-03-11 - 910000fe59d - lavu 60.28.100 - hwcontext_amf.h
Add av_amf_display_mastering_meta_to_hdrmeta(), av_amf_light_metadata_to_hdrmeta().
Add av_amf_extract_hdr_metadata(), av_amf_attach_hdr_metadata().
Add av_amf_get_color_profile().
2026-03-07 - c23d56b173a - lavc 62.26.100 - codec_desc.h
Add AV_CODEC_PROP_ENHANCEMENT.
-40
View File
@@ -1,40 +0,0 @@
This document is work in progress
*What is CVSS*
The Common Vulnerability Scoring System (CVSS) is an open, industry-standard framework used to measure and communicate the severity of software vulnerabilities, ranging from 0.0 to 10.0.
*Why we need this Document*
It is important that FFmpeg CVEs have consistent and correct CVSS, not only for the obvious reason that one can recognize the severity of an issue at first glance.
But also as these numbers form the basis of rewards paid in bug bounty systems. Inconsistent CVSS could lead to unfair payouts.
*What is this Document*
Prior 2026, FFmpeg had no guideline about CVSS.
This document describes how to select the CVSS for a FFmpeg related CVE. It currently only covers the Base Score.
*What is the CVSS Base Score*
AV Attack Vector (Network, Adjacent, Local, Physical)
AC Attack Complexity (Low, High)
PR Privileges Required (None, Low, High)
UI User Interaction (None, Required)
S Scope (Unchanged, Changed)
C Confidentiality (None, Low, High)
I Integrity (None, Low, High)
A Availability (None, Low, High)
*Things people have set incorrectly*
Below are general guidelines and in specific cases other things may apply.
Attack Vector.
Quote from https://www.first.org/cvss/v3.1/user-guide
"Specifically, analysts should only score for Network or Adjacent when a vulnerability is bound to the network stack.
Vulnerabilities which require user interaction to download or receive malicious content (which could also be delivered locally, e.g., via USB drives) should be scored as Local."
Availability.
FFmpeg Crashes -> AVAILABILITY IMPACT: Low
FFmpeg is frequently used as a short-lived, single-run process instead of a continuously running service that handles ongoing streams of user input. In that usage model, a crash usually causes only limited disruption.
User Interaction
Please consider if an attacker can actually set the parameters required for an attack.
In general arbitrary filter parameters cannot be set by an attacker and require the user/account owner/admin to set them
+1 -1
View File
@@ -38,7 +38,7 @@ PROJECT_NAME = FFmpeg
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER =
PROJECT_NUMBER = 8.1.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
+3 -3
View File
@@ -54,7 +54,7 @@ TEXIDEP = perl $(SRC_PATH)/doc/texidep.pl $(SRC_PATH) $< $@ >$(@:%=%.d)
doc/%.txt: TAG = TXT
doc/%.txt: doc/%.texi
$(Q)$(TEXIDEP)
$(M)$(MAKEINFO) --force --no-headers -o $@ $< 2>/dev/null
$(M)makeinfo --force --no-headers -o $@ $< 2>/dev/null
GENTEXI = format codec
GENTEXI := $(GENTEXI:%=doc/avoptions_%.texi)
@@ -69,11 +69,11 @@ doc/%-all.html: TAG = HTML
ifdef HAVE_MAKEINFO_HTML
doc/%.html: doc/%.texi $(SRC_PATH)/doc/t2h.pm $(GENTEXI)
$(Q)$(TEXIDEP)
$(M)$(MAKEINFO) --html -I doc --no-split -D config-not-all --init-file=$(SRC_PATH)/doc/t2h.pm --output $@ $<
$(M)makeinfo --html -I doc --no-split -D config-not-all --init-file=$(SRC_PATH)/doc/t2h.pm --output $@ $<
doc/%-all.html: doc/%.texi $(SRC_PATH)/doc/t2h.pm $(GENTEXI)
$(Q)$(TEXIDEP)
$(M)$(MAKEINFO) --html -I doc --no-split -D config-all --init-file=$(SRC_PATH)/doc/t2h.pm --output $@ $<
$(M)makeinfo --html -I doc --no-split -D config-all --init-file=$(SRC_PATH)/doc/t2h.pm --output $@ $<
else
doc/%.html: doc/%.texi $(SRC_PATH)/doc/t2h.init $(GENTEXI)
$(Q)$(TEXIDEP)
-27
View File
@@ -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
+5
View File
@@ -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.
-2
View File
@@ -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})
+8
View File
@@ -307,6 +307,14 @@ This decoder generates wave patterns according to predefined sequences. Its
use is purely internal and the format of the data it accepts is not publicly
documented.
@section libcelt
libcelt decoder wrapper.
libcelt allows libavcodec to decode the Xiph CELT ultra-low delay audio codec.
Requires the presence of the libcelt headers and library during configuration.
You need to explicitly configure the build with @code{--enable-libcelt}.
@section libgsm
libgsm decoder wrapper.
-41
View File
@@ -1181,51 +1181,10 @@ RIFF Wave Audio demuxer.
This demuxer accepts the following options:
@table @option
@item ignore_length @var{bool}
Ignore the size of the @code{data} chunk and keep reading until the end of the file if set.
May be useful to read broken or partial files where the header was not properly updated,
but will misinterpret files with non-audio chunks after the @code{data} chunk.
Default is disabled.
@item max_size
Specify the maximum packet size in bytes for the demuxed packets. By default
this is set to 0, which means that a sensible value is chosen based on the
input format.
@end table
@section webp
Animated WebP demuxer.
It accepts the following options:
@table @option
@item -min_delay @var{int}
Set the minimum valid delay between frames in milliseconds.
Range is 0 to 60000. Default value is 10.
@item -max_webp_delay @var{int}
Set the maximum valid delay between frames in milliseconds.
Range is 0 to 16777215. Default value is 16777215 (over four hours),
the maximum value allowed by the specification.
@item -default_delay @var{int}
Set the default delay between frames in milliseconds.
Range is 0 to 60000. Default value is 100.
@item -ignore_loop @var{bool}
WebP files can contain information to loop a certain number of times
(or infinitely). If @option{ignore_loop} is set to true, then the loop
setting from the input will be ignored and looping will not occur.
If set to false, then looping will occur and will cycle the number
of times according to the WebP. Default value is true.
@item usebgcolor @var{bool}
WebP files contain a background color hint in the ANIM chunk, but the
WebP specification says that viewer applications are not required to
use it. If @option{usebgcolor} is set to true, then the background
color hint will be used, otherwise transparent black will be used for
the background. Default value is false.
@end table
@c man end DEMUXERS
+4 -33
View File
@@ -225,25 +225,6 @@ AVStream *stream;
AVStream* stream;
@end example
@item
When sensible, prefer a narrow variable scope, especially in for loops:
@example c, good
// Good
for (unsigned i = 0; i < submix->nb_elements; i++) @{
// Do something...
@}
@end example
@example c, bad
// Bad style
unsigned i;
//...
for (i = 0; i < submix->nb_elements; i++) @{
// Do something...
@}
@end example
@end itemize
If you work on a file that does not follow these guidelines consistently,
@@ -387,7 +368,7 @@ symbols. If in doubt, just avoid names starting with @code{_} altogether.
Casts should be used only when necessary. Unneeded parentheses
should also be avoided if they don't make the code easier to understand.
@item
Where applicable, SI units shall be used. For example timeouts should use seconds as the fundamental unit not microseconds.
Where applicable, SI units shall be used. For example timeouts should use seconds as the fundamental unit not micro seconds.
That means a bare value like @samp{1.0} must mean 1 second, @samp{50m} means 50 milliseconds. For weight, gram shall be used.
@end itemize
@@ -488,25 +469,15 @@ later on.
Also if you have doubts about splitting or not splitting, do not hesitate to
ask/discuss it on the developer mailing list.
@subheading Bug fixes intended for backporting should stay focused.
Keep bug fixes as small as possible while fully fixing the reported issue.
Changes not needed for correctness or robustness should be submitted separately,
especially if they increase complexity or affect backporting.
@subheading Cosmetic changes should be kept in separate patches.
We refuse source indentation and other cosmetic changes if they are mixed
with functional changes, such commits will be rejected and removed. However,
indentation changes that can be ignored by @code{git diff --ignore-all-space}
(e.g. changes in whitespace amount, leading/trailing spaces) may be mixed with
functional changes, since reviewers can use @code{git diff -w} or
@code{git log -p --ignore-all-space} to review only the functional parts of
the change. Forgejo's pull request interface also provides a
``Hide whitespace changes'' option for this purpose. Every
with functional changes, such commits will be rejected and removed. Every
developer has his own indentation style, you should not change it. Of course
if you (re)write something, you can use your own style, even though we would
prefer if the indentation throughout FFmpeg was consistent (Many projects
force a given indentation style - we do not.). If you really need to make
non-whitespace cosmetic changes, separate them strictly from real changes.
indentation changes (try to avoid this), separate them strictly from real
changes.
NOTE: If you had to put if()@{ .. @} over a large (> 5 lines) chunk of code,
then either do NOT change the indentation of the inner part within (do not
-4
View File
@@ -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
+1 -5
View File
@@ -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);
+5 -10
View File
@@ -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);
}
+9 -31
View File
@@ -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);
+1 -6
View File
@@ -132,9 +132,8 @@ static int decode_write(AVCodecContext *avctx, AVPacket *packet)
goto fail;
}
if (fwrite(buffer, 1, size, output_file) != size) {
if ((ret = fwrite(buffer, 1, size, output_file)) < 0) {
fprintf(stderr, "Failed to dump raw data.\n");
ret = -1;
goto fail;
}
@@ -233,10 +232,6 @@ int main(int argc, char *argv[])
/* open the file to dump raw data */
output_file = fopen(argv[3], "w+b");
if (!output_file) {
fprintf(stderr, "Cannot open output file '%s'\n", argv[3]);
return -1;
}
/* actual decoding and dump the raw data */
while (ret >= 0) {
+9 -25
View File
@@ -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;
+3 -11
View File
@@ -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);
+1 -3
View File
@@ -430,9 +430,7 @@ int main(int argc, char **argv)
end:
avformat_close_input(&ifmt_ctx);
if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE))
avio_closep(&ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
avformat_close_input(&ofmt_ctx);
avcodec_free_context(&decoder_ctx);
avcodec_free_context(&encoder_ctx);
av_buffer_unref(&hw_device_ctx);
+1 -1
View File
@@ -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);
+2 -2
View File
@@ -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);
+1 -6
View File
@@ -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. */
+3 -3
View File
@@ -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;
}
+1 -3
View File
@@ -294,9 +294,7 @@ int main(int argc, char **argv)
end:
avformat_close_input(&ifmt_ctx);
if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE))
avio_closep(&ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
avformat_close_input(&ofmt_ctx);
avcodec_free_context(&decoder_ctx);
avcodec_free_context(&encoder_ctx);
av_buffer_unref(&hw_device_ctx);
+13 -28
View File
@@ -1569,27 +1569,6 @@ Set whether on display the image should be vertically flipped.
See the @code{-display_rotation} option for more details.
@item -mastering_display[:@var{stream_specifier}] @var{G(%u,%u)B(%u,%u)R(%u,%u)WP(%u,%u)L(%u,%u)} (@emph{input,per-stream})
Set video mastering display metadata.
@var{G(%u,%u)B(%u,%u)R(%u,%u)WP(%u,%u)L(%u,%u)} is a string specifying
X,Y display primaries for GBR channels and white point (WP) in units of
0.00002, and max-min luminance (L) values in units of 0.0001 candela per
meter square. The values are unsigned integers representing the numerator
of a rational with an implicit denominator of 50000 for GBR and (WP), and
implicit denominator 10000 for (L).
This option overrides the mastering display metadata stored in the file,
if any.
@item -content_light[:@var{stream_specifier}] @var{%u,%u} (@emph{input,per-stream})
Set video content light metadata.
@var{%u,%u} is a string specifying max content light level and maximum picture
average light level.
This option overrides the content light metadata stored in the file, if any.
@item -vn (@emph{input/output})
As an input option, blocks all video streams of a file from being filtered or
being automatically selected or mapped for any output. See @code{-discard}
@@ -2388,19 +2367,25 @@ If either the input or output is blocked leading to actual read speed falling be
specified readrate, then this rate takes effect till the input catches up with the
specified readrate. Must not be lower than the primary readrate.
@item -fps_mode[:@var{stream_specifier}] @var{parameter} (@emph{output,per-stream})
Set video sync method / framerate mode.
@item -vsync @var{parameter} (@emph{global})
@itemx -fps_mode[:@var{stream_specifier}] @var{parameter} (@emph{output,per-stream})
Set video sync method / framerate mode. vsync is applied to all output video streams
but can be overridden for a stream by setting fps_mode. vsync is deprecated and will be
removed in the future.
For compatibility reasons some of the values for vsync can be specified as numbers (shown
in parentheses in the following table).
@table @option
@item passthrough
@item passthrough (0)
Each frame is passed with its timestamp from the demuxer to the muxer.
@item cfr
@item cfr (1)
Frames will be duplicated and dropped to achieve exactly the requested
constant frame rate.
@item vfr
@item vfr (2)
Frames are passed through with their timestamp or dropped so as to
prevent 2 frames from having the same timestamp.
@item auto
@item auto (-1)
Chooses between cfr and vfr depending on muxer capabilities. This is the
default method.
@end table
@@ -2430,7 +2415,7 @@ Do not process input timestamps, but keep their values without trying
to sanitize them. In particular, do not remove the initial start time
offset value.
Note that, depending on the @option{fps_mode} option or on specific muxer
Note that, depending on the @option{vsync} option or on specific muxer
processing (e.g. in case the format option @option{avoid_negative_ts}
is enabled) the output timestamps may mismatch with the input
timestamps even when this option is selected.
-1
View File
@@ -357,7 +357,6 @@
<xsd:complexType name="streamGroupComponentType">
<xsd:sequence>
<xsd:element name="subcomponents" type="ffprobe:streamGroupSubComponentList" minOccurs="0" maxOccurs="1"/>
<xsd:element name="side_data_list" type="ffprobe:packetSideDataListType" minOccurs="0" maxOccurs="1"/>
<xsd:element name="component_entry" type="ffprobe:streamGroupEntryType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
+317 -260
View File
@@ -7743,11 +7743,6 @@ The file path of the downloaded whisper.cpp model (mandatory).
The language to use for transcription ('auto' for auto-detect).
Default value: @code{"auto"}
@item translate
If enabled, translate the transcription from the source language to English. A
multilingual model is required to enable this option.
Default value: @code{"false"}
@item queue
The maximum size that will be queued into the filter before processing the audio
with whisper. Using a small value the audio stream will be processed more often,
@@ -7780,8 +7775,8 @@ Default value: @code{"text"}
@item max_len
Maximum segment length in characters. When set to a value greater than 0,
transcription segments will be split by word to not exceed this length. This is
useful for generating subtitles with shorter lines.
transcription segments will be split to not exceed this length. This is useful
for generating subtitles with shorter lines.
Default value: @code{"0"}
@item vad_model
@@ -8611,24 +8606,21 @@ Same as the @ref{subtitles} filter, except that it doesn't require libavcodec
and libavformat to work. On the other hand, it is limited to ASS (Advanced
Substation Alpha) subtitles files.
This filter accepts @option{filename}/@option{f}, @option{original_size},
@option{fontsdir}, and @option{alpha} from the @ref{subtitles} filter, plus the
following option:
This filter accepts the following option in addition to the common options from
the @ref{subtitles} filter:
@table @option
@item shaping
Set the shaping engine.
Set the shaping engine
Available values are:
@table @samp
@item auto
The default libass shaping engine, which is the best available.
@item simple
Fast, font-agnostic shaper that can do only substitutions.
Fast, font-agnostic shaper that can do only substitutions
@item complex
Slower shaper using OpenType for substitutions and positioning. Required
for correct rendering of complex scripts such as Arabic, Hebrew, Devanagari
and Thai. Requires libass to be built with HarfBuzz.
Slower shaper using OpenType for substitutions and positioning
@end table
The default is @code{auto}.
@@ -12224,42 +12216,18 @@ and configure FFmpeg with @code{--enable-libtorch
--extra-cflags=-I/libtorch_root/libtorch/include/torch/csrc/api/include
--extra-ldflags=-L/libtorch_root/libtorch/lib/}
@item onnx
ONNX Runtime backend. To enable this backend you need to install the
ONNX Runtime library (see @url{https://onnxruntime.ai/}) and configure
FFmpeg with @code{--enable-libonnxruntime}.
The current ONNX Runtime backend expects 4-D input and output tensors
with NCHW layout and 32-bit floating-point element type (ONNX
@code{FLOAT}); models with integer or other element types (e.g.
@code{UINT8}) are not supported and will be rejected at load time.
Models using NHWC layout or other ranks are not yet
supported. Only single-input models are supported; the backend binds
exactly one input tensor when running the model.
The @option{input} and @option{output} options are optional for the
ONNX Runtime backend; when they are omitted the backend resolves the
tensor names from the session.
The ONNX Runtime backend runs inference synchronously using a single
inference request. The shared @option{async} and @option{nireq} options
therefore have no effect for @code{dnn_backend=onnx}; inference always
runs synchronously regardless of their values.
@end table
@item model
Set path to model file specifying network architecture and its parameters.
Note that different backends use different file formats. TensorFlow, OpenVINO,
Libtorch, and ONNX Runtime backends can load files for only their respective formats.
Note that different backends use different file formats. TensorFlow, OpenVINO
and Libtorch backend can load files for only its format.
@item input
Set the input name of the dnn network. Required for the TensorFlow backend;
optional for the ONNX Runtime backend.
Set the input name of the dnn network.
@item output
Set the output name of the dnn network. Required for the TensorFlow backend;
optional for the ONNX Runtime backend.
Set the output name of the dnn network.
@item backend_configs
Set the configs to be passed into backend. To use async execution, set async (default: set).
@@ -12268,20 +12236,6 @@ Roll back to sync execution if the backend does not support async.
For tensorflow backend, you can set its configs with @option{sess_config} options,
please use tools/python/tf_sess_config.py to get the configs of TensorFlow backend for your system.
@item device
Set the device to run the model. For the ONNX Runtime backend this selects the
execution provider: @code{cpu} (default), @code{cuda} (NVIDIA GPU),
@code{dml} (DirectML, Windows only) or @code{vitisai} (AMD Ryzen AI NPU).
@item device_id
Set the device index used by GPU execution providers (e.g. @code{cuda} or
@code{dml}) for the ONNX Runtime backend. Default is 0.
@item threads_per_operation
ONNX Runtime backend only. Set the number of CPU threads used per ONNX
Runtime operator when running with @code{device=cpu}. Default is 0 (let
ONNX Runtime choose automatically). Has no effect for GPU/NPU providers.
@end table
@subsection Examples
@@ -14790,73 +14744,6 @@ This flag is enabled by default.
@end table
@end table
@section frc_amf
Double the frame rate, using Frame Rate Converter (FRC) provided by
AMD Advanced Media Framework library for hardware acceleration.
The filter accepts the following options:
@table @option
@item engine_type
Specify the engine used to run shaders.
@table @samp
@item dx11
DirectX 11.
@item dx12
DirectX 12 (Default value).
@end table
@item enable
Boolean value: enable/disable FRC. Dynamic value, can be altered at a runtime
without re-initializing the filter. (Default value: enabled).
@item fallback_mode
Fallback behavior in case of low interpolation confidence.
@table @samp
@item duplicate
Duplicate frame.
@item blend
Blend two frames together (Default value).
@end table
@item indicator
Boolean value: show FRC indicator square in the top left corner of the video
(Default value: disabled).
@item profile
Level of hierarchical motion search.
@table @samp
@item low
Less levels of hierarchical motion search.
Only recommended for extremely low resolutions.
@item high
Recommended for any resolution up to 1440p. (Default value)
@item super
More levels of hierarchical motion search. Recommended for resolutions 1440p
or higher.
@end table
@item mv_search_mode
Performance mode of the motion search.
@table @samp
@item native
Conduct motion search on the full resolution of source images.
@item performance
Conduct motion search on the down scaled source images.
Recommended for APU or low end GPU for better performance.
@end table
@item use_future_frame
Boolean value: enable dependency on future frame, improves quality for the cost
of latency (Default value: enabled).
@end table
@section framestep
Select one frame every N-th frame.
@@ -23392,23 +23279,6 @@ at least libass release 0.17.0 (or LIBASS_VERSION 0x01600010), @emph{and} libass
have been built with libunibreak.
The option is enabled by default except for native ASS.
@item shaping
Set the shaping engine.
Available values are:
@table @samp
@item auto
The default libass shaping engine, which is the best available.
@item simple
Fast, font-agnostic shaper that can do only substitutions.
@item complex
Slower shaper using OpenType for substitutions and positioning. Required
for correct rendering of complex scripts such as Arabic, Hebrew, Devanagari
and Thai. Requires libass to be built with HarfBuzz.
@end table
The default is @code{auto}.
@end table
If the first key is not specified, it is assumed that the first value
@@ -23777,9 +23647,9 @@ The value must be between @code{0} and @var{nb_frames - 1}. Default is @code{0}.
@item
Produce 8x8 PNG tiles of all keyframes (@option{-skip_frame nokey}) in a movie:
@example
ffmpeg -skip_frame nokey -i file.avi -vf 'scale=128:72,tile=8x8' -an -fps_mode passthrough keyframes%03d.png
ffmpeg -skip_frame nokey -i file.avi -vf 'scale=128:72,tile=8x8' -an -vsync 0 keyframes%03d.png
@end example
The @option{-fps_mode passthrough} is necessary to prevent @command{ffmpeg} from
The @option{-vsync 0} is necessary to prevent @command{ffmpeg} from
duplicating each output frame to accommodate the originally detected frame
rate.
@@ -25778,22 +25648,6 @@ Work the same as the identical @ref{scale} filter options.
@item reset_sar
Works the same as the identical @ref{scale} filter option.
@item in_color_range
Override input color range.
@item out_color_range
Specify output color range.
The accepted values for in_trc and out_trc are:
@table @samp
@item studio
Studio (or restricted, or MPEG) color range.
@item full
Full (or JPEG) color range.
@end table
@anchor{color_profile}
@item color_profile
Specify all color properties at once.
@@ -25811,13 +25665,10 @@ BT.2020
@end table
@item in_trc
Override input transfer characteristics.
@item out_trc
@item trc
Specify output transfer characteristics.
The accepted values for in_trc and out_trc are:
The accepted values are:
@table @samp
@item bt709
BT.709
@@ -25869,13 +25720,10 @@ ARIB_STD_B67
@end table
@item in_primaries
Override input color primaries.
@item out_primaries
@item primaries
Specify output color primaries.
The accepted values for in_primaries and out_primaries are:
The accepted values are:
@table @samp
@item bt709
BT.709
@@ -25927,13 +25775,6 @@ Upscale to 4K and change color profile to bt2020.
@example
vpp_amf=4096:2160:color_profile=bt2020
@end example
@item
Override input primaries and input transfer characteristics, change both to bt709.
@example
vpp_amf=color_profile=bt2020:in_trc=smpte2084:in_primaries=bt2020:out_trc=bt709:out_primaries=bt709
@end example
@end itemize
@anchor{vstack}
@@ -27115,19 +26956,7 @@ value.
@chapter CUDA Video Filters
@c man begin CUDA Video Filters
Below is a description of the currently available Nvidia CUDA video filters.
Prerequisites:
@itemize
@item Install Nvidia CUDA Toolkit
@end itemize
Note: If FFmpeg detects the Nvidia CUDA Toolkit during configuration, it will enable CUDA filters automatically without requiring any additional flags. If you want to explicitly enable them, use the following options:
@itemize
@item Configure FFmpeg with @code{--enable-cuda-nvcc --enable-nonfree}.
@item Configure FFmpeg with @code{--enable-cuda-llvm}. Additional requirement: @code{llvm} lib must be installed.
@end itemize
To enable CUDA and/or NPP filters please refer to configuration guidelines for @ref{CUDA} and for @ref{CUDA NPP} filters.
Running CUDA filters requires you to initialize a hardware device and to pass that device to all filters in any filter graph.
@table @option
@@ -27162,7 +26991,23 @@ Since CUDA filters operate exclusively on GPU memory, frame data must sometimes
@end itemize
Note that @ref{hwupload} uploads data to a surface with the same layout as the software frame, so it may be necessary to add a @ref{format} filter immediately before @ref{hwupload} to ensure the input is in the correct format. Similarly, @ref{hwdownload} may not support all output formats, so an additional @ref{format} filter may need to be inserted immediately after @ref{hwdownload} in the filter graph to ensure compatibility.
@section bilateral_cuda
@anchor{CUDA}
@section CUDA
Below is a description of the currently available Nvidia CUDA video filters.
Prerequisites:
@itemize
@item Install Nvidia CUDA Toolkit
@end itemize
Note: If FFmpeg detects the Nvidia CUDA Toolkit during configuration, it will enable CUDA filters automatically without requiring any additional flags. If you want to explicitly enable them, use the following options:
@itemize
@item Configure FFmpeg with @code{--enable-cuda-nvcc --enable-nonfree}.
@item Configure FFmpeg with @code{--enable-cuda-llvm}. Additional requirement: @code{llvm} lib must be installed.
@end itemize
@subsection bilateral_cuda
CUDA accelerated bilateral filter, an edge preserving filter.
This filter is mathematically accurate thanks to the use of GPU acceleration.
For best output quality, use one to one chroma subsampling, i.e. yuv444p format.
@@ -27182,7 +27027,7 @@ Set window size of the bilateral function to determine the number of neighbours
If the number entered is even, one will be added automatically.
Allowed range is 1 to 255. Default is 1.
@end table
@subsection Examples
@subsubsection Examples
@itemize
@item
@@ -27201,7 +27046,7 @@ Apply the bilateral filter on a video.
@end itemize
@section bwdif_cuda
@subsection bwdif_cuda
Deinterlace the input video using the @ref{bwdif} algorithm, but implemented
in CUDA so that it can work as part of a GPU accelerated pipeline with nvdec
@@ -27253,13 +27098,13 @@ Only deinterlace frames marked as interlaced.
The default value is @code{all}.
@end table
@section chromakey_cuda
@subsection chromakey_cuda
CUDA accelerated YUV colorspace color/chroma keying.
This filter works like normal chromakey filter but operates on CUDA frames.
for more details and parameters see @ref{chromakey}.
@subsection Examples
@subsubsection Examples
@itemize
@item
@@ -27295,7 +27140,7 @@ Process two software sources, explicitly uploading the frames:
@end itemize
@section colorspace_cuda
@subsection colorspace_cuda
CUDA accelerated implementation of the colorspace filter.
@@ -27328,7 +27173,7 @@ JPEG (full) range
@end table
@anchor{overlay_cuda}
@section overlay_cuda
@subsection overlay_cuda
Overlay one video on top of another.
@@ -27407,13 +27252,13 @@ This filter also supports the @ref{framesync} options.
@anchor{pad_cuda}
@section pad_cuda
@subsection pad_cuda
Add paddings to an input video stream using CUDA.
This filter is the CUDA-accelerated version of the @ref{pad} filter. It accepts the same options and expressions and provides the same core functionality.
For a detailed description of available options, please see the documentation for the @ref{pad} filter.
@subsection Examples
@subsubsection Examples
@itemize
@item
@@ -27430,7 +27275,7 @@ ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 -vf "pad_cuda=w=ih
@end itemize
@anchor{scale_cuda}
@section scale_cuda
@subsection scale_cuda
Scale (resize) and convert (pixel format) the input video, using accelerated CUDA kernels.
Setting the output width and height works in the same way as for the @ref{scale} filter.
@@ -27479,12 +27324,6 @@ frame-consumer that exhausts the limited decoder frame pool.
If set to 1, frames are passed through as-is if they match the desired output
parameters. This is the default behaviour.
@item use_filters
If set to 1, filter with a generic weight LUT instead of using fixed-function
shader kernels. May be faster or slower depending on the hardware. A value
of @code{auto} (the default) enables this automatically when required for
correct anti-aliasing when downscaling.
@item param
Algorithm-Specific parameter.
@@ -27499,7 +27338,7 @@ Works the same as the identical @ref{scale} filter option.
@end table
@subsection Examples
@subsubsection Examples
@itemize
@item
@@ -27523,7 +27362,7 @@ scale_cuda=passthrough=0
@end example
@end itemize
@section thumbnail_cuda
@subsection thumbnail_cuda
Select the most representative frame in a given sequence of consecutive frames using CUDA.
@@ -27539,7 +27378,7 @@ the end. Default is @code{100}.
Since the filter keeps track of the whole frames sequence, a bigger @var{n}
value will result in a higher memory usage, so a high value is not recommended.
@subsection Example
@subsubsection Example
@itemize
@@ -27551,57 +27390,7 @@ Thumbnails are extracted from every @var{n}=150-frame batch, selecting one per b
@end itemize
@section transpose_cuda
Transpose rows with columns in the input video and optionally flip it.
For more in depth examples see the @ref{transpose} video filter, which shares mostly the same options.
It accepts the following parameters:
@table @option
@item dir
Specify the transposition direction.
Can assume the following values:
@table @samp
@item cclock_flip
Rotate by 90 degrees counterclockwise and vertically flip. (default)
@item clock
Rotate by 90 degrees clockwise.
@item cclock
Rotate by 90 degrees counterclockwise.
@item clock_flip
Rotate by 90 degrees clockwise and vertically flip.
@item reversal
Rotate by 180 degrees.
@item hflip
Flip horizontally.
@item vflip
Flip vertically.
@end table
@item passthrough
Do not apply the transposition if the input geometry matches the one
specified by the specified value. It accepts the following values:
@table @samp
@item none
Always apply transposition. (default)
@item portrait
Preserve portrait geometry (when @var{height} >= @var{width}).
@item landscape
Preserve landscape geometry (when @var{width} >= @var{height}).
@end table
@end table
@section yadif_cuda
@subsection yadif_cuda
Deinterlace the input video using the @ref{yadif} algorithm, but implemented
in CUDA so that it can work as part of a GPU accelerated pipeline with nvdec
@@ -27659,6 +27448,274 @@ Only deinterlace frames marked as interlaced.
The default value is @code{all}.
@end table
@anchor{CUDA NPP}
@section CUDA NPP
Below is a description of the currently available NVIDIA Performance Primitives (libnpp) video filters.
Prerequisites:
@itemize
@item Install Nvidia CUDA Toolkit
@item Install libnpp
@end itemize
To enable CUDA NPP filters:
@itemize
@item Configure FFmpeg with @code{--enable-nonfree --enable-libnpp}.
@end itemize
@anchor{scale_npp}
@subsection scale_npp
Use the NVIDIA Performance Primitives (libnpp) to perform scaling and/or pixel
format conversion on CUDA video frames. Setting the output width and height
works in the same way as for the @var{scale} filter.
The following additional options are accepted:
@table @option
@item format
The pixel format of the output CUDA frames. If set to the string "same" (the
default), the input format will be kept. Note that automatic format negotiation
and conversion is not yet supported for hardware frames
@item interp_algo
The interpolation algorithm used for resizing. One of the following:
@table @option
@item nn
Nearest neighbour.
@item linear
@item cubic
@item cubic2p_bspline
2-parameter cubic (B=1, C=0)
@item cubic2p_catmullrom
2-parameter cubic (B=0, C=1/2)
@item cubic2p_b05c03
2-parameter cubic (B=1/2, C=3/10)
@item super
Supersampling
@item lanczos
@end table
@item force_original_aspect_ratio
Enable decreasing or increasing output video width or height if necessary to
keep the original aspect ratio. Possible values:
@table @samp
@item disable
Scale the video as specified and disable this feature.
@item decrease
The output video dimensions will automatically be decreased if needed.
@item increase
The output video dimensions will automatically be increased if needed.
@end table
One useful instance of this option is that when you know a specific device's
maximum allowed resolution, you can use this to limit the output video to
that, while retaining the aspect ratio. For example, device A allows
1280x720 playback, and your video is 1920x800. Using this option (set it to
decrease) and specifying 1280x720 to the command line makes the output
1280x533.
Please note that this is a different thing than specifying -1 for @option{w}
or @option{h}, you still need to specify the output resolution for this option
to work.
@item force_divisible_by
Ensures that both the output dimensions, width and height, are divisible by the
given integer when used together with @option{force_original_aspect_ratio}. This
works similar to using @code{-n} in the @option{w} and @option{h} options.
This option respects the value set for @option{force_original_aspect_ratio},
increasing or decreasing the resolution accordingly. The video's aspect ratio
may be slightly modified.
This option can be handy if you need to have a video fit within or exceed
a defined resolution using @option{force_original_aspect_ratio} but also have
encoder restrictions on width or height divisibility.
@item reset_sar
Works the same as the identical @ref{scale} filter option.
@item eval
Specify when to evaluate @var{width} and @var{height} expression. It accepts the following values:
@table @samp
@item init
Only evaluate expressions once during the filter initialization or when a command is processed.
@item frame
Evaluate expressions for each incoming frame.
@end table
@end table
The values of the @option{w} and @option{h} options are expressions
containing the following constants:
@table @var
@item in_w
@item in_h
The input width and height
@item iw
@item ih
These are the same as @var{in_w} and @var{in_h}.
@item out_w
@item out_h
The output (scaled) width and height
@item ow
@item oh
These are the same as @var{out_w} and @var{out_h}
@item a
The same as @var{iw} / @var{ih}
@item sar
input sample aspect ratio
@item dar
The input display aspect ratio. Calculated from @code{(iw / ih) * sar}.
@item n
The (sequential) number of the input frame, starting from 0.
Only available with @code{eval=frame}.
@item t
The presentation timestamp of the input frame, expressed as a number of
seconds. Only available with @code{eval=frame}.
@item pos
The position (byte offset) of the frame in the input stream, or NaN if
this information is unavailable and/or meaningless (for example in case of synthetic video).
Only available with @code{eval=frame}.
Deprecated, do not use.
@end table
@subsection scale2ref_npp
Use the NVIDIA Performance Primitives (libnpp) to scale (resize) the input
video, based on a reference video.
See the @ref{scale_npp} filter for available options, scale2ref_npp supports the same
but uses the reference video instead of the main input as basis. scale2ref_npp
also supports the following additional constants for the @option{w} and
@option{h} options:
@table @var
@item main_w
@item main_h
The main input video's width and height
@item main_a
The same as @var{main_w} / @var{main_h}
@item main_sar
The main input video's sample aspect ratio
@item main_dar, mdar
The main input video's display aspect ratio. Calculated from
@code{(main_w / main_h) * main_sar}.
@item main_n
The (sequential) number of the main input frame, starting from 0.
Only available with @code{eval=frame}.
@item main_t
The presentation timestamp of the main input frame, expressed as a number of
seconds. Only available with @code{eval=frame}.
@item main_pos
The position (byte offset) of the frame in the main input stream, or NaN if
this information is unavailable and/or meaningless (for example in case of synthetic video).
Only available with @code{eval=frame}.
@end table
@subsubsection Examples
@itemize
@item
Scale a subtitle stream (b) to match the main video (a) in size before overlaying
@example
'scale2ref_npp[b][a];[a][b]overlay_cuda'
@end example
@item
Scale a logo to 1/10th the height of a video, while preserving its display aspect ratio.
@example
[logo-in][video-in]scale2ref_npp=w=oh*mdar:h=ih/10[logo-out][video-out]
@end example
@end itemize
@subsection sharpen_npp
Use the NVIDIA Performance Primitives (libnpp) to perform image sharpening with
border control.
The following additional options are accepted:
@table @option
@item border_type
Type of sampling to be used ad frame borders. One of the following:
@table @option
@item replicate
Replicate pixel values.
@end table
@end table
@subsection transpose_npp
Transpose rows with columns in the input video and optionally flip it.
For more in depth examples see the @ref{transpose} video filter, which shares mostly the same options.
It accepts the following parameters:
@table @option
@item dir
Specify the transposition direction.
Can assume the following values:
@table @samp
@item cclock_flip
Rotate by 90 degrees counterclockwise and vertically flip. (default)
@item clock
Rotate by 90 degrees clockwise.
@item cclock
Rotate by 90 degrees counterclockwise.
@item clock_flip
Rotate by 90 degrees clockwise and vertically flip.
@end table
@item passthrough
Do not apply the transposition if the input geometry matches the one
specified by the specified value. It accepts the following values:
@table @samp
@item none
Always apply transposition. (default)
@item portrait
Preserve portrait geometry (when @var{height} >= @var{width}).
@item landscape
Preserve landscape geometry (when @var{width} >= @var{height}).
@end table
@end table
@c man end CUDA Video Filters
@chapter OpenCL Video Filters
@@ -32276,7 +32333,7 @@ select=n=2:e='mod(n, 2)+1' [odd][even]; [odd] pad=h=2*ih [tmp]; [tmp][even] over
Select useful frames from an ffconcat file which is using inpoints and
outpoints but where the source files are not intra frame only.
@example
ffmpeg -copyts -segment_time_metadata 1 -i input.ffconcat -fps_mode passthrough -vf select=concatdec_select -af aselect=concatdec_select output.avi
ffmpeg -copyts -vsync 0 -segment_time_metadata 1 -i input.ffconcat -vf select=concatdec_select -af aselect=concatdec_select output.avi
@end example
@end itemize
-3
View File
@@ -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})
+2 -33
View File
@@ -205,39 +205,6 @@ FFmpeg can make use of this library, originating in Modplug-XMMS, to read from M
See @url{https://github.com/Konstanty/libmodplug}. Pass @code{--enable-libmodplug} to configure to
enable it.
@section ONNX Runtime
FFmpeg can make use of the ONNX Runtime library as a backend for DNN based filters.
Go to @url{https://onnxruntime.ai/} and follow the instructions for installing
the library. Pre-built packages are available for various platforms.
Configure FFmpeg with ONNX Runtime support:
@example
./configure \
--enable-libonnxruntime \
--extra-cflags="-I/path/to/onnxruntime/include" \
--extra-ldflags="-L/path/to/onnxruntime/lib"
@end example
On ELF-based systems (Linux, BSD) you may also want to embed the
library search path so that the installed @file{ffmpeg} binary finds the
shared library at run time without setting @env{LD_LIBRARY_PATH}:
@example
./configure \
--enable-libonnxruntime \
--extra-cflags="-I/path/to/onnxruntime/include" \
--extra-ldflags="-L/path/to/onnxruntime/lib -Wl,-rpath,/path/to/onnxruntime/lib"
@end example
The @code{-Wl,-rpath} flag is ELF-specific and should be omitted on
other platforms (Windows, macOS).
For MinGW GCC builds, add the @code{-D_stdcall=__stdcall} flag for compatibility
with ONNX Runtime headers.
@section OpenCORE, VisualOn, and Fraunhofer libraries
Spun off Google Android sources, OpenCore, VisualOn and Fraunhofer
@@ -1328,6 +1295,8 @@ following image formats are supported:
@item Bink Audio @tab @tab X
@tab Used in Bink and Smacker files in many games.
@item Bonk audio @tab @tab X
@item CELT @tab @tab E
@tab decoding supported through external library libcelt
@item codec2 @tab E @tab E
@tab en/decoding supported through external library libcodec2
@item CRI HCA @tab @tab X
+1 -2
View File
@@ -52,8 +52,7 @@ Web, mail, and public facing git, also website git
fftrac VM:
----------
trac.ffmpeg.org Legacy issue tracking
code.ffmpeg.org Primary issue tracking
trac.ffmpeg.org Issue tracking
gpg encrypted backups of the trac repositories are created once a day
and can be downloaded by any of the admins.
+1 -4
View File
@@ -21,10 +21,7 @@ a mail for every change to every issue.
The subscription URL for the ffmpeg-trac list is:
https://lists.ffmpeg.org/mailman/listinfo/ffmpeg-trac
The primary issue tracker is:
https://code.ffmpeg.org/FFmpeg/FFmpeg/issues
Legacy issues may still exist on:
The URL of the webinterface of the tracker is:
https://trac.ffmpeg.org
Type:
+4 -195
View File
@@ -1330,21 +1330,11 @@ element. Imply that the @option{single_file} option is set to
@var{true}. In the template, @code{$ext$} is replaced with the file
name extension specific for the segment format.
@item availability_start_time_ms @var{milliseconds}
Set the MPD @code{availabilityStartTime} attribute as Unix epoch time in
milliseconds. If set to @code{0}, the wall clock is used when the first
packet is written. This is useful for live outputs that need a stable
availability start time across restarts.
@item streaming @var{bool}
Enable or disable chunk streaming mode of output. In chunk streaming
mode, each frame will be a @code{moof} fragment which forms a
chunk. This is disabled by default.
@item suggested_presentation_delay @var{duration}
Set the MPD @code{suggestedPresentationDelay} attribute. If set to
@code{0}, the last segment duration is used.
@item target_latency @var{target_latency}
Set an intended target latency in seconds for serving (fractional
value can be set). Applicable only when the @option{streaming} and
@@ -1769,7 +1759,7 @@ See also the @ref{framehash} and @ref{md5} muxers.
Animated GIF muxer.
Note that the GIF format has a very large time base: the delay between two frames can
therefore not be smaller than one centisecond.
therefore not be smaller than one centi second.
@subsection Options
@table @option
@@ -2654,12 +2644,6 @@ writing is completed. Default is disabled.
@item protocol_opts @var{options_list}
Set protocol options as a :-separated list of key=value parameters. Values
containing the @code{:} special character must be escaped.
@item update_filemtime @var{bool}
If set to 1, set each output file's modification time to the
@code{creation_time} metadata value plus the frame's PTS offset.
If @code{creation_time} is missing or unparsable, a warning is
logged and the option is ignored. Default value is 0.
@end table
@subsection Examples
@@ -2668,7 +2652,7 @@ logged and the option is ignored. Default value is 0.
Use @command{ffmpeg} for creating a sequence of files @file{img-001.jpeg},
@file{img-002.jpeg}, ..., taking one image every second from the input video:
@example
ffmpeg -i in.avi -fps_mode cfr -r 1 -f image2 'img-%03d.jpeg'
ffmpeg -i in.avi -vsync cfr -r 1 -f image2 'img-%03d.jpeg'
@end example
Note that with @command{ffmpeg}, if the format is not specified with the
@@ -2676,7 +2660,7 @@ Note that with @command{ffmpeg}, if the format is not specified with the
format, the image2 muxer is automatically selected, so the previous
command can be written as:
@example
ffmpeg -i in.avi -fps_mode cfr -r 1 'img-%03d.jpeg'
ffmpeg -i in.avi -vsync cfr -r 1 'img-%03d.jpeg'
@end example
Note also that the pattern must not necessarily contain "%d" or
@@ -2728,58 +2712,6 @@ computer-generated compositions.
This muxer accepts a single audio stream containing PCM data.
@section iterm2
iTerm2 inline image protocol muxer.
This muxer writes video frames as OSC 1337 inline images for display in
terminals that support the iTerm2 image protocol. Use @option{-re} to limit
the output rate to the source framerate; without it, frames are emitted as
fast as they are encoded, which is usually not desired for live display.
Frames are sent with the multipart form of the protocol, which splits each
image across several short control sequences. This avoids the per-sequence
size limit that otherwise discards large frames, and requires iTerm2 3.5 or
newer.
The output is a self-contained byte stream and can be redirected to a file.
Replaying the file with @command{cat} displays the images in the terminal.
@subsection Options
@table @option
@item display_width @var{size}
Set the displayed image width. @var{size} can be @samp{auto}, @var{N} terminal
cells, @var{N}px pixels, or @var{N}% of the terminal width. When unset, the
terminal derives the width from the image.
@item display_height @var{size}
Set the displayed image height. @var{size} uses the same syntax as
@option{display_width}. When unset, the terminal derives the height from the
image.
@item keep_aspect @var{bool}
Preserve the input aspect ratio when scaling. Default is enabled.
@item tmux @var{bool}
Wrap image data in tmux DCS passthrough. This requires a tmux version whose
passthrough sequence size limit is large enough for image data, with
passthrough enabled via @command{tmux set -g allow-passthrough on}. Default is
disabled.
@end table
@subsection Examples
Display a video in an iTerm2 terminal:
@example
ffmpeg -re -i input.mp4 -f iterm2 -
@end example
Scale the displayed image to 40 terminal cells tall. Inside tmux, enable
passthrough first with @command{tmux set -g allow-passthrough on}, then add
@option{tmux}:
@example
ffmpeg -re -i input.mp4 -f iterm2 -display_height 40 -tmux 1 -
@end example
@section ivf
On2 IVF muxer.
@@ -2819,14 +2751,6 @@ song lyrics with an audio file, such as MP3, Vorbis, or MIDI.
This muxer accepts a single @samp{subrip} or @samp{text} subtitles stream.
@subsection Options
@table @option
@item precision @var{number}
Set the number of decimal digits used for the fractional (sub-second)
part of the timestamps. Range is @code{1} to @code{6}. Default is
@code{2}, i.e. centiseconds.
@end table
@subsection Metadata
The following metadata tags are converted to the format corresponding
metadata:
@@ -3145,7 +3069,7 @@ Default is @code{0x0001}.
Set the @samp{original_network_id}. This is unique identifier of a
network in DVB. Its main use is in the unique identification of a service
through the path @samp{Original_Network_ID, Transport_Stream_ID}. Default
is @code{0xff01}.
is @code{0x0001}.
@item mpegts_service_id @var{integer}
Set the @samp{service_id}, also known as program in DVB. Default is
@@ -3172,8 +3096,6 @@ MPEG2 Digital HDTV service.
Advanced Codec Digital SDTV service.
@item advanced_codec_digital_hdtv
Advanced Codec Digital HDTV service.
@item hevc_digital_hdtv
HEVC Digital Television service.
@end table
@item mpegts_pmt_start_pid @var{integer}
@@ -3350,19 +3272,6 @@ ogg files can be safely chained.
@end table
@section pdv
Playdate Video muxer.
This muxer writes the Playdate video container used by Panic's Playdate SDK.
It requires a seekable output and a single PDV video stream.
@table @option
@item max_frames @var{frames}
Reserve space for at most @var{frames} video frames in the file header. This
option is mandatory.
@end table
@anchor{rcwtenc}
@section rcwt
@@ -3608,13 +3517,6 @@ Wrap around segment index once it reaches @var{limit}.
@item segment_start_number @var{number}
Set the sequence number of the first segment. Defaults to @code{0}.
@item segment_wrap_number @var{number}
Set the number of times the segment index is assumed to have already wrapped
when generating the indexes reported in the segment list. Together with
@option{segment_wrap} and @option{segment_start_number} it offsets the reported
index, which is computed as @code{segment_start_number + segment_wrap *
segment_wrap_number}. Defaults to @code{0}.
@item strftime @var{1|0}
Use the @code{strftime} function to define the name of the new
segments to write. If this is selected, the output segment name must
@@ -3641,25 +3543,6 @@ argument must be a time duration specification, and defaults to 0.
If enabled, write an empty segment if there are no packets during the period a
segment would usually span. Otherwise, the segment will be filled with the next
packet written. Defaults to @code{0}.
@item write_header_trailer @var{bool}
Write a header to the first segment and a trailer to the last one, instead of
writing a header and a trailer to every individual segment. Disabling it
(@code{false}) also forces @option{individual_header_trailer} to @code{false},
so that no segment is given a header or trailer. Default value is @code{true}.
@item individual_header_trailer @var{bool}
If enabled, write a complete header and trailer to every segment, making each
segment an independently usable file. If disabled (@code{false}), only the first
segment is given a header and only the last one a trailer. It is forced to
@code{false} when @option{write_header_trailer} is @code{false} or when
@option{segment_header_filename} is set. Default value is @code{true}.
@item segment_header_filename @var{name}
Write the stream header to a separate file named @var{name} instead of storing
it in the segments. Setting it forces @option{write_header_trailer} to
@code{true} and @option{individual_header_trailer} to @code{false}, so the
header is written only once, to @var{name}. Unset by default.
@end table
Make sure to require a closed GOP when encoding and to set the GOP
@@ -3925,76 +3808,6 @@ ffmpeg -i ... -map 0 -flags +global_header -c:v libx264 -c:a aac
@end example
@end itemize
@section wav
RIFF Wave Audio muxer.
@subsection Options
@table @option
@item rf64 @var{mode}
Choose whether to use the RF64 file format instead of RIFF.
RF64 allows files larger than 4 gigabytes, but RF64 support is not as
universal as RIFF.
The following modes are recognized:
@table @samp
@item auto
Start writing a standard RIFF file to retain compatibility with non-RF64-aware
software, but switch to RF64 if the output file grows larger than 4 gigabytes.
Reserves a small amount of extra space in the header using a @code{JUNK} chunk,
which should be ignored by all compliant RIFF readers, but some extremely
simplistic WAV readers may be confused by this.
@item always
Always use the RF64 format regardless of file size. The output file will only
be readable by RF64-compatible software and is no longer a standard RIFF WAVE
file.
@item never
Always use plain RIFF, never RF64. This mode is the most compatible with legacy
software, but if the output file grows beyond 4 gigabytes, the 32-bit size field
in the @code{data} chunk will no longer be able to correctly represent the size,
and most audio software will not be able to read some or all of the data.
(The @ref{wav} demuxer's @code{ignore_length} option can be used to recover such
a file.)
This is the default mode.
@end table
@item write_bext @var{bool}
Add a Broadcast Wave Format @code{BEXT} chunk containing extended audio
metadata if enabled. Defaults to false.
@item write_peak @var{mode}
Add a Peak Envelope chunk (EBU Tech 3285 Supplement 3) if enabled.
Defaults to off.
@table @samp
@item off
Do not add the Peak Envelope chunk.
@item on
Add the Peak Envelope chunk, calculating the peak values based on the
@code{peak_block_size}, @code{peak_format}, and @code{peak_ppv} options.
@item only
Like @code{on}, but skip writing the actual audio data (no @code{data}
chunk will be written to the file; only the Peak Envelope and other metadata
chunks will be written.)
@end table
@item peak_block_size @var{int}
Number of audio samples used to generate each peak frame, up to 65536.
Default is 256.
@item peak_format @var{format}
The format of the peak envelope data (1: uint8, 2: uint16). Default is 2 (uint16).
@item peak_ppv @var{int}
Number of peak points per peak value (1 or 2). Default is 2.
@end table
@section webm_chunk
WebM Live Chunk Muxer.
@@ -4138,10 +3951,6 @@ This muxer supports the following options:
Set the timeout in milliseconds for ICE and DTLS handshake.
Default value is 5000.
@item timeout @var{integer}
Set timeout in seconds for socket I/O operations. Applicable only for HTTP output.
Default value is -1.
@item pkt_size @var{integer}
Set the maximum size, in bytes, of RTP packets that send out.
Default value is 1200.
+6 -1
View File
@@ -20,7 +20,7 @@ architecture-specific versions. It is recommended to look at older
revisions of the interesting files (web frontends for the various FFmpeg
branches are listed at http://ffmpeg.org/download.html).
Alternatively, look into the other architecture-specific versions in
the x86/, ppc/, aarch64/ subdirectories. Even if you don't exactly
the x86/, ppc/, alpha/ subdirectories. Even if you don't exactly
comprehend the instructions, it could help understanding the functions
and how they can be optimized.
@@ -191,6 +191,11 @@ __asm__() block.
Use external asm (nasm) or inline asm (__asm__()), do not use intrinsics.
The latter requires a good optimizing compiler which gcc is not.
When debugging a x86 external asm compilation issue, if lost in the macro
expansions, add DBG=1 to your make command-line: the input file will be
preprocessed, stripped of the debug/empty lines, then compiled, showing the
actual lines causing issues.
Inline asm vs. external asm
---------------------------
Both inline asm (__asm__("..") in a .c file, handled by a compiler such as gcc)
+8 -76
View File
@@ -169,7 +169,6 @@ Read angle 2 of playlist 4 from BluRay mounted to /mnt/bluray, start from chapte
-playlist 4 -angle 2 -chapter 2 bluray:/mnt/bluray
@end example
@anchor{cache}
@section cache
Caching wrapper for input stream.
@@ -344,8 +343,7 @@ time, which is valuable for files on slow medium.
If set to 1, the protocol will retry reading at the end of the file, allowing
reading files that still are being written. In order for this to terminate,
you either need to use the rw_timeout option, or use the interrupt callback
(for API users). Setting this option also ignores the file size reported by
the file system.
(for API users).
@item seekable
Controls if seekability is advertised on the file. 0 means non-seekable, -1
@@ -453,16 +451,15 @@ string describing the libavformat build. ("Lavf/<version>")
Set the Referer header. Include 'Referer: URL' header in HTTP request.
@item multiple_requests
Force persistent connections if set to 1, or disable if 0. Default is -1,
which means auto (implies keep-alive when using -request_size or
-initial_request_size).
Use persistent connections if set to 1, default is 0.
@item request_size
Limit the size of requests made. This is useful for some pathological servers
that throttle unbounded range requests, as well as when expecting to seek
frequently. Disabled (set to 0) by default.
Note that if enabling this option, it's strongly recommended to also set
Note that if enabling this option, it's strongly recommended to also enable
the @option{multiple_requests} option, as well as setting
@option{short_seek_size} to the same value or higher. Doing so allows FFmpeg
to reuse a single HTTP connection wherever possible.
@@ -1572,67 +1569,6 @@ If set to any value, listen for an incoming connection. Outgoing connection is d
Set the maximum number of streams. By default no limit is set.
@end table
@section shared
Thread-safe, persistent, cross-process cache wrapper for input streams. Caches
the input stream to a file in the specified directory. This is similar to
@ref{cache}, but with a persistent cache on disk that may be shared between
multiple processes or demuxers, even concurrently.
The filename of the cache is obtained by hashing the input URL, so there is
some risk of collision if the same URL is used for different content (e.g.
as a result of extra POST data being used to select the stream ID). To avoid
this, make sure to only use this protocol for URLs that uniquely identify
the content; otherwise you may get a garbled mix of sources.
The accepted options are:
@table @option
@item cache_dir
Path to the directory where cache files are stored. This option is required.
@item block_shift
Shift factor (log2) of the block size used for internal reads/writes. Defaults
to 15, i.e. 32KB blocks. If this does not match the value that was specified
when an existing cache file was created, the previously specified value will
be used instead.
@item read_only
If true, use the shared cache for reads but don't write any new blocks to it.
Default is false. Note that even with this option enabled, the cache file will
be initialized if it does not already exist.
@item cache_verify
If true, verify any data read from the cache against the underlying input
stream, and report any mismatches. Note that this will make the cache layer
effectively useless. This is purely a debug option.
@item cache_timeout
If set to a nonzero value, specifies the maximum time (in microseconds) to wait
for data to become available, if another process is currently trying to fetch
and cache the same block at the same time. If this timeout elapses, it's
assumed that the other process may have gotten stuck or died in the meantime.
If set to zero, no waiting is done and all processes will immediately race
to try and fetch the same missing blocks themselves. Defaults to 10000 (10 ms).
@item retry_errors
If true (the default), transient read errors from the underlying input stream
are ignored and retried again. If false, any blocks that previously failed
being read from will be treated as permanently inaccessible.
@item retry_corrupt
If true (the default), blocks whose contents fail the CRC integrity check are
re-fetched from the underlying input stream, overwriting the corrupt cached
data. If false, cache corruption is treated as a fatal read error.
@end table
URL Syntax is
@example
shared:@var{URL}
@end example
@section srt
Haivision Secure Reliable Transport Protocol via libsrt.
@@ -1921,10 +1857,6 @@ When true, use Timestamp-based Packet Delivery mode. The default behavior
depends on the transmission type: enabled in live mode, disabled in file
mode.
@item ipv6only=@var{1|0}
Accept IPv4 or not while using the IPv6 wildcard address. This should be set
when listening on a IPv6 wildcard address.
@end table
For more information see: @url{https://github.com/Haivision/srt}.
@@ -2091,8 +2023,8 @@ database, but it does not validate that the certificate actually
matches the host name we are trying to connect to. (With other backends,
the host name is validated as well.)
This is enabled by default. Verifying the peer requires a CA database,
which in some cases has to be provided by the caller.
This is disabled by default since it requires a CA database to be
provided by the caller in many cases.
@item cert_file, cert=@var{filename}
A file containing a certificate to use in the handshake with the peer.
@@ -2163,8 +2095,8 @@ peer certificate is signed by one of the root certificates in the CA
database, but it does not validate that the certificate actually
matches the host name we are trying to connect to.
This is enabled by default. Verifying the peer requires a CA database,
which in some cases has to be provided by the caller.
This is disabled by default since it requires a CA database to be
provided by the caller in many cases.
@item cert_file, cert=@var{filename}
A file containing a certificate to use in the handshake with the peer.
+13 -94
View File
@@ -11,88 +11,48 @@ For programmatic use, they can be set explicitly in the
@table @option
@anchor{scaler}
@item scaler, scaler_sub
Choose the scaling algorithm to use. Default value is @samp{auto} for both.
It accepts the following values:
@table @samp
@item auto
Aumotic choice. For @samp{scaler_sub}, this means the same algorithm as
@samp{scaler}. For @samp{scaler}, this defaults to the scaler flag selected
by @samp{sws_flags}.
@item bilinear
Bilinear filter. (AKA triangle filter)
@item bicubic
2-tap cubic BC-spline (AKA Mitchell-Netravali spline). The B and C parameters
can be configured by setting @code{param0} and @code{param1}, defaulting to
0.0 and 0.6 respectively.
@item point, neighbor
Point sampling (AKA nearest neighbor).
@item area
Area averaging. Equivalent to @samp{bilinear} for upscaling.
@item gaussian
2-tap Gaussian filter approximation. The sharpness parameter can be configured
by setting @code{param0}, defaulting to 3.0.
@item sinc
Unwindowed sinc filter.
@item lanczos
Lanczos resampling (sinc windowed sinc). The number of filter taps can
be configured by setting @code{param0}, defaulting to 3.
@item spline
Unwindowed natural bicubic spline.
@end table
@anchor{sws_flags}
@item sws_flags
Set the scaler flags. This is also used to set the scaling
algorithm, though this usage is deprecated in favor of setting @samp{scaler}.
Only a single algorithm may be selected. Default value is @samp{bicubic}.
algorithm. Only a single algorithm should be selected. Default
value is @samp{bicubic}.
It accepts the following values:
@table @samp
@item fast_bilinear
Select fast bilinear scaling algorithm. (Deprecated)
Select fast bilinear scaling algorithm.
@item bilinear
Select bilinear scaling algorithm. (Deprecated)
Select bilinear scaling algorithm.
@item bicubic
Select bicubic scaling algorithm. (Deprecated)
Select bicubic scaling algorithm.
@item experimental
Select experimental scaling algorithm. (Deprecated)
Select experimental scaling algorithm.
@item neighbor
Select nearest neighbor rescaling algorithm. (Deprecated)
Select nearest neighbor rescaling algorithm.
@item area
Select averaging area rescaling algorithm. (Deprecated)
Select averaging area rescaling algorithm.
@item bicublin
Select bicubic scaling algorithm for the luma component, bilinear for
chroma components. (Deprecated)
chroma components.
@item gauss
Select Gaussian rescaling algorithm. (Deprecated)
Select Gaussian rescaling algorithm.
@item sinc
Select sinc rescaling algorithm. (Deprecated)
Select sinc rescaling algorithm.
@item lanczos
Select Lanczos rescaling algorithm. The default width (alpha) is 3 and can be
changed by setting @code{param0}. (Deprecated)
changed by setting @code{param0}.
@item spline
Select natural bicubic spline rescaling algorithm. (Deprecated)
Select natural bicubic spline rescaling algorithm.
@item print_info
Enable printing/debug logging.
@@ -191,47 +151,6 @@ No blending
@end table
@item sws_backends
Set the allowed swscale backends. This is a flags option, so multiple backends
may be combined.
@table @samp
@item auto
Automatic selection. Equal to either @samp{stable} or @samp{all} depending on
whether or not the @samp{unstable} flag is set. This is the default value.
@item stable
All stable backends.
@item unstable
All unstable backends.
@item all
All available backends.
@item legacy
Legacy swscale code.
@item c
Template-based reference code.
@item memcpy
Fast path using libc @code{memcpy}.
@item x86
x86 SIMD kernels.
@item aarch64
AArch64 NEON kernels.
@item spirv
Vulkan SPIR-V backend.
@item glsl
Vulkan GLSL backend.
@end table
@end table
@c man end SCALER OPTIONS
+2 -3
View File
@@ -13,9 +13,8 @@ threaded error diffusion pass following a multi-threaded scaling pass.
SwsGraph is internally recreated whenever the image format, dimensions or
settings change in any way. sws_scale_frame() is itself just a light-weight
wrapper that runs ff_sws_graph_reinit() initially and on format changes,
splits interlaced images into separate fields, and calls ff_sws_graph_run()
on each.
wrapper that runs ff_sws_graph_create() whenever the format changes, splits
interlaced images into separate fields, and calls ff_sws_graph_run() on each.
From the point of view of SwsGraph itself, all inputs are progressive.
+73 -53
View File
@@ -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
View File
@@ -1,17 +1,14 @@
# Transforms
The basis transforms used for FFT and various other derived functions are based on the following unrollings.
The basis transforms used for FFT and various other derived functions are based
on the following unrollings.
The functions can be easily adapted to double precision floats as well.
## Parity permutation
# Parity permutation
The basis transforms described here all use the following permutation:
``` C
void ff_tx_gen_split_radix_parity_revtab(int *revtab, int len, int inv,
int basis, int dual_stride);
```
Parity means even and odd complex numbers will be split, e.g. the even
coefficients will come first, after which the odd coefficients will be
placed. For example, a 4-point transform's coefficients after reordering:
@@ -36,8 +33,7 @@ register or 0. This allows to reuse SSE functions as dual-transform
functions in AVX mode.
If length is smaller than basis/2 this function will not do anything.
## 4-point FFT transform
# 4-point FFT transform
The only permutation this transform needs is to swap the `z[1]` and `z[2]`
elements when performing an inverse transform, which in the assembly code is
hardcoded with the function itself being templated and duplicated for each
@@ -84,8 +80,7 @@ static void fft4(FFTComplex *z)
}
```
## 8-point AVX FFT transform
# 8-point AVX FFT transform
Input must be pre-permuted using the parity lookup table, generated via
`ff_tx_gen_split_radix_parity_revtab`.
@@ -198,8 +193,7 @@ This theme continues throughout the document. Note that in the actual assembly c
the paths are interleaved to improve unit saturation and CPU dependency tracking, so
to more clearly see them, you'll need to deinterleave the instructions.
## 8-point SSE/ARM64 FFT transform
# 8-point SSE/ARM64 FFT transform
Input must be pre-permuted using the parity lookup table, generated via
`ff_tx_gen_split_radix_parity_revtab`.
@@ -311,8 +305,7 @@ static void fft8(FFTComplex *z)
Most functions here are highly tuned to use x86's addsub instruction to save on
external sign mask loading.
## 16-point AVX FFT transform
# 16-point AVX FFT transform
This version expects the output of the 8 and 4-point transforms to follow the
even/odd convention established above.
@@ -452,8 +445,7 @@ static void fft16(FFTComplex *z)
}
```
## AVX split-radix synthesis
# AVX split-radix synthesis
To create larger transforms, the following unrolling of the C split-radix
function is used.
@@ -713,8 +705,8 @@ beginning to overlap, particularly `[o1]` with `[0]` after the second iteration.
To iterate further, set `z = &z[16]` via `z += 8` for the second iteration. After
the 4th iteration, the layout resets, so repeat the same.
## 15-point AVX FFT transform
# 15-point AVX FFT transform
The 15-point transform is based on the following unrolling. The input
must be permuted via the following loop:
+20 -10
View File
@@ -2,6 +2,14 @@
# common bits used by all libraries
#
DEFAULT_X86ASMD=.dbg
ifeq ($(DBG),1)
X86ASMD=$(DEFAULT_X86ASMD)
else
X86ASMD=
endif
ifndef SUBDIR
LINK = $(LD) $(1)
@@ -27,7 +35,7 @@ M = @$(call ECHO,$(TAG),$@);
$(foreach VAR,$(BRIEF), \
$(eval override $(VAR) = @$$(call ECHO,$(VAR),$$(MSG)); $($(VAR))))
$(foreach VAR,$(SILENT),$(eval override $(VAR) = @$($(VAR))))
$(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_PATH)/%=%)); $(INSTALL))
$(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL))
endif
# Prepend to a recursively expanded variable without making it simply expanded.
@@ -97,6 +105,10 @@ COMPILE_LASX = $(call COMPILE,CC,LASXFLAGS)
%_host.o: %.c
$(COMPILE_HOSTC)
%$(DEFAULT_X86ASMD).asm: %.asm
$(DEPX86ASM) $(X86ASMFLAGS) -M -o $@ $< > $(@:.asm=.d)
$(X86ASM) $(X86ASMFLAGS) -e $< | sed '/^%/d;/^$$/d;' > $@
%.o: %.asm
$(COMPILE_X86ASM)
-$(if $(ASMSTRIPFLAGS), $(STRIP) $(ASMSTRIPFLAGS) $@)
@@ -114,8 +126,8 @@ $(BIN2CEXE): ffbuild/bin2c_host.o
$(HOSTLD) $(HOSTLDFLAGS) $(HOSTLD_O) $^ $(HOSTEXTRALIBS)
RUN_BIN2C = $(BIN2C) $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) $@ $(subst .,_,$(basename $(notdir $@)))
RUN_GZIP = $(M)mkdir -p $(dir $@) && gzip -nc9 $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) >$@
RUN_MINIFY = $(M)mkdir -p $(dir $@) && sed 's!/\\*.*\\*/!!g' $< | tr '\n' ' ' | tr -s ' ' | sed 's/^ //; s/ $$//' > $@
RUN_GZIP = $(M)gzip -nc9 $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) >$@
RUN_MINIFY = $(M)sed 's!/\\*.*\\*/!!g' $< | tr '\n' ' ' | tr -s ' ' | sed 's/^ //; s/ $$//' > $@
%.gz: TAG = GZIP
%.min: TAG = MINIFY
@@ -185,7 +197,7 @@ endif
clean::
$(RM) $(BIN2CEXE) $(CLEANSUFFIXES:%=ffbuild/%)
%.c %.h %.S %.pc %.ver %.version: TAG = GEN
%.c %.h %.pc %.ver %.version: TAG = GEN
# Dummy rule to stop make trying to rebuild removed or renamed headers
%.h %_template.c:
@@ -205,7 +217,6 @@ OBJS += $(OBJS-yes)
SHLIBOBJS += $(SHLIBOBJS-yes)
STLIBOBJS += $(STLIBOBJS-yes)
FFLIBS := $($(NAME)_FFLIBS) $(FFLIBS-yes) $(FFLIBS)
DEVPROGS += $(DEVPROGS-yes)
TESTPROGS += $(TESTPROGS-yes)
LDLIBS = $(FFLIBS:%=%$(BUILDSUF))
@@ -214,8 +225,7 @@ FFEXTRALIBS := $(LDLIBS:%=$(LD_LIB)) $(foreach lib,EXTRALIBS-$(NAME) $(FFLIBS:%=
OBJS := $(sort $(OBJS:%=$(SUBDIR)%))
SHLIBOBJS := $(sort $(SHLIBOBJS:%=$(SUBDIR)%))
STLIBOBJS := $(sort $(STLIBOBJS:%=$(SUBDIR)%))
TESTOBJS := $(TESTOBJS:%=$(SUBDIR)tests/%) $(TESTPROGS:%=$(SUBDIR)tests/%.o) $(DEVPROGS:%=$(SUBDIR)%.o)
DEVPROGS := $(DEVPROGS:%=$(SUBDIR)%$(EXESUF))
TESTOBJS := $(TESTOBJS:%=$(SUBDIR)tests/%) $(TESTPROGS:%=$(SUBDIR)tests/%.o)
TESTPROGS := $(TESTPROGS:%=$(SUBDIR)tests/%$(EXESUF))
HOSTOBJS := $(HOSTPROGS:%=$(SUBDIR)%.o)
HOSTPROGS := $(HOSTPROGS:%=$(SUBDIR)%$(HOSTEXESUF))
@@ -256,14 +266,14 @@ $(TOOLOBJS): | tools
OUTDIRS := $(OUTDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(SHLIBOBJS) $(STLIBOBJS) $(TESTOBJS))
CLEANSUFFIXES = *.d *.gcda *.gcno *.h.c *.ho *.map *.o *.objs *.pc *.ptx *.ptx.gz *.ptx.c *.spv *.spv.gz *.spv.c *.gen.asm *.gen.c *.gen.S *.ver *.version *.html.gz *.html.c *.css.min.gz *.css.min *.css.c *~ *.ilk *.pdb
CLEANSUFFIXES = *.d *.gcda *.gcno *.h.c *.ho *.map *.o *.objs *.pc *.ptx *.ptx.gz *.ptx.c *.spv *.spv.gz *.spv.c *.ver *.version *.html.gz *.html.c *.css.min.gz *.css.min *.css.c *$(DEFAULT_X86ASMD).asm *~ *.ilk *.pdb
LIBSUFFIXES = *.a *.lib *.so *.so.* *.dylib *.dll *.def *.dll.a
define RULES
clean::
$(RM) $(DEVPROGS) $(HOSTPROGS) $(TESTPROGS) $(TOOLS)
$(RM) $(HOSTPROGS) $(TESTPROGS) $(TOOLS)
endef
$(eval $(RULES))
-include $(wildcard $(OBJS:.o=.d) $(HOSTOBJS:.o=.d) $(TESTOBJS:.o=.d) $(HOBJS:.o=.d) $(SHLIBOBJS:.o=.d) $(STLIBOBJS:.o=.d) $(SPVOBJS:.spv.o=.d))
-include $(wildcard $(OBJS:.o=.d) $(HOSTOBJS:.o=.d) $(TESTOBJS:.o=.d) $(HOBJS:.o=.d) $(SHLIBOBJS:.o=.d) $(STLIBOBJS:.o=.d) $(SPVOBJS:.spv.o=.d)) $(OBJS:.o=$(DEFAULT_X86ASMD).d)
+7 -26
View File
@@ -14,15 +14,6 @@ INSTHEADERS := $(INSTHEADERS) $(HEADERS:%=$(SUBDIR)%)
all-$(CONFIG_STATIC): $(SUBDIR)$(LIBNAME) $(SUBDIR)lib$(FULLNAME).pc
all-$(CONFIG_SHARED): $(SUBDIR)$(SLIBNAME) $(SUBDIR)lib$(FULLNAME).pc
# Make <4.0 does not support the built-in file function;
# versions that do support it should use it, as it's
# faster and isn't bound by command line length limits.
ifeq (4.0,$(firstword $(sort 4.0 $(MAKE_VERSION))))
HAVE_BUILTIN_FILE := yes
else
HAVE_BUILTIN_FILE := no
endif
LIBOBJS := $(OBJS) $(SHLIBOBJS) $(STLIBOBJS) $(SUBDIR)%.h.o $(TESTOBJS)
$(LIBOBJS) $(LIBOBJS:.o=.s) $(LIBOBJS:.o=.i): CPPFLAGS += -DHAVE_AV_CONFIG_H
@@ -45,11 +36,7 @@ endif
$(SUBDIR)$(LIBNAME): $(OBJS) $(STLIBOBJS)
$(RM) $@
ifeq ($(RESPONSE_FILES),yes)
ifeq ($(HAVE_BUILTIN_FILE),yes)
$(file >$@.objs,$^)
else
$(Q)echo $^ > $@.objs
endif
$(AR) $(ARFLAGS) $(AR_O) @$@.objs
else
$(AR) $(ARFLAGS) $(AR_O) $^
@@ -64,13 +51,15 @@ install-libs-$(CONFIG_SHARED): install-lib$(NAME)-shared
define RULES
$(TOOLS): THISLIB = $(FULLNAME:%=$(LD_LIB))
$(TESTPROGS) $(DEVPROGS): THISLIB = $(SUBDIR)$(LIBNAME)
$(TESTPROGS): THISLIB = $(SUBDIR)$(LIBNAME)
$(LIBOBJS): CPPFLAGS += -DBUILDING_$(NAME)
$(NAME)LINK_EXE_ARGS = $(LDFLAGS) $(LDEXEFLAGS)
$(NAME)LINK_SO_ARGS = $(SHFLAGS) $(LDFLAGS) $(LDSOFLAGS)
$(NAME)LINK_EXTRA = $(FFEXTRALIBS)
$(DEVPROGS) $(TESTPROGS) $(TOOLS): %$(EXESUF): %.o
$(TESTPROGS) $(TOOLS): %$(EXESUF): %.o
$$(call LINK,$$(call $(NAME)LINK_EXE_ARGS) $$(LD_O) $$(filter %.o,$$^) $$(THISLIB) $$(call $(NAME)LINK_EXTRA) $$(EXTRALIBS-$$(*F)) $$(ELIBS))
$(SUBDIR)lib$(NAME).version: $(SUBDIR)version.h $(SUBDIR)version_major.h | $(SUBDIR)
@@ -86,20 +75,14 @@ $(SUBDIR)$(SLIBNAME): $(SUBDIR)$(SLIBNAME_WITH_MAJOR)
$(Q)cd ./$(SUBDIR) && $(LN_S) $(SLIBNAME_WITH_MAJOR) $(SLIBNAME)
$(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(OBJS) $(SHLIBOBJS) $(SUBDIR)lib$(NAME).ver
$(SLIB_CREATE_DEF_CMD)
ifeq ($(RESPONSE_FILES),yes)
ifeq ($(HAVE_BUILTIN_FILE),yes)
$$(file >$$@.objs,$$(filter %.o,$$^))
else
$(Q)echo $$(filter %.o,$$^) > $$@.objs
endif
endif
$(Q)$(SLIB_CREATE_DEF_CMD)
ifeq ($(RESPONSE_FILES),yes)
$$(call LINK,$$(call $(NAME)LINK_SO_ARGS) $$(LD_O) @$$@.objs $$(call $(NAME)LINK_EXTRA))
else
$$(call LINK,$$(call $(NAME)LINK_SO_ARGS) $$(LD_O) $$(filter %.o,$$^) $$(call $(NAME)LINK_EXTRA))
endif
$(Q)$(SLIB_EXTRA_CMD)
$(SLIB_EXTRA_CMD)
-$(RM) $$@.objs
ifdef SUBDIR
@@ -113,9 +96,7 @@ clean::
install-lib$(NAME)-shared: $(SUBDIR)$(SLIBNAME)
$(Q)mkdir -p "$(SHLIBDIR)"
$$(INSTALL) -m 755 $$< "$(SHLIBDIR)/$(SLIB_INSTALL_NAME)"
ifneq ($(STRIPTYPE),nostrip)
$$(STRIP) "$(SHLIBDIR)/$(SLIB_INSTALL_NAME)"
endif
$(Q)$(foreach F,$(SLIB_INSTALL_LINKS),(cd "$(SHLIBDIR)" && $(LN_S) $(SLIB_INSTALL_NAME) $(F));)
$(if $(SLIB_INSTALL_EXTRA_SHLIB),$$(INSTALL) -m 644 $(SLIB_INSTALL_EXTRA_SHLIB:%=$(SUBDIR)%) "$(SHLIBDIR)")
$(if $(SLIB_INSTALL_EXTRA_LIB),$(Q)mkdir -p "$(LIBDIR)")
@@ -153,6 +134,6 @@ endef
$(eval $(RULES))
$(TOOLS): $(DEP_LIBS) $(SUBDIR)$($(CONFIG_SHARED:yes=S)LIBNAME)
$(TESTPROGS) $(DEVPROGS): $(DEP_LIBS) $(SUBDIR)$(LIBNAME)
$(TESTPROGS): $(DEP_LIBS) $(SUBDIR)$(LIBNAME)
testprogs: $(TESTPROGS)
+1 -1
View File
@@ -1267,7 +1267,7 @@ unsigned stream_specifier_match(const StreamSpecifier *ss,
break;
}
}
av_fallthrough;
// fall-through
case STREAM_LIST_GROUP_IDX:
if (ss->stream_list == STREAM_LIST_GROUP_IDX &&
ss->list_id >= 0 && ss->list_id < s->nb_stream_groups)
-10
View File
@@ -216,16 +216,6 @@ void term_init(void)
#endif
#if HAVE_TERMIOS_H
/* A closed fd 0 is later reused by the first opened input file. read_key()
* would then read from that input instead of the terminal and corrupt the
* stream, so disable interaction when fd 0 is not an open descriptor.
*/
if (stdin_interaction && fcntl(0, F_GETFD) == -1) {
av_log(NULL, AV_LOG_WARNING,
"fd 0 is not an open file descriptor, stdin interaction disabled\n");
stdin_interaction = 0;
}
if (stdin_interaction) {
struct termios tty;
if (tcgetattr (0, &tty) == 0) {
+34 -4
View File
@@ -51,6 +51,16 @@
#include "libswresample/swresample.h"
// deprecated features
#define FFMPEG_OPT_QPHIST 1
#define FFMPEG_OPT_ADRIFT_THRESHOLD 1
#define FFMPEG_OPT_ENC_TIME_BASE_NUM 1
#define FFMPEG_OPT_TOP 1
#define FFMPEG_OPT_FORCE_KF_SOURCE_NO_DROP 1
#define FFMPEG_OPT_VSYNC_DROP 1
#define FFMPEG_OPT_VSYNC 1
#define FFMPEG_OPT_FILTER_SCRIPT 1
#define FFMPEG_ERROR_RATE_EXCEEDED FFERRTAG('E', 'R', 'E', 'D')
enum VideoSyncMethod {
@@ -59,6 +69,9 @@ enum VideoSyncMethod {
VSYNC_CFR,
VSYNC_VFR,
VSYNC_VSCFR,
#if FFMPEG_OPT_VSYNC_DROP
VSYNC_DROP,
#endif
};
enum EncTimeBase {
@@ -205,17 +218,21 @@ typedef struct OptionsContext {
SpecifierOptList display_rotations;
SpecifierOptList display_hflips;
SpecifierOptList display_vflips;
SpecifierOptList mastering_displays;
SpecifierOptList content_lights;
SpecifierOptList rc_overrides;
SpecifierOptList intra_matrices;
SpecifierOptList inter_matrices;
SpecifierOptList chroma_intra_matrices;
#if FFMPEG_OPT_TOP
SpecifierOptList top_field_first;
#endif
SpecifierOptList metadata_map;
SpecifierOptList presets;
SpecifierOptList copy_initial_nonkeyframes;
SpecifierOptList copy_prior_start;
SpecifierOptList filters;
#if FFMPEG_OPT_FILTER_SCRIPT
SpecifierOptList filter_scripts;
#endif
SpecifierOptList reinit_filters;
SpecifierOptList drop_changed;
SpecifierOptList fix_sub_duration;
@@ -417,6 +434,9 @@ enum DecoderFlags {
// decoder should override timestamps by fixed framerate
// from DecoderOpts.framerate
DECODER_FLAG_FRAMERATE_FORCED = (1 << 2),
#if FFMPEG_OPT_TOP
DECODER_FLAG_TOP_FIELD_FIRST = (1 << 3),
#endif
DECODER_FLAG_SEND_END_TS = (1 << 4),
// force bitexact decoding
DECODER_FLAG_BITEXACT = (1 << 5),
@@ -449,7 +469,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 +500,9 @@ typedef struct InputStream {
/* framerate forced with -r */
AVRational framerate;
#if FFMPEG_OPT_TOP
int top_field_first;
#endif
int fix_sub_duration;
@@ -581,6 +604,9 @@ typedef struct EncStats {
enum {
KF_FORCE_SOURCE = 1,
#if FFMPEG_OPT_FORCE_KF_SOURCE_NO_DROP
KF_FORCE_SOURCE_NO_DROP = 2,
#endif
// force keyframe if lavfi.scd.time metadata is set
KF_FORCE_SCD_METADATA = 3,
};
@@ -637,6 +663,10 @@ typedef struct OutputStream {
Encoder *enc;
/* video only */
#if FFMPEG_OPT_TOP
int top_field_first;
#endif
int bitexact;
int bits_per_raw_sample;
@@ -783,7 +813,7 @@ int check_avoptions_used(const AVDictionary *opts, const AVDictionary *opts_used
int assert_file_overwrite(const char *filename);
int find_codec(void *logctx, const char *name,
enum AVMediaType type, int encoder, const AVCodec **codec);
int parse_and_set_vsync(const char *arg, enum VideoSyncMethod *vsync_var, int file_idx, int st_idx);
int parse_and_set_vsync(const char *arg, enum VideoSyncMethod *vsync_var, int file_idx, int st_idx, int is_global);
int filtergraph_is_simple(const FilterGraph *fg);
int fg_create_simple(FilterGraph **pfg,
+9 -11
View File
@@ -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)
@@ -1616,15 +1621,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) {
+53 -203
View File
@@ -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,6 +96,12 @@ typedef struct DemuxStream {
uint64_t nb_packets;
// combined size of all the packets read
uint64_t data_size;
// latest wallclock time at which packet reading resumed after a stall - used for readrate
int64_t resume_wc;
// timestamp of first packet sent after the latest stall - used for readrate
int64_t resume_pts;
// measure of how far behind packet reading is against spceified readrate
int64_t lag;
} DemuxStream;
typedef struct DemuxStreamGroup {
@@ -141,13 +144,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 +514,43 @@ 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;
if (pts <= stream_ts_offset + initial_burst) continue;
max_pts = stream_ts_offset + initial_burst + (int64_t)(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 + (int64_t)(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,
@@ -998,7 +982,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 +1248,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 +1301,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 +1366,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 +1483,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 +1508,12 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
return ret;
}
}
#if FFMPEG_OPT_TOP
ist->top_field_first = -1;
opt_match_per_stream_int(ist, &o->top_field_first, ic, st, &ist->top_field_first);
#endif
break;
case AVMEDIA_TYPE_AUDIO: {
const char *ch_layout_str = NULL;
@@ -1804,11 +1659,6 @@ static int istg_parse_tile_grid(const OptionsContext *o, Demuxer *d, InputStream
if (tg->nb_tiles == 1)
return 0;
if (!tg->nb_tiles) {
av_log(istg, AV_LOG_FATAL, "A demuxer exported an invalid tile group stream group. "
"This is a bug, please report it.\n");
return AVERROR_BUG;
}
memset(&opts, 0, sizeof(opts));
+18 -5
View File
@@ -227,9 +227,6 @@ int enc_open(void *opaque, const AVFrame *frame)
frame->ch_layout.nb_channels > 0);
enc_ctx->sample_fmt = frame->format;
enc_ctx->sample_rate = frame->sample_rate;
if (!enc_ctx->frame_size && (!(enc->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) ||
(enc_ctx->flags2 & AV_CODEC_FLAG2_FIXED_FRAME_SIZE)))
enc_ctx->frame_size = frame->nb_samples;
ret = av_channel_layout_copy(&enc_ctx->ch_layout, &frame->ch_layout);
if (ret < 0)
return ret;
@@ -283,8 +280,17 @@ int enc_open(void *opaque, const AVFrame *frame)
}
if (enc_ctx->flags & (AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME) ||
(frame->flags & AV_FRAME_FLAG_INTERLACED)) {
int top_field_first = !!(frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST);
(frame->flags & AV_FRAME_FLAG_INTERLACED)
#if FFMPEG_OPT_TOP
|| ost->top_field_first >= 0
#endif
) {
int top_field_first =
#if FFMPEG_OPT_TOP
ost->top_field_first >= 0 ?
ost->top_field_first :
#endif
!!(frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST);
if (enc->id == AV_CODEC_ID_MJPEG)
enc_ctx->field_order = top_field_first ? AV_FIELD_TT : AV_FIELD_BB;
@@ -796,6 +802,13 @@ static int frame_encode(OutputStream *ost, AVFrame *frame, AVPacket *pkt)
if (type == AVMEDIA_TYPE_VIDEO) {
frame->quality = e->enc_ctx->global_quality;
frame->pict_type = forced_kf_apply(e, &ost->kf, frame);
#if FFMPEG_OPT_TOP
if (ost->top_field_first >= 0) {
frame->flags &= ~AV_FRAME_FLAG_TOP_FIELD_FIRST;
frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST * (!!ost->top_field_first);
}
#endif
} else {
if (!(e->enc_ctx->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE) &&
e->enc_ctx->ch_layout.nb_channels != frame->ch_layout.nb_channels) {
+37 -21
View File
@@ -27,7 +27,6 @@
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
#include "libavutil/attributes.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/bprint.h"
@@ -51,6 +50,8 @@ typedef struct FilterGraphPriv {
// true when the filtergraph contains only meta filters
// that do not modify the frame data
int is_meta;
// source filters are present in the graph
int have_sources;
int disable_conversions;
unsigned nb_outputs_done;
@@ -1037,7 +1038,6 @@ void fg_free(FilterGraph **pfg)
av_frame_free(&ifp->opts.fallback);
av_buffer_unref(&ifp->hw_frames_ctx);
av_channel_layout_uninit(&ifp->ch_layout);
av_freep(&ifilter->linklabel);
av_freep(&ifp->opts.name);
av_frame_side_data_free(&ifp->side_data, &ifp->nb_side_data);
@@ -1143,6 +1143,16 @@ int fg_create(FilterGraph **pfg, char **graph_desc, Scheduler *sch,
if (ret < 0)
goto fail;
for (unsigned i = 0; i < graph->nb_filters; i++) {
const AVFilter *f = graph->filters[i]->filter;
if ((!avfilter_filter_pad_count(f, 0) &&
!(f->flags & AVFILTER_FLAG_DYNAMIC_INPUTS)) ||
!strcmp(f->name, "apad")) {
fgp->have_sources = 1;
break;
}
}
for (AVFilterInOut *cur = inputs; cur; cur = cur->next) {
InputFilter *const ifilter = ifilter_alloc(fg);
@@ -1671,10 +1681,7 @@ static int configure_output_video_filter(FilterGraphPriv *fgp, AVFilterGraph *gr
av_frame_side_data_remove(&ofp->side_data, &ofp->nb_side_data, AV_FRAME_DATA_DISPLAYMATRIX);
}
if ((ofp->width || ofp->height) && (ofp->flags & OFILTER_FLAG_AUTOSCALE) &&
// skip add scale for hardware format
!(ofp->format != AV_PIX_FMT_NONE &&
av_pix_fmt_desc_get(ofp->format)->flags & AV_PIX_FMT_FLAG_HWACCEL)) {
if ((ofp->width || ofp->height) && (ofp->flags & OFILTER_FLAG_AUTOSCALE)) {
char args[255];
AVFilterContext *filter;
const AVDictionaryEntry *e = NULL;
@@ -1799,8 +1806,10 @@ static int configure_output_audio_filter(FilterGraphPriv *fgp, AVFilterGraph *gr
pad_idx = 0;
}
if (ofilter->apad)
if (ofilter->apad) {
AUTO_INSERT_FILTER("-apad", "apad", ofilter->apad);
fgp->have_sources = 1;
}
snprintf(name, sizeof(name), "trim for output %s", ofilter->output_name);
ret = insert_trim(fgp, ofp->trim_start_us, ofp->trim_duration_us,
@@ -2257,7 +2266,8 @@ static int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *fr
for (int i = 0; i < frame->nb_side_data; i++) {
const AVSideDataDescriptor *desc = av_frame_side_data_desc(frame->side_data[i]->type);
if (!(desc->props & AV_SIDE_DATA_PROP_GLOBAL))
if (!(desc->props & AV_SIDE_DATA_PROP_GLOBAL) ||
frame->side_data[i]->type == AV_FRAME_DATA_DISPLAYMATRIX)
continue;
ret = av_frame_side_data_clone(&ifp->side_data,
@@ -2268,11 +2278,8 @@ static int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *fr
}
sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX);
if (sd) {
if (sd)
memcpy(ifp->displaymatrix, sd->data, sizeof(ifp->displaymatrix));
if (ifp->opts.flags & IFILTER_FLAG_AUTOROTATE)
av_frame_side_data_remove(&ifp->side_data, &ifp->nb_side_data, AV_FRAME_DATA_DISPLAYMATRIX);
}
ifp->displaymatrix_present = !!sd;
/* Copy downmix related side data to InputFilterPriv so it may be propagated
@@ -2540,7 +2547,11 @@ static void video_sync_process(OutputFilterPriv *ofp, AVFrame *frame,
if (delta0 < 0 &&
delta > 0 &&
fps->vsync_method != VSYNC_PASSTHROUGH) {
fps->vsync_method != VSYNC_PASSTHROUGH
#if FFMPEG_OPT_VSYNC_DROP
&& fps->vsync_method != VSYNC_DROP
#endif
) {
if (delta0 < -0.6) {
av_log(ofp, AV_LOG_VERBOSE, "Past duration %f too large\n", -delta0);
} else
@@ -2558,7 +2569,6 @@ static void video_sync_process(OutputFilterPriv *ofp, AVFrame *frame,
delta0 = 0;
ofp->next_pts = llrint(sync_ipts);
}
av_fallthrough;
case VSYNC_CFR:
// FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
if (frame_drop_threshold && delta < frame_drop_threshold && fps->frame_number) {
@@ -2579,6 +2589,9 @@ static void video_sync_process(OutputFilterPriv *ofp, AVFrame *frame,
ofp->next_pts = llrint(sync_ipts);
frame->duration = llrint(duration);
break;
#if FFMPEG_OPT_VSYNC_DROP
case VSYNC_DROP:
#endif
case VSYNC_PASSTHROUGH:
ofp->next_pts = llrint(sync_ipts);
frame->duration = llrint(duration);
@@ -2823,10 +2836,8 @@ static int fg_output_step(OutputFilterPriv *ofp, FilterGraphThread *fgt,
if (!fgt->got_frame) {
ret = clone_side_data(&fd->side_data, &fd->nb_side_data,
ofp->side_data, ofp->nb_side_data, 0);
if (ret < 0) {
av_frame_unref(frame);
if (ret < 0)
return ret;
}
}
fd->wallclock[LATENCY_PROBE_FILTER_POST] = av_gettime_relative();
@@ -2860,6 +2871,7 @@ static int read_frames(FilterGraph *fg, FilterGraphThread *fgt,
AVFrame *frame)
{
FilterGraphPriv *fgp = fgp_from_fg(fg);
int did_step = 0;
// graph not configured, just select the input to request
if (!fgt->graph) {
@@ -2878,7 +2890,7 @@ static int read_frames(FilterGraph *fg, FilterGraphThread *fgt,
return AVERROR_BUG;
}
if (fgp->nb_outputs_done < fg->nb_outputs) {
while (fgp->nb_outputs_done < fg->nb_outputs) {
int ret;
/* Reap all buffers present in the buffer sinks */
@@ -2893,6 +2905,9 @@ static int read_frames(FilterGraph *fg, FilterGraphThread *fgt,
}
}
// return after one iteration, so that scheduler can rate-control us
if (did_step && fgp->have_sources)
return 0;
ret = avfilter_graph_request_oldest(fgt->graph);
if (ret == AVERROR(EAGAIN)) {
@@ -2909,8 +2924,7 @@ static int read_frames(FilterGraph *fg, FilterGraphThread *fgt,
}
fgt->next_in = fg->nb_inputs;
// return so that scheduler can rate-control us
return 0;
did_step = 1;
}
return AVERROR_EOF;
@@ -3167,7 +3181,7 @@ static int send_frame(FilterGraph *fg, FilterGraphThread *fgt,
const char *color_space_name = av_color_space_name(frame->colorspace);
const char *color_range_name = av_color_range_name(frame->color_range);
const char *alpha_mode = av_alpha_mode_name(frame->alpha_mode);
av_bprintf(&reason, "video parameters changed to %s(%s, %s), %dx%d, %s alpha, ",
av_bprintf(&reason, "video parameters changed to %s(%s, %s), %dx%d, %s alpha,",
unknown_if_null(pixel_format_name), unknown_if_null(color_range_name),
unknown_if_null(color_space_name), frame->width, frame->height,
unknown_if_null(alpha_mode));
@@ -3323,6 +3337,8 @@ static int filter_thread(void *arg)
o = (intptr_t)fgt.frame->opaque;
o = (intptr_t)fgt.frame->opaque;
// message on the control stream
if (input_idx == fg->nb_inputs) {
FilterCommand *fc;
+5
View File
@@ -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
+3
View File
@@ -81,6 +81,9 @@ typedef struct MuxStream {
int copy_initial_nonkeyframes;
int copy_prior_start;
int streamcopy_started;
#if FFMPEG_OPT_VSYNC_DROP
int ts_drop;
#endif
AVRational frame_rate;
AVRational max_frame_rate;
+83 -24
View File
@@ -417,19 +417,45 @@ static int ost_get_filters(const OptionsContext *o, AVFormatContext *oc,
OutputStream *ost, char **dst)
{
const char *filters = NULL;
#if FFMPEG_OPT_FILTER_SCRIPT
const char *filters_script = NULL;
opt_match_per_stream_str(ost, &o->filter_scripts, oc, ost->st, &filters_script);
#endif
opt_match_per_stream_str(ost, &o->filters, oc, ost->st, &filters);
if (!ost->ist) {
if (filters) {
if (
#if FFMPEG_OPT_FILTER_SCRIPT
filters_script ||
#endif
filters) {
av_log(ost, AV_LOG_ERROR,
"Filtergraph '%s' was specified for a stream fed from a complex "
"%s '%s' was specified for a stream fed from a complex "
"filtergraph. Simple and complex filtering cannot be used "
"together for the same stream.\n", filters);
"together for the same stream.\n",
#if FFMPEG_OPT_FILTER_SCRIPT
filters ? "Filtergraph" : "Filtergraph script",
filters ? filters : filters_script
#else
"Filtergraph", filters
#endif
);
return AVERROR(EINVAL);
}
return 0;
}
#if FFMPEG_OPT_FILTER_SCRIPT
if (filters_script && filters) {
av_log(ost, AV_LOG_ERROR, "Both -filter and -filter_script set\n");
return AVERROR(EINVAL);
}
if (filters_script)
*dst = read_file_to_string(filters_script);
else
#endif
if (filters)
*dst = av_strdup(filters);
else
@@ -735,10 +761,21 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
opt_match_per_stream_int(ost, &o->force_fps, oc, st, &ms->force_fps);
#if FFMPEG_OPT_TOP
ost->top_field_first = -1;
opt_match_per_stream_int(ost, &o->top_field_first, oc, st, &ost->top_field_first);
if (ost->top_field_first >= 0)
av_log(ost, AV_LOG_WARNING, "-top is deprecated, use the setfield filter instead\n");
#endif
#if FFMPEG_OPT_VSYNC
*vsync_method = video_sync_method;
#else
*vsync_method = VSYNC_AUTO;
#endif
opt_match_per_stream_str(ost, &o->fps_mode, oc, st, &fps_mode);
if (fps_mode) {
ret = parse_and_set_vsync(fps_mode, vsync_method, ost->file->index, ost->index);
ret = parse_and_set_vsync(fps_mode, vsync_method, ost->file->index, ost->index, 0);
if (ret < 0)
return ret;
}
@@ -773,6 +810,10 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
*vsync_method = VSYNC_VSCFR;
}
}
#if FFMPEG_OPT_VSYNC_DROP
if (*vsync_method == VSYNC_DROP)
ms->ts_drop = 1;
#endif
}
return 0;
@@ -999,12 +1040,28 @@ static int streamcopy_init(const OptionsContext *o, const Muxer *mux,
int ret = 0;
const char *filters = NULL;
#if FFMPEG_OPT_FILTER_SCRIPT
const char *filters_script = NULL;
opt_match_per_stream_str(ost, &o->filter_scripts, mux->fc, ost->st, &filters_script);
#endif
opt_match_per_stream_str(ost, &o->filters, mux->fc, ost->st, &filters);
if (filters) {
if (
#if FFMPEG_OPT_FILTER_SCRIPT
filters_script ||
#endif
filters) {
av_log(ost, AV_LOG_ERROR,
"Filtergraph '%s' was specified, but codec copy was selected. "
"Filtering and streamcopy cannot be used together.\n", filters);
"%s '%s' was specified, but codec copy was selected. "
"Filtering and streamcopy cannot be used together.\n",
#if FFMPEG_OPT_FILTER_SCRIPT
filters ? "Filtergraph" : "Filtergraph script",
filters ? filters : filters_script
#else
"Filtergraph", filters
#endif
);
return AVERROR(EINVAL);
}
@@ -1344,11 +1401,20 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
q = (AVRational){ ENC_TIME_BASE_FILTER, 0 };
} else {
ret = av_parse_ratio(&q, enc_time_base, INT_MAX, 0, NULL);
if (ret < 0 || q.den <= 0 || q.num < 0) {
if (ret < 0 || q.den <= 0
#if !FFMPEG_OPT_ENC_TIME_BASE_NUM
|| q.num < 0
#endif
) {
av_log(ost, AV_LOG_FATAL, "Invalid time base: %s\n", enc_time_base);
ret = ret < 0 ? ret : AVERROR(EINVAL);
goto fail;
}
#if FFMPEG_OPT_ENC_TIME_BASE_NUM
if (q.num < 0)
av_log(ost, AV_LOG_WARNING, "-enc_time_base -1 is deprecated,"
" use -enc_time_base demux\n");
#endif
}
enc_tb = q;
@@ -1465,8 +1531,6 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
if (oc->oformat->flags & AVFMT_GLOBALHEADER && ost->enc)
ost->enc->enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
if (oc->oformat->flags & AVFMT_FIXED_FRAMESIZE && ost->enc)
ost->enc->enc_ctx->flags2 |= AV_CODEC_FLAG2_FIXED_FRAME_SIZE;
opt_match_per_stream_int(ost, &o->copy_initial_nonkeyframes,
oc, st, &ms->copy_initial_nonkeyframes);
@@ -2063,8 +2127,7 @@ static int setup_sync_queues(Muxer *mux, AVFormatContext *oc,
nb_interleaved += IS_INTERLEAVED(type);
nb_av_enc += IS_AV_ENC(ost, type);
nb_audio_fs += (ost->enc && type == AVMEDIA_TYPE_AUDIO &&
(!(ost->enc->enc_ctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) ||
(ost->enc->enc_ctx->flags2 & AV_CODEC_FLAG2_FIXED_FRAME_SIZE)));
!(ost->enc->enc_ctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE));
limit_frames |= ms->max_frames < INT64_MAX;
limit_frames_av_enc |= (ms->max_frames < INT64_MAX) && IS_AV_ENC(ost, type);
@@ -2489,10 +2552,6 @@ static int of_map_group(Muxer *mux, AVDictionary **dict, AVBPrint *bp, const cha
}
break;
}
case AV_STREAM_GROUP_PARAMS_LCEVC:
case AV_STREAM_GROUP_PARAMS_TREF:
case AV_STREAM_GROUP_PARAMS_DOLBY_VISION:
break;
default:
av_log(mux, AV_LOG_ERROR, "Unsupported mapped group type %d.\n", stg->type);
ret = AVERROR(EINVAL);
@@ -2515,10 +2574,6 @@ static int of_parse_group_token(Muxer *mux, const char *token, char *ptr)
{ .i64 = AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT }, .unit = "type" },
{ "iamf_mix_presentation", NULL, 0, AV_OPT_TYPE_CONST,
{ .i64 = AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION }, .unit = "type" },
{ "lcevc", NULL, 0, AV_OPT_TYPE_CONST,
{ .i64 = AV_STREAM_GROUP_PARAMS_LCEVC }, .unit = "type" },
{ "tref", NULL, 0, AV_OPT_TYPE_CONST,
{ .i64 = AV_STREAM_GROUP_PARAMS_TREF }, .unit = "type" },
{ NULL },
};
const AVClass class = {
@@ -2593,10 +2648,6 @@ static int of_parse_group_token(Muxer *mux, const char *token, char *ptr)
ret = avformat_stream_group_add_stream(stg, oc->streams[idx]);
if (ret < 0)
goto end;
OutputStream *ost = mux->of.streams[idx];
if (ost->enc && (type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT ||
type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION))
ost->enc->enc_ctx->flags2 |= AV_CODEC_FLAG2_FIXED_FRAME_SIZE;
}
while (e = av_dict_get(dict, "stg", e, 0)) {
char *endptr;
@@ -2621,6 +2672,8 @@ static int of_parse_group_token(Muxer *mux, const char *token, char *ptr)
ret = of_parse_iamf_submixes(mux, stg, ptr);
break;
default:
av_log(mux, AV_LOG_FATAL, "Unknown group type %d.\n", type);
ret = AVERROR(EINVAL);
break;
}
@@ -3227,6 +3280,12 @@ static int process_forced_keyframes(Muxer *mux, const OptionsContext *o)
// parse it only for static kf timings
} else if (!strcmp(forced_keyframes, "source")) {
ost->kf.type = KF_FORCE_SOURCE;
#if FFMPEG_OPT_FORCE_KF_SOURCE_NO_DROP
} else if (!strcmp(forced_keyframes, "source_no_drop")) {
av_log(ost, AV_LOG_WARNING, "The 'source_no_drop' value for "
"-force_key_frames is deprecated, use just 'source'\n");
ost->kf.type = KF_FORCE_SOURCE;
#endif
} else if (!strcmp(forced_keyframes, "scd_metadata")) {
ost->kf.type = KF_FORCE_SCD_METADATA;
} else {
+109 -11
View File
@@ -56,6 +56,9 @@ char *vstats_filename;
float dts_delta_threshold = 10;
float dts_error_threshold = 3600*30;
#if FFMPEG_OPT_VSYNC
enum VideoSyncMethod video_sync_method = VSYNC_AUTO;
#endif
float frame_drop_threshold = 0;
int do_benchmark = 0;
int do_benchmark_all = 0;
@@ -356,17 +359,38 @@ int view_specifier_parse(const char **pspec, ViewSpecifier *vs)
return 0;
}
int parse_and_set_vsync(const char *arg, enum VideoSyncMethod *vsync_var, int file_idx, int st_idx)
int parse_and_set_vsync(const char *arg, enum VideoSyncMethod *vsync_var, int file_idx, int st_idx, int is_global)
{
if (!av_strcasecmp(arg, "cfr")) *vsync_var = VSYNC_CFR;
else if (!av_strcasecmp(arg, "vfr")) *vsync_var = VSYNC_VFR;
else if (!av_strcasecmp(arg, "passthrough")) *vsync_var = VSYNC_PASSTHROUGH;
else if (!av_strcasecmp(arg, "auto")) *vsync_var = VSYNC_AUTO;
else {
#if FFMPEG_OPT_VSYNC_DROP
else if (!av_strcasecmp(arg, "drop")) {
av_log(NULL, AV_LOG_WARNING, "-vsync/fps_mode drop is deprecated\n");
*vsync_var = VSYNC_DROP;
}
#endif
else if (!is_global && !av_strcasecmp(arg, "auto")) *vsync_var = VSYNC_AUTO;
else if (!is_global) {
av_log(NULL, AV_LOG_FATAL, "Invalid value %s specified for fps_mode of #%d:%d.\n", arg, file_idx, st_idx);
return AVERROR(EINVAL);
}
#if FFMPEG_OPT_VSYNC
if (is_global && *vsync_var == VSYNC_AUTO) {
int ret;
double num;
ret = parse_number("vsync", arg, OPT_TYPE_INT, VSYNC_AUTO, VSYNC_VFR, &num);
if (ret < 0)
return ret;
video_sync_method = num;
av_log(NULL, AV_LOG_WARNING, "Passing a number to -vsync is deprecated,"
" use a string argument as described in the manual.\n");
}
#endif
return 0;
}
@@ -621,7 +645,6 @@ static int opt_map(void *optctx, const char *opt, const char *arg)
for (i = 0; i < o->nb_stream_maps; i++) {
m = &o->stream_maps[i];
if (file_idx == m->file_index &&
!m->linklabel &&
m->stream_index >= 0 &&
m->stream_index < input_files[m->file_index]->nb_streams &&
stream_specifier_match(&ss,
@@ -1210,6 +1233,14 @@ static int opt_audio_filters(void *optctx, const char *opt, const char *arg)
return parse_option(o, "filter:a", arg, options);
}
#if FFMPEG_OPT_VSYNC
static int opt_vsync(void *optctx, const char *opt, const char *arg)
{
av_log(NULL, AV_LOG_WARNING, "-vsync is deprecated. Use -fps_mode\n");
return parse_and_set_vsync(arg, &video_sync_method, -1, -1, 1);
}
#endif
static int opt_timecode(void *optctx, const char *opt, const char *arg)
{
OptionsContext *o = optctx;
@@ -1250,6 +1281,31 @@ static int opt_filter_complex(void *optctx, const char *opt, const char *arg)
return 0;
}
#if FFMPEG_OPT_FILTER_SCRIPT
static int opt_filter_complex_script(void *optctx, const char *opt, const char *arg)
{
GlobalOptionsContext *go = optctx;
char *graph_desc;
int ret;
graph_desc = read_file_to_string(arg);
if (!graph_desc)
return AVERROR(EINVAL);
av_log(NULL, AV_LOG_WARNING, "-%s is deprecated, use -/filter_complex %s instead\n",
opt, arg);
ret = GROW_ARRAY(go->filtergraphs, go->nb_filtergraphs);
if (ret < 0) {
av_freep(&graph_desc);
return ret;
}
go->filtergraphs[go->nb_filtergraphs - 1] = graph_desc;
return 0;
}
#endif
void show_help_default(const char *opt, const char *arg)
{
int show_advanced = 0, show_avoptions = 0;
@@ -1540,6 +1596,22 @@ int opt_timelimit(void *optctx, const char *opt, const char *arg)
return 0;
}
#if FFMPEG_OPT_QPHIST
static int opt_qphist(void *optctx, const char *opt, const char *arg)
{
av_log(NULL, AV_LOG_WARNING, "Option -%s is deprecated and has no effect\n", opt);
return 0;
}
#endif
#if FFMPEG_OPT_ADRIFT_THRESHOLD
static int opt_adrift_threshold(void *optctx, const char *opt, const char *arg)
{
av_log(NULL, AV_LOG_WARNING, "Option -%s is deprecated and has no effect\n", opt);
return 0;
}
#endif
static const char *const alt_channel_layout[] = { "ch_layout", NULL};
static const char *const alt_codec[] = { "c", "acodec", "vcodec", "scodec", "dcodec", NULL };
static const char *const alt_filter[] = { "af", "vf", NULL };
@@ -1746,6 +1818,11 @@ const OptionDef options[] = {
{ "filter_buffered_frames", OPT_TYPE_INT, OPT_EXPERT,
{ &filter_buffered_frames },
"maximum number of buffered frames in a filter graph" },
#if FFMPEG_OPT_FILTER_SCRIPT
{ "filter_script", OPT_TYPE_STRING, OPT_PERSTREAM | OPT_EXPERT | OPT_OUTPUT,
{ .off = OFFSET(filter_scripts) },
"deprecated, use -/filter", "filename" },
#endif
{ "reinit_filter", OPT_TYPE_INT, OPT_PERSTREAM | OPT_INPUT | OPT_EXPERT,
{ .off = OFFSET(reinit_filters) },
"reinit filtergraph on input parameter changes", "" },
@@ -1761,6 +1838,11 @@ const OptionDef options[] = {
{ "lavfi", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_EXPERT,
{ .func_arg = opt_filter_complex },
"create a complex filtergraph", "graph_description" },
#if FFMPEG_OPT_FILTER_SCRIPT
{ "filter_complex_script", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_EXPERT,
{ .func_arg = opt_filter_complex_script },
"deprecated, use -/filter_complex instead", "filename" },
#endif
{ "print_graphs", OPT_TYPE_BOOL, 0,
{ &print_graphs },
"print execution graph data to stderr" },
@@ -1860,12 +1942,6 @@ const OptionDef options[] = {
{ .off = OFFSET(display_vflips) },
"set display vertical flip for stream(s) "
"(overrides any display rotation if it is not set)"},
{ "mastering_display", OPT_TYPE_STRING, OPT_VIDEO | OPT_PERSTREAM | OPT_INPUT | OPT_EXPERT,
{ .off = OFFSET(mastering_displays) },
"set SMPTE2084 mastering display color volume info" },
{ "content_light", OPT_TYPE_STRING, OPT_VIDEO | OPT_PERSTREAM | OPT_INPUT | OPT_EXPERT,
{ .off = OFFSET(content_lights) },
"set SMPTE2084 Max CLL and Max FALL values" },
{ "vn", OPT_TYPE_BOOL, OPT_VIDEO | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT,
{ .off = OFFSET(video_disable) },
"disable video" },
@@ -1913,7 +1989,7 @@ const OptionDef options[] = {
.u1.name_canon = "tag", },
{ "fps_mode", OPT_TYPE_STRING, OPT_VIDEO | OPT_EXPERT | OPT_PERSTREAM | OPT_OUTPUT,
{ .off = OFFSET(fps_mode) },
"set framerate mode for matching video streams" },
"set framerate mode for matching video streams; overrides vsync" },
{ "force_fps", OPT_TYPE_BOOL, OPT_VIDEO | OPT_EXPERT | OPT_PERSTREAM | OPT_OUTPUT,
{ .off = OFFSET(force_fps) },
"force the selected framerate, disable the best supported framerate selection" },
@@ -2098,5 +2174,27 @@ const OptionDef options[] = {
{ .func_arg = opt_filter_hw_device },
"set hardware device used when filtering", "device" },
// deprecated options
#if FFMPEG_OPT_ADRIFT_THRESHOLD
{ "adrift_threshold", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_EXPERT,
{ .func_arg = opt_adrift_threshold },
"deprecated, does nothing", "threshold" },
#endif
#if FFMPEG_OPT_TOP
{ "top", OPT_TYPE_INT, OPT_VIDEO | OPT_EXPERT | OPT_PERSTREAM | OPT_INPUT | OPT_OUTPUT,
{ .off = OFFSET(top_field_first) },
"deprecated, use the setfield video filter", "" },
#endif
#if FFMPEG_OPT_QPHIST
{ "qphist", OPT_TYPE_FUNC, OPT_VIDEO | OPT_EXPERT,
{ .func_arg = opt_qphist },
"deprecated, does nothing" },
#endif
#if FFMPEG_OPT_VSYNC
{ "vsync", OPT_TYPE_FUNC, OPT_FUNC_ARG | OPT_EXPERT,
{ .func_arg = opt_vsync },
"set video sync method globally; deprecated, use -fps_mode", "" },
#endif
{ NULL, },
};
+53 -164
View File
@@ -32,7 +32,6 @@
#include "libavcodec/packet.h"
#include "libavutil/avassert.h"
#include "libavutil/container_fifo.h"
#include "libavutil/error.h"
#include "libavutil/fifo.h"
#include "libavutil/frame.h"
@@ -87,7 +86,6 @@ typedef struct SchDec {
unsigned nb_outputs;
SchTask task;
SchWaiter waiter;
// Queue for receiving input packets, one stream.
ThreadQueue *queue;
@@ -97,9 +95,6 @@ typedef struct SchDec {
// temporary storage used by sch_dec_send()
AVFrame *send_frame;
// internal queue of undecoded packets used by sch_dec_receive()
AVContainerFifo *overflow;
} SchDec;
typedef struct SchSyncQueue {
@@ -440,7 +435,7 @@ static void task_init(Scheduler *sch, SchTask *task, enum SchedulerNodeType type
task->func_arg = func_arg;
}
static int64_t trailing_dts(const Scheduler *sch)
static int64_t trailing_dts(const Scheduler *sch, int count_finished)
{
int64_t min_dts = INT64_MAX;
@@ -450,7 +445,7 @@ static int64_t trailing_dts(const Scheduler *sch)
for (unsigned j = 0; j < mux->nb_streams; j++) {
const SchMuxStream *ms = &mux->streams[j];
if (ms->source_finished)
if (ms->source_finished && !count_finished)
continue;
if (ms->last_dts == AV_NOPTS_VALUE)
return AV_NOPTS_VALUE;
@@ -462,26 +457,6 @@ static int64_t trailing_dts(const Scheduler *sch)
return min_dts == INT64_MAX ? AV_NOPTS_VALUE : min_dts;
}
static int64_t progressing_dts(const Scheduler *sch, int count_finished)
{
int64_t max_dts = INT64_MIN;
for (unsigned i = 0; i < sch->nb_mux; i++) {
const SchMux *mux = &sch->mux[i];
for (unsigned j = 0; j < mux->nb_streams; j++) {
const SchMuxStream *ms = &mux->streams[j];
if (ms->source_finished && !count_finished)
continue;
if (ms->last_dts != AV_NOPTS_VALUE)
max_dts = FFMAX(max_dts, ms->last_dts);
}
}
return max_dts == INT64_MIN ? AV_NOPTS_VALUE : max_dts;
}
void sch_remove_filtergraph(Scheduler *sch, int idx)
{
SchFilterGraph *fg = &sch->filters[idx];
@@ -553,7 +528,6 @@ void sch_free(Scheduler **psch)
tq_free(&dec->queue);
av_thread_message_queue_free(&dec->queue_end_ts);
av_container_fifo_free(&dec->overflow);
for (unsigned j = 0; j < dec->nb_outputs; j++) {
SchDecOutput *o = &dec->outputs[j];
@@ -565,8 +539,6 @@ void sch_free(Scheduler **psch)
av_freep(&dec->outputs);
av_frame_free(&dec->send_frame);
waiter_uninit(&dec->waiter);
}
av_freep(&sch->dec);
@@ -817,14 +789,6 @@ int sch_add_dec(Scheduler *sch, SchThreadFunc func, void *ctx, int send_end_ts)
return ret;
}
dec->overflow = av_container_fifo_alloc_avpacket(0);
if (!dec->overflow)
return AVERROR(ENOMEM);
ret = waiter_init(&dec->waiter);
if (ret < 0)
return ret;
return idx;
}
@@ -1318,15 +1282,7 @@ int sch_mux_sub_heartbeat_add(Scheduler *sch, unsigned mux_idx, unsigned stream_
return 0;
}
enum {
UNCHOKE_DEMUX = (1 << 0),
UNCHOKE_FILTER = (1 << 1),
UNCHOKE_DECODE = (1 << 2),
UNCHOKE_ALL = UNCHOKE_DEMUX | UNCHOKE_FILTER | UNCHOKE_DECODE,
};
static void unchoke_for_stream(Scheduler *sch, SchedulerNode src, int flags);
static void unchoke_for_stream(Scheduler *sch, SchedulerNode src);
// Unchoke any filter graphs that are downstream of this node, to prevent it
// from getting stuck trying to push data to a full queue
@@ -1338,10 +1294,8 @@ static void unchoke_downstream(Scheduler *sch, SchedulerNode *dst)
switch (dst->type) {
case SCH_NODE_TYPE_DEC:
dec = &sch->dec[dst->idx];
if (!dec->waiter.choked_next) {
for (int i = 0; i < dec->nb_outputs; i++)
unchoke_downstream(sch, dec->outputs[i].dst);
}
for (int i = 0; i < dec->nb_outputs; i++)
unchoke_downstream(sch, dec->outputs[i].dst);
break;
case SCH_NODE_TYPE_ENC:
enc = &sch->enc[dst->idx];
@@ -1357,8 +1311,8 @@ static void unchoke_downstream(Scheduler *sch, SchedulerNode *dst)
fg->waiter.choked_next = 0;
} else {
// ensure that this filter graph is not stuck waiting for
// input from a different upstream source
unchoke_for_stream(sch, fg->inputs[fg->best_input].src, UNCHOKE_ALL);
// input from a different upstream demuxer
unchoke_for_stream(sch, fg->inputs[fg->best_input].src);
}
break;
default:
@@ -1367,30 +1321,23 @@ static void unchoke_downstream(Scheduler *sch, SchedulerNode *dst)
}
}
static void unchoke_for_stream(Scheduler *sch, SchedulerNode src, int flags)
static void unchoke_for_stream(Scheduler *sch, SchedulerNode src)
{
while (1) {
SchFilterGraph *fg;
SchDemux *demux;
SchDec *dec;
switch (src.type) {
case SCH_NODE_TYPE_DEMUX:
// fed directly by a demuxer (i.e. not through a filtergraph)
demux = &sch->demux[src.idx];
if (demux->waiter.choked_next == 0)
return; // prevent infinite loop
if (flags & UNCHOKE_DEMUX) {
demux->waiter.choked_next = 0;
for (int i = 0; i < demux->nb_streams; i++)
unchoke_downstream(sch, demux->streams[i].dst);
}
demux->waiter.choked_next = 0;
for (int i = 0; i < demux->nb_streams; i++)
unchoke_downstream(sch, demux->streams[i].dst);
return;
case SCH_NODE_TYPE_DEC:
dec = &sch->dec[src.idx];
if (!(flags & UNCHOKE_DECODE))
return;
dec->waiter.choked_next = 0;
src = dec->src;
src = sch->dec[src.idx].src;
continue;
case SCH_NODE_TYPE_ENC:
src = sch->enc[src.idx].src;
@@ -1400,8 +1347,7 @@ static void unchoke_for_stream(Scheduler *sch, SchedulerNode src, int flags)
// the filtergraph contains internal sources and
// requested to be scheduled directly
if (fg->best_input == fg->nb_inputs) {
if (flags & UNCHOKE_FILTER)
fg->waiter.choked_next = 0;
fg->waiter.choked_next = 0;
return;
}
src = fg->inputs[fg->best_input].src;
@@ -1453,23 +1399,17 @@ static void schedule_update_locked(Scheduler *sch)
if (atomic_load(&sch->terminate))
return;
dts = trailing_dts(sch);
dts = trailing_dts(sch, 0);
atomic_store(&sch->last_dts, progressing_dts(sch, 0));
atomic_store(&sch->last_dts, dts);
// initialize our internal state
#define RESET_WAITER(field) \
do { \
for (unsigned i = 0; i < sch->nb_##field; i++) { \
SchWaiter *w = &sch->field[i].waiter; \
w->choked_prev = atomic_load(&w->choked); \
w->choked_next = 1; \
} \
} while (0)
RESET_WAITER(demux);
RESET_WAITER(filters);
RESET_WAITER(dec);
for (unsigned type = 0; type < 2; type++)
for (unsigned i = 0; i < (type ? sch->nb_filters : sch->nb_demux); i++) {
SchWaiter *w = type ? &sch->filters[i].waiter : &sch->demux[i].waiter;
w->choked_prev = atomic_load(&w->choked);
w->choked_next = 1;
}
// figure out the sources that are allowed to proceed
for (unsigned i = 0; i < sch->nb_mux; i++) {
@@ -1480,18 +1420,15 @@ static void schedule_update_locked(Scheduler *sch)
// unblock sources for output streams that are not finished
// and not too far ahead of the trailing stream
if (ms->source_finished) {
// still allow decoders to drain
unchoke_for_stream(sch, ms->src, UNCHOKE_DECODE);
if (ms->source_finished)
continue;
}
if (dts == AV_NOPTS_VALUE && ms->last_dts != AV_NOPTS_VALUE)
continue;
if (dts != AV_NOPTS_VALUE && ms->last_dts - dts >= SCHEDULE_TOLERANCE)
continue;
// resolve the source to unchoke
unchoke_for_stream(sch, ms->src, UNCHOKE_ALL);
unchoke_for_stream(sch, ms->src);
have_unchoked = 1;
}
}
@@ -1504,41 +1441,33 @@ static void schedule_update_locked(Scheduler *sch)
for (unsigned j = 0; j < fg->nb_inputs; j++) {
SchFilterIn *fi = &fg->inputs[j];
if (fi->receive_finished && !fi->send_finished)
unchoke_for_stream(sch, fi->src, UNCHOKE_ALL);
unchoke_for_stream(sch, fi->src);
}
}
// make sure to unchoke at least one source, if still available
#define UNCHOKE_ONCE(field) \
do { \
for (unsigned i = 0; !have_unchoked && i < sch->nb_##field; i++) { \
SchWaiter *w = &sch->field[i].waiter; \
if (!sch->field[i].task_exited) { \
w->choked_next = 0; \
have_unchoked = 1; \
break; \
} \
} \
} while (0)
for (unsigned type = 0; !have_unchoked && type < 2; type++)
for (unsigned i = 0; i < (type ? sch->nb_filters : sch->nb_demux); i++) {
int exited = type ? sch->filters[i].task_exited : sch->demux[i].task_exited;
SchWaiter *w = type ? &sch->filters[i].waiter : &sch->demux[i].waiter;
if (!exited) {
w->choked_next = 0;
have_unchoked = 1;
break;
}
}
UNCHOKE_ONCE(demux);
UNCHOKE_ONCE(filters);
for (unsigned type = 0; type < 2; type++) {
for (unsigned i = 0; i < (type ? sch->nb_filters : sch->nb_demux); i++) {
SchWaiter *w = type ? &sch->filters[i].waiter : &sch->demux[i].waiter;
if (w->choked_prev != w->choked_next) {
waiter_set(w, w->choked_next);
if (!type)
choke_demux(sch, i, w->choked_next);
}
}
}
#define UPDATE_WAITER(field) \
do { \
for (unsigned i = 0; i < sch->nb_##field; i++) { \
SchWaiter *w = &sch->field[i].waiter; \
if (w->choked_prev != w->choked_next) { \
waiter_set(w, w->choked_next); \
if (offsetof(Scheduler, field) == offsetof(Scheduler, demux)) \
choke_demux(sch, i, w->choked_next); \
} \
} \
} while (0)
UPDATE_WAITER(demux);
UPDATE_WAITER(filters);
UPDATE_WAITER(dec);
}
enum {
@@ -2257,7 +2186,7 @@ int sch_mux_receive(Scheduler *sch, unsigned mux_idx, AVPacket *pkt)
av_assert0(mux_idx < sch->nb_mux);
mux = &sch->mux[mux_idx];
ret = tq_receive(mux->queue, &stream_idx, pkt, 0);
ret = tq_receive(mux->queue, &stream_idx, pkt);
pkt->stream_index = stream_idx;
return ret;
}
@@ -2341,12 +2270,6 @@ int sch_dec_receive(Scheduler *sch, unsigned dec_idx, AVPacket *pkt)
av_assert0(dec_idx < sch->nb_dec);
dec = &sch->dec[dec_idx];
retry:
// Pull a packet from the overflow FIFO while unchoked or expecting EOF ts
if (av_container_fifo_can_read(dec->overflow) &&
(!atomic_load(&dec->waiter.choked) || dec->expect_end_ts))
return av_container_fifo_read(dec->overflow, pkt, 0);
// the decoder should have given us post-flush end timestamp in pkt
if (dec->expect_end_ts) {
Timestamp ts = (Timestamp){ .ts = pkt->pts, .tb = pkt->time_base };
@@ -2357,32 +2280,14 @@ retry:
dec->expect_end_ts = 0;
}
ret = tq_receive(dec->queue, &dummy, pkt, 0);
ret = tq_receive(dec->queue, &dummy, pkt);
av_assert0(dummy <= 0);
// drain packets from overflow queue before returning EOF
if (ret == AVERROR_EOF && av_container_fifo_can_read(dec->overflow)) {
int terminate = waiter_wait(sch, &dec->waiter);
if (terminate)
return ret;
return av_container_fifo_read(dec->overflow, pkt, 0);
} else if (ret < 0)
return ret;
// got a flush packet, on the next call to this function the decoder
// should give us post-flush end timestamp (after draining overflow fifo)
if (!pkt->data && !pkt->side_data_elems && dec->queue_end_ts)
// will give us post-flush end timestamp
if (ret >= 0 && !pkt->data && !pkt->side_data_elems && dec->queue_end_ts)
dec->expect_end_ts = 1;
// we got a packet, but we're currently choked or have existing overflow
// packets; so push it to the FIFO first
if (atomic_load(&dec->waiter.choked) || av_container_fifo_can_read(dec->overflow)) {
ret = av_container_fifo_write(dec->overflow, pkt, 0);
if (ret < 0)
return ret;
goto retry;
}
return ret;
}
@@ -2516,7 +2421,7 @@ int sch_enc_receive(Scheduler *sch, unsigned enc_idx, AVFrame *frame)
av_assert0(enc_idx < sch->nb_enc);
enc = &sch->enc[enc_idx];
ret = tq_receive(enc->queue, &dummy, frame, 0);
ret = tq_receive(enc->queue, &dummy, frame);
av_assert0(dummy <= 0);
return ret;
@@ -2605,7 +2510,6 @@ int sch_filter_receive(Scheduler *sch, unsigned fg_idx,
unsigned *in_idx, AVFrame *frame)
{
SchFilterGraph *fg;
int ret, idx;
av_assert0(fg_idx < sch->nb_filters);
fg = &sch->filters[fg_idx];
@@ -2626,20 +2530,14 @@ int sch_filter_receive(Scheduler *sch, unsigned fg_idx,
}
if (*in_idx == fg->nb_inputs) {
// drain incoming frames before waiting, to avoid blocking downstream
ret = tq_receive(fg->queue, &idx, frame, THREAD_QUEUE_FLAG_NO_BLOCK);
if (ret >= 0) {
av_assert0(idx >= 0);
*in_idx = idx;
return 0;
}
int terminate = waiter_wait(sch, &fg->waiter);
return terminate ? AVERROR_EOF : AVERROR(EAGAIN);
}
while (1) {
ret = tq_receive(fg->queue, &idx, frame, 0);
int ret, idx;
ret = tq_receive(fg->queue, &idx, frame);
if (idx < 0)
return AVERROR_EOF;
else if (ret >= 0) {
@@ -2826,10 +2724,6 @@ int sch_stop(Scheduler *sch, int64_t *finish_ts)
atomic_store(&sch->terminate, 1);
// Ensure no other thread is currently in schedule_update_locked while
// we are choking all demuxers
pthread_mutex_lock(&sch->schedule_lock);
for (unsigned type = 0; type < 2; type++)
for (unsigned i = 0; i < (type ? sch->nb_demux : sch->nb_filters); i++) {
SchWaiter *w = type ? &sch->demux[i].waiter : &sch->filters[i].waiter;
@@ -2838,11 +2732,6 @@ int sch_stop(Scheduler *sch, int64_t *finish_ts)
choke_demux(sch, i, 0); // unfreeze to allow draining
}
for (unsigned i = 0; i < sch->nb_dec; i++)
waiter_set(&sch->dec[i].waiter, 0); // unfreeze to allow draining
pthread_mutex_unlock(&sch->schedule_lock);
for (unsigned i = 0; i < sch->nb_demux; i++) {
SchDemux *d = &sch->demux[i];
@@ -2879,7 +2768,7 @@ int sch_stop(Scheduler *sch, int64_t *finish_ts)
}
if (finish_ts)
*finish_ts = progressing_dts(sch, 1);
*finish_ts = trailing_dts(sch, 1);
sch->state = SCH_STATE_STOPPED;
+15 -18
View File
@@ -3007,7 +3007,6 @@ static int read_thread(void *arg)
// initial metadata as update.
st->event_flags &= ~AVSTREAM_EVENT_FLAG_METADATA_UPDATED;
}
ic->event_flags &= ~AVFMT_EVENT_FLAG_METADATA_UPDATED;
for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
if (wanted_stream_spec[i] && st_index[i] == -1) {
av_log(NULL, AV_LOG_ERROR, "Stream specifier %s does not match any %s stream\n", wanted_stream_spec[i], av_get_media_type_string(i));
@@ -3176,24 +3175,16 @@ static int read_thread(void *arg)
is->eof = 0;
}
if (show_status) {
if (ic->event_flags & AVFMT_EVENT_FLAG_METADATA_UPDATED) {
fprintf(stderr, "\x1b[2K\r");
dump_dictionary(NULL, ic->metadata,
"\r New metadata", " ", AV_LOG_INFO);
}
if (ic->streams[pkt->stream_index]->event_flags &
AVSTREAM_EVENT_FLAG_METADATA_UPDATED) {
fprintf(stderr, "\x1b[2K\r");
snprintf(metadata_description,
sizeof(metadata_description),
"\r New metadata for stream %d",
pkt->stream_index);
dump_dictionary(NULL, ic->streams[pkt->stream_index]->metadata,
metadata_description, " ", AV_LOG_INFO);
}
if (show_status && ic->streams[pkt->stream_index]->event_flags &
AVSTREAM_EVENT_FLAG_METADATA_UPDATED) {
fprintf(stderr, "\x1b[2K\r");
snprintf(metadata_description,
sizeof(metadata_description),
"\r New metadata for stream %d",
pkt->stream_index);
dump_dictionary(NULL, ic->streams[pkt->stream_index]->metadata,
metadata_description, " ", AV_LOG_INFO);
}
ic->event_flags &= ~AVFMT_EVENT_FLAG_METADATA_UPDATED;
ic->streams[pkt->stream_index]->event_flags &= ~AVSTREAM_EVENT_FLAG_METADATA_UPDATED;
/* check if packet is in play range specified by user, then queue, otherwise discard */
@@ -3883,6 +3874,12 @@ int main(int argc, char **argv)
flags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER;
if (audio_disable)
flags &= ~SDL_INIT_AUDIO;
else {
/* Try to work around an occasional ALSA buffer underflow issue when the
* period size is NPOT due to ALSA resampling by forcing the buffer size. */
if (!SDL_getenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE"))
SDL_setenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE","1", 1);
}
if (display_disable)
flags &= ~SDL_INIT_VIDEO;
if (SDL_Init (flags)) {
+3 -1
View File
@@ -23,7 +23,9 @@
#include "ffplay_renderer.h"
#if (SDL_VERSION_ATLEAST(2, 0, 6) && CONFIG_LIBPLACEBO)
#define HAVE_VULKAN_RENDERER 1
/* Get PL_API_VER */
#include <libplacebo/config.h>
#define HAVE_VULKAN_RENDERER (PL_API_VER >= 278)
#else
#define HAVE_VULKAN_RENDERER 0
#endif
+54 -187
View File
@@ -39,7 +39,6 @@
#include "libavutil/avutil.h"
#include "libavutil/bprint.h"
#include "libavutil/channel_layout.h"
#include "libavutil/downmix_info.h"
#include "libavutil/display.h"
#include "libavutil/film_grain_params.h"
#include "libavutil/hdr_dynamic_metadata.h"
@@ -216,8 +215,6 @@ typedef enum {
SECTION_ID_STREAM_GROUP_SUBPIECE,
SECTION_ID_STREAM_GROUP_BLOCKS,
SECTION_ID_STREAM_GROUP_BLOCK,
SECTION_ID_STREAM_GROUP_SIDE_DATA_LIST,
SECTION_ID_STREAM_GROUP_SIDE_DATA,
SECTION_ID_STREAM_GROUP_STREAMS,
SECTION_ID_STREAM_GROUP_STREAM,
SECTION_ID_STREAM_GROUP_DISPOSITION,
@@ -301,7 +298,7 @@ static const AVTextFormatSection sections[] = {
[SECTION_ID_STREAM_GROUP_STREAM_TAGS] = { SECTION_ID_STREAM_GROUP_STREAM_TAGS, "tags", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_group_stream_tags" },
[SECTION_ID_STREAM_GROUP] = { SECTION_ID_STREAM_GROUP, "stream_group", 0, { SECTION_ID_STREAM_GROUP_TAGS, SECTION_ID_STREAM_GROUP_DISPOSITION, SECTION_ID_STREAM_GROUP_COMPONENTS, SECTION_ID_STREAM_GROUP_STREAMS, -1 } },
[SECTION_ID_STREAM_GROUP_COMPONENTS] = { SECTION_ID_STREAM_GROUP_COMPONENTS, "components", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_COMPONENT, -1 }, .element_name = "component", .unique_name = "stream_group_components" },
[SECTION_ID_STREAM_GROUP_COMPONENT] = { SECTION_ID_STREAM_GROUP_COMPONENT, "component", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_SIDE_DATA_LIST, SECTION_ID_STREAM_GROUP_SUBCOMPONENTS, -1 }, .unique_name = "stream_group_component", .element_name = "component_entry", .get_type = get_stream_group_type },
[SECTION_ID_STREAM_GROUP_COMPONENT] = { SECTION_ID_STREAM_GROUP_COMPONENT, "component", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_SUBCOMPONENTS, -1 }, .unique_name = "stream_group_component", .element_name = "component_entry", .get_type = get_stream_group_type },
[SECTION_ID_STREAM_GROUP_SUBCOMPONENTS] = { SECTION_ID_STREAM_GROUP_SUBCOMPONENTS, "subcomponents", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_SUBCOMPONENT, -1 }, .element_name = "component" },
[SECTION_ID_STREAM_GROUP_SUBCOMPONENT] = { SECTION_ID_STREAM_GROUP_SUBCOMPONENT, "subcomponent", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_PIECES, -1 }, .element_name = "subcomponent_entry", .get_type = get_raw_string_type },
[SECTION_ID_STREAM_GROUP_PIECES] = { SECTION_ID_STREAM_GROUP_PIECES, "pieces", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_PIECE, -1 }, .element_name = "piece", .unique_name = "stream_group_pieces" },
@@ -310,8 +307,6 @@ static const AVTextFormatSection sections[] = {
[SECTION_ID_STREAM_GROUP_SUBPIECE] = { SECTION_ID_STREAM_GROUP_SUBPIECE, "subpiece", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { SECTION_ID_STREAM_GROUP_BLOCKS, -1 }, .element_name = "subpiece_entry", .get_type = get_raw_string_type },
[SECTION_ID_STREAM_GROUP_BLOCKS] = { SECTION_ID_STREAM_GROUP_BLOCKS, "blocks", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_BLOCK, -1 }, .element_name = "block" },
[SECTION_ID_STREAM_GROUP_BLOCK] = { SECTION_ID_STREAM_GROUP_BLOCK, "block", AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS|AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE, { -1 }, .element_name = "block_entry", .get_type = get_raw_string_type },
[SECTION_ID_STREAM_GROUP_SIDE_DATA_LIST] = { SECTION_ID_STREAM_GROUP_SIDE_DATA_LIST, "side_data_list", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "stream_group_side_data_list" },
[SECTION_ID_STREAM_GROUP_SIDE_DATA] = { SECTION_ID_STREAM_GROUP_SIDE_DATA, "side_data", AV_TEXTFORMAT_SECTION_FLAG_HAS_TYPE|AV_TEXTFORMAT_SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .unique_name = "stream_group_side_data", .element_name = "side_datum", .get_type = get_packet_side_data_type },
[SECTION_ID_STREAM_GROUP_STREAMS] = { SECTION_ID_STREAM_GROUP_STREAMS, "streams", AV_TEXTFORMAT_SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_GROUP_STREAM, -1 }, .unique_name = "stream_group_streams" },
[SECTION_ID_STREAM_GROUP_STREAM] = { SECTION_ID_STREAM_GROUP_STREAM, "stream", 0, { SECTION_ID_STREAM_GROUP_STREAM_DISPOSITION, SECTION_ID_STREAM_GROUP_STREAM_TAGS, -1 }, .unique_name = "stream_group_stream" },
[SECTION_ID_STREAM_GROUP_DISPOSITION] = { SECTION_ID_STREAM_GROUP_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_group_disposition" },
@@ -345,11 +340,12 @@ static const char *print_input_filename;
static const AVInputFormat *iformat = NULL;
static const char *output_filename = NULL;
static const char unit_second_str[] = "s" ;
static const char unit_hertz_str[] = "Hz" ;
static const char unit_byte_str[] = "byte" ;
static const char unit_bit_per_second_str[] = "bit/s";
static unsigned int nb_streams;
static int nb_streams;
static uint64_t *nb_streams_packets;
static uint64_t *nb_streams_frames;
static int *selected_streams;
@@ -436,8 +432,8 @@ static void log_callback(void *ptr, int level, const char *fmt, va_list vl)
#define print_list_fmt(k, f, n, m, ...) do { \
av_bprint_clear(&pbuf); \
for (unsigned int idx = 0; idx < n; idx++) { \
for (unsigned int idx2 = 0; idx2 < m; idx2++) { \
for (int idx = 0; idx < n; idx++) { \
for (int idx2 = 0; idx2 < m; idx2++) { \
if (idx > 0 || idx2 > 0) \
av_bprint_chars(&pbuf, ' ', 1); \
av_bprintf(&pbuf, f, __VA_ARGS__); \
@@ -455,9 +451,7 @@ static void log_callback(void *ptr, int level, const char *fmt, va_list vl)
#define print_ts(k, v) avtext_print_ts(tfc, k, v, 0)
#define print_duration_time(k, v, tb) avtext_print_time(tfc, k, v, tb, 1)
#define print_duration_ts(k, v) avtext_print_ts(tfc, k, v, 1)
#define print_val(k, v, u) avtext_print_unit_integer(tfc, k, v, AV_TEXTFORMAT_VALUE_FMT_INT, u)
#define print_int_fmt(k, v, f, u) avtext_print_unit_integer(tfc, k, v, f, u)
#define print_decibel(k, v) avtext_print_unit_double(tfc, k, v, AV_TEXTFORMAT_VALUE_FMT_DECIBEL, 0)
#define print_val(k, v, u) avtext_print_unit_integer(tfc, k, v, u)
static void print_integers(AVTextFormatContext *tfc, const char *key,
const void *data, int size, const char *format,
@@ -509,30 +503,6 @@ static inline int show_tags(AVTextFormatContext *tfc, AVDictionary *tags, int se
return ret;
}
static void print_downmix_info(AVTextFormatContext *tfc,
const AVDownmixInfo *downmix_info)
{
switch (downmix_info->preferred_downmix_type) {
case AV_DOWNMIX_TYPE_LORO:
print_str("preferred_downmix_type", "loro");
break;
case AV_DOWNMIX_TYPE_LTRT:
print_str("preferred_downmix_type", "ltrt");
break;
case AV_DOWNMIX_TYPE_DPLII:
print_str("preferred_downmix_type", "dplII");
break;
default:
print_str("preferred_downmix_type", "unknown");
break;
}
print_decibel("center_mix_level_db", downmix_info->center_mix_level);
print_decibel("center_mix_level_ltrt_db", downmix_info->center_mix_level_ltrt);
print_decibel("surround_mix_level_db", downmix_info->surround_mix_level);
print_decibel("surround_mix_level_ltrt_db", downmix_info->surround_mix_level_ltrt);
print_decibel("lfe_mix_level_db", downmix_info->lfe_mix_level);
}
static void print_displaymatrix(AVTextFormatContext *tfc, const int32_t matrix[9])
{
double rotation = av_display_rotation_get(matrix);
@@ -831,62 +801,6 @@ static void print_dynamic_hdr10_plus(AVTextFormatContext *tfc, const AVDynamicHD
}
}
static void print_dynamic_hdr_smpte2094_app5(AVTextFormatContext *tfc, const AVDynamicHDRSmpte2094App5 *metadata)
{
if (!metadata)
return;
print_int("application_version", metadata->application_version);
print_int("minimum_application_version", metadata->minimum_application_version);
print_int("has_custom_hdr_reference_white_flag", metadata->has_custom_hdr_reference_white_flag);
print_int("has_adaptive_tone_map_flag", metadata->has_adaptive_tone_map_flag);
if (metadata->has_custom_hdr_reference_white_flag)
print_int("hdr_reference_white", metadata->hdr_reference_white);
if (!metadata->has_adaptive_tone_map_flag)
return;
print_int("baseline_hdr_headroom", metadata->baseline_hdr_headroom);
print_int("use_reference_white_tone_mapping_flag", metadata->use_reference_white_tone_mapping_flag);
if (metadata->use_reference_white_tone_mapping_flag)
return;
print_int("num_alternate_images", metadata->num_alternate_images);
print_int("gain_application_space_chromaticities_flag", metadata->gain_application_space_chromaticities_flag);
print_int("has_common_component_mix_params_flag", metadata->has_common_component_mix_params_flag);
print_int("has_common_curve_params_flag", metadata->has_common_curve_params_flag);
if (metadata->gain_application_space_chromaticities_flag == 3) {
for (int i = 0; i < 8; i++)
print_int("gain_application_space_chromaticities", metadata->gain_application_space_chromaticities[i]);
}
for (int a = 0; a < metadata->num_alternate_images; a++) {
print_int("alternate_hdr_headroom", metadata->alternate_hdr_headrooms[a]);
print_int("component_mixing_type", metadata->component_mixing_type[a]);
if (metadata->component_mixing_type[a] == 3) {
for (int k = 0; k < 6; k++) {
print_int("has_component_mixing_coefficient_flag", metadata->has_component_mixing_coefficient_flag[a][k]);
if (metadata->has_component_mixing_coefficient_flag[a][k])
print_int("component_mixing_coefficient", metadata->component_mixing_coefficient[a][k]);
}
}
print_int("gain_curve_num_control_points_minus_1", metadata->gain_curve_num_control_points_minus_1[a]);
print_int("gain_curve_use_pchip_slope_flag", metadata->gain_curve_use_pchip_slope_flag[a]);
for (int c = 0; c <= metadata->gain_curve_num_control_points_minus_1[a]; c++)
print_int("gain_curve_control_point_x", metadata->gain_curve_control_points_x[a][c]);
for (int c = 0; c <= metadata->gain_curve_num_control_points_minus_1[a]; c++)
print_int("gain_curve_control_point_y", metadata->gain_curve_control_points_y[a][c]);
if (!metadata->gain_curve_use_pchip_slope_flag[a]) {
for (int c = 0; c <= metadata->gain_curve_num_control_points_minus_1[a]; c++)
print_int("gain_curve_control_point_theta", metadata->gain_curve_control_points_theta[a][c]);
}
}
}
static void print_dynamic_hdr_vivid(AVTextFormatContext *tfc, const AVDynamicHDRVivid *metadata)
{
if (!metadata)
@@ -1028,7 +942,7 @@ static void print_film_grain_params(AVTextFormatContext *tfc,
avtext_print_section_footer(tfc);
}
for (unsigned uv = 0; uv < 2; uv++) {
for (int uv = 0; uv < 2; uv++) {
if (!aom->num_uv_points[uv] && !aom->chroma_scaling_from_luma)
continue;
@@ -1094,8 +1008,7 @@ static void print_film_grain_params(AVTextFormatContext *tfc,
}
static void print_pkt_side_data(AVTextFormatContext *tfc,
int width,
int height,
AVCodecParameters *par,
const AVPacketSideData *sd,
SectionID id_data)
{
@@ -1121,7 +1034,7 @@ static void print_pkt_side_data(AVTextFormatContext *tfc,
print_int("padding", spherical->padding);
} else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) {
size_t l, t, r, b;
av_spherical_tile_bounds(spherical, width, height,
av_spherical_tile_bounds(spherical, par->width, par->height,
&l, &t, &r, &b);
print_int("bound_left", l);
print_int("bound_top", t);
@@ -1368,7 +1281,7 @@ static void show_packet(AVTextFormatContext *tfc, InputFile *ifile, AVPacket *pk
print_time("dts_time", pkt->dts, &st->time_base);
print_duration_ts("duration", pkt->duration);
print_duration_time("duration_time", pkt->duration, &st->time_base);
print_int_fmt("size", pkt->size, AV_TEXTFORMAT_VALUE_FMT_BYTE, unit_byte_str);
print_val("size", pkt->size, unit_byte_str);
if (pkt->pos != -1) print_fmt ("pos", "%"PRId64, pkt->pos);
else print_str_opt("pos", "N/A");
print_fmt("flags", "%c%c%c", pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_',
@@ -1392,7 +1305,7 @@ static void show_packet(AVTextFormatContext *tfc, InputFile *ifile, AVPacket *pk
avtext_print_section_header(tfc, NULL, SECTION_ID_PACKET_SIDE_DATA_LIST);
for (int i = 0; i < pkt->side_data_elems; i++) {
print_pkt_side_data(tfc, st->codecpar->width, st->codecpar->height, &pkt->side_data[i],
print_pkt_side_data(tfc, st->codecpar, &pkt->side_data[i],
SECTION_ID_PACKET_SIDE_DATA);
avtext_print_section_footer(tfc);
}
@@ -1428,9 +1341,6 @@ static void show_subtitle(AVTextFormatContext *tfc, AVSubtitle *sub, AVStream *s
fflush(stdout);
}
static void print_iamf_param_definition(AVTextFormatContext *tfc, const char *name,
const AVIAMFParamDefinition *param, SectionID section_id);
static void print_frame_side_data(AVTextFormatContext *tfc,
const AVFrame *frame,
const AVStream *stream)
@@ -1444,9 +1354,7 @@ static void print_frame_side_data(AVTextFormatContext *tfc,
avtext_print_section_header(tfc, sd, SECTION_ID_FRAME_SIDE_DATA);
name = av_frame_side_data_name(sd->type);
print_str("side_data_type", name ? name : "unknown");
if (sd->type == AV_FRAME_DATA_DOWNMIX_INFO) {
print_downmix_info(tfc, (AVDownmixInfo *)sd->data);
} else if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
print_displaymatrix(tfc, (const int32_t*)sd->data);
} else if (sd->type == AV_FRAME_DATA_AFD && sd->size > 0) {
print_int("active_format", *sd->data);
@@ -1471,9 +1379,6 @@ static void print_frame_side_data(AVTextFormatContext *tfc,
} else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_PLUS) {
AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data;
print_dynamic_hdr10_plus(tfc, metadata);
} else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_SMPTE_2094_APP5) {
AVDynamicHDRSmpte2094App5 *metadata = (AVDynamicHDRSmpte2094App5 *)sd->data;
print_dynamic_hdr_smpte2094_app5(tfc, metadata);
} else if (sd->type == AV_FRAME_DATA_CONTENT_LIGHT_LEVEL) {
print_context_light_level(tfc, (AVContentLightMetadata *)sd->data);
} else if (sd->type == AV_FRAME_DATA_ICC_PROFILE) {
@@ -1495,11 +1400,6 @@ static void print_frame_side_data(AVTextFormatContext *tfc,
print_int("view_id", *(int*)sd->data);
} else if (sd->type == AV_FRAME_DATA_EXIF) {
print_int("size", sd->size);
} else if (sd->type == AV_FRAME_DATA_IAMF_MIX_GAIN_PARAM ||
sd->type == AV_FRAME_DATA_IAMF_DEMIXING_INFO_PARAM ||
sd->type == AV_FRAME_DATA_IAMF_RECON_GAIN_INFO_PARAM) {
const AVIAMFParamDefinition *param = (AVIAMFParamDefinition *)sd->data;
print_iamf_param_definition(tfc, NULL, param, SECTION_ID_FRAME_SIDE_DATA);
}
avtext_print_section_footer(tfc);
}
@@ -1533,7 +1433,7 @@ static void show_frame(AVTextFormatContext *tfc, AVFrame *frame, AVStream *strea
print_duration_time("duration_time", frame->duration, &stream->time_base);
if (fd && fd->pkt_pos != -1) print_fmt ("pkt_pos", "%"PRId64, fd->pkt_pos);
else print_str_opt("pkt_pos", "N/A");
if (fd && fd->pkt_size != -1) print_int_fmt("pkt_size", fd->pkt_size, AV_TEXTFORMAT_VALUE_FMT_BYTE, unit_byte_str);
if (fd && fd->pkt_size != -1) print_val ("pkt_size", fd->pkt_size, unit_byte_str);
else print_str_opt("pkt_size", "N/A");
switch (stream->codecpar->codec_type) {
@@ -1796,10 +1696,12 @@ static int read_interval_packets(AVTextFormatContext *tfc, InputFile *ifile,
}
av_packet_unref(pkt);
//Flush remaining frames that are cached in the decoder
for (int i = 0; i < ifile->nb_streams; i++) {
for (i = 0; i < ifile->nb_streams; i++) {
pkt->stream_index = i;
if (do_read_frames) {
while (process_frame(tfc, ifile, frame, pkt, &(int){1}) > 0);
if (ifile->streams[i].dec_ctx)
avcodec_flush_buffers(ifile->streams[i].dec_ctx);
}
}
@@ -1813,33 +1715,17 @@ end:
return ret;
}
static void flush_buffers(InputFile *ifile)
{
int i;
if (!do_read_frames)
return;
for (i = 0; i < ifile->nb_streams; i++) {
if (ifile->streams[i].dec_ctx)
avcodec_flush_buffers(ifile->streams[i].dec_ctx);
}
}
static int read_packets(AVTextFormatContext *tfc, InputFile *ifile)
{
AVFormatContext *fmt_ctx = ifile->fmt_ctx;
int ret = 0;
int i, ret = 0;
int64_t cur_ts = fmt_ctx->start_time;
if (read_intervals_nb == 0) {
ReadInterval interval = (ReadInterval) { .has_start = 0, .has_end = 0 };
ret = read_interval_packets(tfc, ifile, &interval, &cur_ts);
} else {
for (int i = 0; i < read_intervals_nb; i++) {
/* flushing buffers can reset parts of the private context which may be
* read by show_streams(), so only flush between each read_interval */
if (i)
flush_buffers(ifile);
for (i = 0; i < read_intervals_nb; i++) {
ret = read_interval_packets(tfc, ifile, &read_intervals[i], &cur_ts);
if (ret < 0)
break;
@@ -1852,7 +1738,7 @@ static int read_packets(AVTextFormatContext *tfc, InputFile *ifile)
static void print_dispositions(AVTextFormatContext *tfc, uint32_t disposition, SectionID section_id)
{
avtext_print_section_header(tfc, NULL, section_id);
for (unsigned i = 0; i < sizeof(disposition) * CHAR_BIT; i++) {
for (int i = 0; i < sizeof(disposition) * CHAR_BIT; i++) {
const char *disposition_str = av_disposition_to_string(1U << i);
if (disposition_str)
@@ -2075,7 +1961,7 @@ static int show_stream(AVTextFormatContext *tfc, AVFormatContext *fmt_ctx, int s
if (stream->codecpar->nb_coded_side_data) {
avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_SIDE_DATA_LIST);
for (int i = 0; i < stream->codecpar->nb_coded_side_data; i++) {
print_pkt_side_data(tfc, stream->codecpar->width, stream->codecpar->height, &stream->codecpar->coded_side_data[i],
print_pkt_side_data(tfc, stream->codecpar, &stream->codecpar->coded_side_data[i],
SECTION_ID_STREAM_SIDE_DATA);
avtext_print_section_footer(tfc);
}
@@ -2092,10 +1978,10 @@ static int show_stream(AVTextFormatContext *tfc, AVFormatContext *fmt_ctx, int s
static int show_streams(AVTextFormatContext *tfc, InputFile *ifile)
{
AVFormatContext *fmt_ctx = ifile->fmt_ctx;
int ret = 0;
int i, ret = 0;
avtext_print_section_header(tfc, NULL, SECTION_ID_STREAMS);
for (int i = 0; i < ifile->nb_streams; i++)
for (i = 0; i < ifile->nb_streams; i++)
if (selected_streams[i]) {
ret = show_stream(tfc, fmt_ctx, i, &ifile->streams[i], 0);
if (ret < 0)
@@ -2109,7 +1995,7 @@ static int show_streams(AVTextFormatContext *tfc, InputFile *ifile)
static int show_program(AVTextFormatContext *tfc, InputFile *ifile, AVProgram *program)
{
AVFormatContext *fmt_ctx = ifile->fmt_ctx;
int ret = 0;
int i, ret = 0;
avtext_print_section_header(tfc, NULL, SECTION_ID_PROGRAM);
print_int("program_id", program->id);
@@ -2123,7 +2009,7 @@ static int show_program(AVTextFormatContext *tfc, InputFile *ifile, AVProgram *p
goto end;
avtext_print_section_header(tfc, NULL, SECTION_ID_PROGRAM_STREAMS);
for (unsigned i = 0; i < program->nb_stream_indexes; i++) {
for (i = 0; i < program->nb_stream_indexes; i++) {
if (selected_streams[program->stream_index[i]]) {
ret = show_stream(tfc, fmt_ctx, program->stream_index[i], &ifile->streams[program->stream_index[i]], IN_PROGRAM);
if (ret < 0)
@@ -2140,10 +2026,10 @@ end:
static int show_programs(AVTextFormatContext *tfc, InputFile *ifile)
{
AVFormatContext *fmt_ctx = ifile->fmt_ctx;
int ret = 0;
int i, ret = 0;
avtext_print_section_header(tfc, NULL, SECTION_ID_PROGRAMS);
for (unsigned i = 0; i < fmt_ctx->nb_programs; i++) {
for (i = 0; i < fmt_ctx->nb_programs; i++) {
AVProgram *program = fmt_ctx->programs[i];
if (!program)
continue;
@@ -2167,7 +2053,7 @@ static void print_tile_grid_params(AVTextFormatContext *tfc, const AVStreamGroup
print_int("width", tile_grid->width);
print_int("height", tile_grid->height);
avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_SUBCOMPONENTS);
for (unsigned i = 0; i < tile_grid->nb_tiles; i++) {
for (int i = 0; i < tile_grid->nb_tiles; i++) {
avtext_print_section_header(tfc, "tile_offset", SECTION_ID_STREAM_GROUP_SUBCOMPONENT);
print_int("stream_index", tile_grid->offsets[i].idx);
print_int("tile_horizontal_offset", tile_grid->offsets[i].horizontal);
@@ -2175,15 +2061,6 @@ static void print_tile_grid_params(AVTextFormatContext *tfc, const AVStreamGroup
avtext_print_section_footer(tfc);
}
avtext_print_section_footer(tfc);
if (tile_grid->nb_coded_side_data) {
avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_SIDE_DATA_LIST);
for (int i = 0; i < tile_grid->nb_coded_side_data; i++) {
print_pkt_side_data(tfc, tile_grid->width, tile_grid->height, &tile_grid->coded_side_data[i],
SECTION_ID_STREAM_GROUP_SIDE_DATA);
avtext_print_section_footer(tfc);
}
avtext_print_section_footer(tfc);
}
avtext_print_section_footer(tfc);
}
@@ -2191,21 +2068,12 @@ static void print_iamf_param_definition(AVTextFormatContext *tfc, const char *na
const AVIAMFParamDefinition *param, SectionID section_id)
{
SectionID subsection_id, parameter_section_id;
if (section_id == SECTION_ID_FRAME_SIDE_DATA)
subsection_id = SECTION_ID_FRAME_SIDE_DATA_COMPONENT_LIST;
else {
av_assert0(sections[section_id].children_ids[0] != -1);
subsection_id = sections[section_id].children_ids[0];
}
av_assert0(sections[subsection_id].children_ids[0] != -1);
subsection_id = sections[section_id].children_ids[0];
av_assert0(subsection_id != -1);
parameter_section_id = sections[subsection_id].children_ids[0];
// When printing as part of side-data, skip opening a section
if (section_id != SECTION_ID_FRAME_SIDE_DATA)
avtext_print_section_header(tfc, "IAMF Param Definition", section_id);
if (name)
print_str("name", name);
av_assert0(parameter_section_id != -1);
avtext_print_section_header(tfc, "IAMF Param Definition", section_id);
print_str("name", name);
print_int("nb_subblocks", param->nb_subblocks);
print_int("type", param->type);
print_int("parameter_id", param->parameter_id);
@@ -2214,7 +2082,7 @@ static void print_iamf_param_definition(AVTextFormatContext *tfc, const char *na
print_int("constant_subblock_duration", param->constant_subblock_duration);
if (param->nb_subblocks > 0)
avtext_print_section_header(tfc, NULL, subsection_id);
for (unsigned i = 0; i < param->nb_subblocks; i++) {
for (int i = 0; i < param->nb_subblocks; i++) {
const void *subblock = av_iamf_param_definition_get_subblock(param, i);
switch(param->type) {
case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: {
@@ -2248,9 +2116,7 @@ static void print_iamf_param_definition(AVTextFormatContext *tfc, const char *na
}
if (param->nb_subblocks > 0)
avtext_print_section_footer(tfc); // subsection_id
if (section_id != SECTION_ID_FRAME_SIDE_DATA)
avtext_print_section_footer(tfc); // section_id
avtext_print_section_footer(tfc); // section_id
}
static void print_iamf_audio_element_params(AVTextFormatContext *tfc, const AVStreamGroup *stg,
@@ -2265,7 +2131,7 @@ static void print_iamf_audio_element_params(AVTextFormatContext *tfc, const AVSt
print_int("audio_element_type", audio_element->audio_element_type);
print_int("default_w", audio_element->default_w);
avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_SUBCOMPONENTS);
for (unsigned i = 0; i < audio_element->nb_layers; i++) {
for (int i = 0; i < audio_element->nb_layers; i++) {
const AVIAMFLayer *layer = audio_element->layers[i];
char val_str[128];
avtext_print_section_header(tfc, "IAMF Audio Layer", SECTION_ID_STREAM_GROUP_SUBCOMPONENT);
@@ -2301,7 +2167,7 @@ static void print_iamf_submix_params(AVTextFormatContext *tfc, const AVIAMFSubmi
print_int("nb_layouts", submix->nb_layouts);
print_q("default_mix_gain", submix->default_mix_gain, '/');
avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_PIECES);
for (unsigned i = 0; i < submix->nb_elements; i++) {
for (int i = 0; i < submix->nb_elements; i++) {
const AVIAMFSubmixElement *element = submix->elements[i];
avtext_print_section_header(tfc, "IAMF Submix Element", SECTION_ID_STREAM_GROUP_PIECE);
print_int("stream_id", element->audio_element_id);
@@ -2324,7 +2190,7 @@ static void print_iamf_submix_params(AVTextFormatContext *tfc, const AVIAMFSubmi
if (submix->output_mix_config)
print_iamf_param_definition(tfc, "output_mix_config", submix->output_mix_config,
SECTION_ID_STREAM_GROUP_PIECE);
for (unsigned i = 0; i < submix->nb_layouts; i++) {
for (int i = 0; i < submix->nb_layouts; i++) {
const AVIAMFSubmixLayout *layout = submix->layouts[i];
char val_str[128];
avtext_print_section_header(tfc, "IAMF Submix Layout", SECTION_ID_STREAM_GROUP_PIECE);
@@ -2354,7 +2220,7 @@ static void print_iamf_mix_presentation_params(AVTextFormatContext *tfc, const A
print_str(annotation->key, annotation->value);
avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBCOMPONENT
}
for (unsigned i = 0; i < mix_presentation->nb_submixes; i++)
for (int i = 0; i < mix_presentation->nb_submixes; i++)
print_iamf_submix_params(tfc, mix_presentation->submixes[i]);
avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_SUBCOMPONENTS
avtext_print_section_footer(tfc); // SECTION_ID_STREAM_GROUP_COMPONENT
@@ -2376,7 +2242,7 @@ static int show_stream_group(AVTextFormatContext *tfc, InputFile *ifile, AVStrea
{
AVFormatContext *fmt_ctx = ifile->fmt_ctx;
AVBPrint pbuf;
int ret = 0;
int i, ret = 0;
av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP);
@@ -2401,7 +2267,7 @@ static int show_stream_group(AVTextFormatContext *tfc, InputFile *ifile, AVStrea
goto end;
avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUP_STREAMS);
for (unsigned i = 0; i < stg->nb_streams; i++) {
for (i = 0; i < stg->nb_streams; i++) {
if (selected_streams[stg->streams[i]->index]) {
ret = show_stream(tfc, fmt_ctx, stg->streams[i]->index, &ifile->streams[stg->streams[i]->index], IN_STREAM_GROUP);
if (ret < 0)
@@ -2419,10 +2285,10 @@ end:
static int show_stream_groups(AVTextFormatContext *tfc, InputFile *ifile)
{
AVFormatContext *fmt_ctx = ifile->fmt_ctx;
int ret = 0;
int i, ret = 0;
avtext_print_section_header(tfc, NULL, SECTION_ID_STREAM_GROUPS);
for (unsigned i = 0; i < fmt_ctx->nb_stream_groups; i++) {
for (i = 0; i < fmt_ctx->nb_stream_groups; i++) {
AVStreamGroup *stg = fmt_ctx->stream_groups[i];
ret = show_stream_group(tfc, ifile, stg);
@@ -2436,10 +2302,10 @@ static int show_stream_groups(AVTextFormatContext *tfc, InputFile *ifile)
static int show_chapters(AVTextFormatContext *tfc, InputFile *ifile)
{
AVFormatContext *fmt_ctx = ifile->fmt_ctx;
int ret = 0;
int i, ret = 0;
avtext_print_section_header(tfc, NULL, SECTION_ID_CHAPTERS);
for (unsigned i = 0; i < fmt_ctx->nb_chapters; i++) {
for (i = 0; i < fmt_ctx->nb_chapters; i++) {
AVChapter *chapter = fmt_ctx->chapters[i];
avtext_print_section_header(tfc, NULL, SECTION_ID_CHAPTER);
@@ -2476,7 +2342,7 @@ static int show_format(AVTextFormatContext *tfc, InputFile *ifile)
}
print_time("start_time", fmt_ctx->start_time, &AV_TIME_BASE_Q);
print_time("duration", fmt_ctx->duration, &AV_TIME_BASE_Q);
if (size >= 0) print_int_fmt("size", size, AV_TEXTFORMAT_VALUE_FMT_BYTE, unit_byte_str);
if (size >= 0) print_val ("size", size, unit_byte_str);
else print_str_opt("size", "N/A");
if (fmt_ctx->bit_rate > 0) print_val ("bit_rate", fmt_ctx->bit_rate, unit_bit_per_second_str);
else print_str_opt("bit_rate", "N/A");
@@ -2559,7 +2425,7 @@ static const AVCodec *get_decoder_for_stream(AVFormatContext *fmt_ctx, AVStream
static int open_input_file(InputFile *ifile, const char *filename,
const char *print_filename)
{
int err;
int err, i;
AVFormatContext *fmt_ctx = NULL;
const AVDictionaryEntry *t = NULL;
int scan_all_pmts_set = 0;
@@ -2600,7 +2466,7 @@ static int open_input_file(InputFile *ifile, const char *filename,
err = avformat_find_stream_info(fmt_ctx, opts);
for (int i = 0; i < orig_nb_streams; i++)
for (i = 0; i < orig_nb_streams; i++)
av_dict_free(&opts[i]);
av_freep(&opts);
@@ -2618,7 +2484,7 @@ static int open_input_file(InputFile *ifile, const char *filename,
ifile->nb_streams = fmt_ctx->nb_streams;
/* bind a decoder to each input stream */
for (unsigned i = 0; i < fmt_ctx->nb_streams; i++) {
for (i = 0; i < fmt_ctx->nb_streams; i++) {
InputStream *ist = &ifile->streams[i];
AVStream *stream = fmt_ctx->streams[i];
const AVCodec *codec;
@@ -2676,9 +2542,10 @@ static int open_input_file(InputFile *ifile, const char *filename,
static void close_input_file(InputFile *ifile)
{
int i;
/* close decoder for each stream */
for (int i = 0; i < ifile->nb_streams; i++)
for (i = 0; i < ifile->nb_streams; i++)
avcodec_free_context(&ifile->streams[i].dec_ctx);
av_freep(&ifile->streams);
@@ -2691,7 +2558,7 @@ static int probe_file(AVTextFormatContext *tfc, const char *filename,
const char *print_filename)
{
InputFile ifile = { 0 };
int ret;
int ret, i;
int section_id;
do_analyze_frames = do_analyze_frames && do_show_streams;
@@ -2711,7 +2578,7 @@ static int probe_file(AVTextFormatContext *tfc, const char *filename,
REALLOCZ_ARRAY_STREAM(streams_with_closed_captions,0,ifile.fmt_ctx->nb_streams);
REALLOCZ_ARRAY_STREAM(streams_with_film_grain,0,ifile.fmt_ctx->nb_streams);
for (unsigned i = 0; i < ifile.fmt_ctx->nb_streams; i++) {
for (i = 0; i < ifile.fmt_ctx->nb_streams; i++) {
if (stream_specifier) {
ret = avformat_match_stream_specifier(ifile.fmt_ctx,
ifile.fmt_ctx->streams[i],
@@ -2929,9 +2796,9 @@ static inline void mark_section_show_entries(SectionID section_id,
static int match_section(const char *section_name,
int show_all_entries, AVDictionary *entries)
{
int ret = 0;
int i, ret = 0;
for (unsigned i = 0; i < FF_ARRAY_ELEMS(sections); i++) {
for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) {
const struct AVTextFormatSection *section = &sections[i];
if (!strcmp(section_name, section->name) ||
(section->unique_name && !strcmp(section_name, section->unique_name))) {
+1 -2
View File
@@ -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"
@@ -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); \
+9 -20
View File
@@ -68,11 +68,6 @@ enum show_muxdemuxers {
SHOW_MUXERS,
};
enum show_codec {
SHOW_DECODER,
SHOW_ENCODER,
};
static FILE *report_file;
static int report_file_level = AV_LOG_DEBUG;
@@ -326,12 +321,6 @@ static void print_codec(const AVCodec *c)
printf("hardware ");
if (c->capabilities & AV_CODEC_CAP_HYBRID)
printf("hybrid ");
if (c->capabilities & AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE)
printf("reorderedopaque ");
if (c->capabilities & AV_CODEC_CAP_ENCODER_FLUSH)
printf("flush ");
if (c->capabilities & AV_CODEC_CAP_ENCODER_RECON_FRAME)
printf("reconframe ");
if (!c->capabilities)
printf("none");
printf("\n");
@@ -602,9 +591,9 @@ int show_help(void *optctx, const char *opt, const char *arg)
if (!*topic) {
show_help_default(topic, par);
} else if (!strcmp(topic, "decoder")) {
show_help_codec(par, SHOW_DECODER);
show_help_codec(par, 0);
} else if (!strcmp(topic, "encoder")) {
show_help_codec(par, SHOW_ENCODER);
show_help_codec(par, 1);
} else if (!strcmp(topic, "demuxer")) {
show_help_demuxer(par);
} else if (!strcmp(topic, "muxer")) {
@@ -719,16 +708,16 @@ int show_codecs(void *optctx, const char *opt, const char *arg)
/* print decoders/encoders when there's more than one or their
* names are different from codec name */
while ((codec = next_codec_for_id(desc->id, &iter, SHOW_DECODER))) {
while ((codec = next_codec_for_id(desc->id, &iter, 0))) {
if (strcmp(codec->name, desc->name)) {
print_codecs_for_id(desc->id, SHOW_DECODER);
print_codecs_for_id(desc->id, 0);
break;
}
}
iter = NULL;
while ((codec = next_codec_for_id(desc->id, &iter, SHOW_ENCODER))) {
while ((codec = next_codec_for_id(desc->id, &iter, 1))) {
if (strcmp(codec->name, desc->name)) {
print_codecs_for_id(desc->id, SHOW_ENCODER);
print_codecs_for_id(desc->id, 1);
break;
}
}
@@ -785,12 +774,12 @@ static int print_codecs(int encoder)
int show_decoders(void *optctx, const char *opt, const char *arg)
{
return print_codecs(SHOW_DECODER);
return print_codecs(0);
}
int show_encoders(void *optctx, const char *opt, const char *arg)
{
return print_codecs(SHOW_ENCODER);
return print_codecs(1);
}
int show_bsfs(void *optctx, const char *opt, const char *arg)
@@ -887,7 +876,7 @@ static int show_formats_devices(void *optctx, const char *opt, const char *arg,
const char *name = NULL;
const char *long_name = NULL;
if (muxdemuxers != SHOW_DEMUXERS) {
if (muxdemuxers !=SHOW_DEMUXERS) {
ofmt_opaque = NULL;
while ((ofmt = av_muxer_iterate(&ofmt_opaque))) {
is_dev = is_device(ofmt->priv_class);
+17 -38
View File
@@ -18,21 +18,19 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <inttypes.h>
#include <limits.h>
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "libavutil/mem.h"
#include "libavutil/avassert.h"
#include "libavutil/avutil.h"
#include "libavutil/base64.h"
#include "libavutil/bprint.h"
#include "libavutil/common.h"
#include "libavutil/error.h"
#include "libavutil/hash.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/macros.h"
#include "libavutil/opt.h"
#include "avtextformat.h"
@@ -240,7 +238,12 @@ fail:
return ret;
}
/* Temporary definitions during refactoring */
static const char unit_second_str[] = "s";
static const char unit_hertz_str[] = "Hz";
static const char unit_byte_str[] = "byte";
static const char unit_bit_per_second_str[] = "bit/s";
void avtext_print_section_header(AVTextFormatContext *tctx, const void *data, int section_id)
{
@@ -364,30 +367,24 @@ struct unit_value {
int64_t i;
} val;
AVTextFormatValueFormat fmt;
const char *unit;
};
static const char float_fmt_full[] = "%f";
static const char float_fmt_singledigit[] = "%.1f";
static char *value_string(const AVTextFormatContext *tctx, char *buf, int buf_size, struct unit_value uv)
{
double vald;
int64_t vali = 0;
const char *float_fmt = 0;
int show_float = 0;
if (uv.fmt == AV_TEXTFORMAT_VALUE_FMT_DECIBEL) {
vald = 20 * log10(uv.val.d);
float_fmt = float_fmt_singledigit;
} else if (uv.fmt >= AV_TEXTFORMAT_VALUE_FMT_DOUBLE) {
if (uv.unit == unit_second_str) {
vald = uv.val.d;
float_fmt = float_fmt_full;
show_float = 1;
} else {
vald = (double)uv.val.i;
vali = uv.val.i;
}
if (uv.fmt == AV_TEXTFORMAT_VALUE_FMT_SECOND && tctx->opts.use_value_sexagesimal_format) {
if (uv.unit == unit_second_str && tctx->opts.use_value_sexagesimal_format) {
double secs;
int hours, mins;
secs = vald;
@@ -402,7 +399,7 @@ static char *value_string(const AVTextFormatContext *tctx, char *buf, int buf_si
if (tctx->opts.use_value_prefix && vald > 1) {
int64_t index;
if (uv.fmt == AV_TEXTFORMAT_VALUE_FMT_BYTE && tctx->opts.use_byte_value_binary_prefix) {
if (uv.unit == unit_byte_str && tctx->opts.use_byte_value_binary_prefix) {
index = (int64_t)(log2(vald) / 10);
index = av_clip64(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1);
vald /= si_prefixes[index].bin_val;
@@ -416,46 +413,29 @@ static char *value_string(const AVTextFormatContext *tctx, char *buf, int buf_si
vali = (int64_t)vald;
}
if (float_fmt || (tctx->opts.use_value_prefix && vald != (int64_t)vald))
snprintf(buf, buf_size, float_fmt ? float_fmt : "%f", vald);
if (show_float || (tctx->opts.use_value_prefix && vald != (int64_t)vald))
snprintf(buf, buf_size, "%f", vald);
else
snprintf(buf, buf_size, "%"PRId64, vali);
av_strlcatf(buf, buf_size, "%s%s%s", *prefix_string || tctx->opts.show_value_unit && uv.unit && *uv.unit ? " " : "",
prefix_string, tctx->opts.show_value_unit && uv.unit ? uv.unit : "");
av_strlcatf(buf, buf_size, "%s%s%s", *prefix_string || tctx->opts.show_value_unit ? " " : "",
prefix_string, tctx->opts.show_value_unit ? uv.unit : "");
}
return buf;
}
void avtext_print_unit_integer(AVTextFormatContext *tctx, const char *key, int64_t val, AVTextFormatValueFormat fmt, const char *unit)
void avtext_print_unit_integer(AVTextFormatContext *tctx, const char *key, int64_t val, const char *unit)
{
char val_str[128];
struct unit_value uv;
av_assert0(fmt < AV_TEXTFORMAT_VALUE_FMT_DOUBLE);
uv.val.i = val;
uv.fmt = fmt;
uv.unit = unit;
avtext_print_string(tctx, key, value_string(tctx, val_str, sizeof(val_str), uv), 0);
}
void avtext_print_unit_double(AVTextFormatContext *tctx, const char *key, double val, AVTextFormatValueFormat fmt, const char *unit)
{
char val_str[128];
struct unit_value uv;
av_assert0(fmt >= AV_TEXTFORMAT_VALUE_FMT_DOUBLE);
uv.val.d = val;
uv.fmt = fmt;
uv.unit = unit;
avtext_print_string(tctx, key, value_string(tctx, val_str, sizeof(val_str), uv), 0);
}
int avtext_print_string(AVTextFormatContext *tctx, const char *key, const char *val, int flags)
{
const AVTextFormatSection *section;
@@ -515,7 +495,6 @@ void avtext_print_time(AVTextFormatContext *tctx, const char *key,
double d = av_q2d(*time_base) * ts;
struct unit_value uv;
uv.val.d = d;
uv.fmt = AV_TEXTFORMAT_VALUE_FMT_SECOND;
uv.unit = unit_second_str;
value_string(tctx, buf, sizeof(buf), uv);
avtext_print_string(tctx, key, buf, 0);
+1 -11
View File
@@ -161,14 +161,6 @@ struct AVTextFormatContext {
unsigned int string_validation_utf8_flags;
};
typedef enum {
AV_TEXTFORMAT_VALUE_FMT_INT,
AV_TEXTFORMAT_VALUE_FMT_BYTE,
AV_TEXTFORMAT_VALUE_FMT_DOUBLE = 0x100,
AV_TEXTFORMAT_VALUE_FMT_SECOND,
AV_TEXTFORMAT_VALUE_FMT_DECIBEL,
} AVTextFormatValueFormat;
#define AV_TEXTFORMAT_PRINT_STRING_OPTIONAL 1
#define AV_TEXTFORMAT_PRINT_STRING_VALIDATE 2
@@ -186,9 +178,7 @@ void avtext_print_integer(AVTextFormatContext *tctx, const char *key, int64_t va
int avtext_print_string(AVTextFormatContext *tctx, const char *key, const char *val, int flags);
void avtext_print_unit_integer(AVTextFormatContext *tctx, const char *key, int64_t val, AVTextFormatValueFormat fmt, const char *unit);
void avtext_print_unit_double(AVTextFormatContext *tctx, const char *key, double val, AVTextFormatValueFormat fmt, const char *unit);
void avtext_print_unit_integer(AVTextFormatContext *tctx, const char *key, int64_t val, const char *unit);
void avtext_print_rational(AVTextFormatContext *tctx, const char *key, AVRational q, char sep);
+2 -2
View File
@@ -18,13 +18,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <inttypes.h>
#include <limits.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "avtextformat.h"
#include "libavutil/avutil.h"
#include "libavutil/bprint.h"
#include "libavutil/error.h"
#include "libavutil/opt.h"
+1 -2
View File
@@ -18,14 +18,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <inttypes.h>
#include <limits.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "avtextformat.h"
#include "libavutil/avutil.h"
#include "libavutil/bprint.h"
#include "libavutil/opt.h"
#include "tf_internal.h"
+2 -1
View File
@@ -18,9 +18,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <inttypes.h>
#include <limits.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "avtextformat.h"
+4 -3
View File
@@ -18,13 +18,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <inttypes.h>
#include <limits.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "avtextformat.h"
#include "libavutil/attributes.h"
#include "libavutil/bprint.h"
#include "libavutil/opt.h"
#include "tf_internal.h"
@@ -73,7 +74,7 @@ static char *ini_escape_str(AVBPrint *dst, const char *src)
case '=':
case ':':
av_bprint_chars(dst, '\\', 1);
av_fallthrough;
/* fallthrough */
default:
if ((unsigned char)c < 32)
av_bprintf(dst, "\\x00%02x", (unsigned char)c);
+2 -1
View File
@@ -18,9 +18,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <inttypes.h>
#include <limits.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "avtextformat.h"
+2 -1
View File
@@ -18,9 +18,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <inttypes.h>
#include <limits.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "avtextformat.h"
+2 -2
View File
@@ -18,8 +18,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <inttypes.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "avtextformat.h"
#include "libavutil/bprint.h"
+2 -2
View File
@@ -194,7 +194,7 @@ static int receive_locked(ThreadQueue *tq, int *stream_idx,
return nb_finished == tq->nb_streams ? AVERROR_EOF : AVERROR(EAGAIN);
}
int tq_receive(ThreadQueue *tq, int *stream_idx, void *data, int flags)
int tq_receive(ThreadQueue *tq, int *stream_idx, void *data)
{
int ret;
@@ -211,7 +211,7 @@ int tq_receive(ThreadQueue *tq, int *stream_idx, void *data, int flags)
if (can_read != av_container_fifo_can_read(tq->fifo))
pthread_cond_broadcast(&tq->cond);
if (ret == AVERROR(EAGAIN) && !(flags & THREAD_QUEUE_FLAG_NO_BLOCK)) {
if (ret == AVERROR(EAGAIN)) {
pthread_cond_wait(&tq->cond, &tq->lock);
continue;
}
+1 -10
View File
@@ -26,12 +26,6 @@ enum ThreadQueueType {
THREAD_QUEUE_PACKETS,
};
enum ThreadQueueFlags {
/* When set, tq_receive() will return AVERROR(EAGAIN) instead of blocking
* when the queue is empty or choked. */
THREAD_QUEUE_FLAG_NO_BLOCK = (1 << 0),
};
typedef struct ThreadQueue ThreadQueue;
/**
@@ -80,8 +74,6 @@ void tq_choke(ThreadQueue *tq, int choked);
* written here
* @param data the data item will be written here on success using the
* callback provided to tq_alloc()
* @param flags combination of THREAD_QUEUE_FLAG_*
*
* @return
* - 0 a data item was successfully read; *stream_idx contains a non-negative
* stream index
@@ -89,8 +81,7 @@ void tq_choke(ThreadQueue *tq, int choked);
* side has marked the given stream as finished. This will happen at most once
* for each stream. When *stream_idx is -1, all streams are done.
*/
int tq_receive(ThreadQueue *tq, int *stream_idx, void *data, int flags);
int tq_receive(ThreadQueue *tq, int *stream_idx, void *data);
/**
* Mark the given stream finished from the receiving side.
*/
+15 -14
View File
@@ -115,9 +115,10 @@ OBJS-$(CONFIG_H264PARSE) += h264_parse.o h264_ps.o h264data.o \
h2645data.o h2645_parse.o h2645_vui.o
OBJS-$(CONFIG_H264PRED) += h264pred.o
OBJS-$(CONFIG_H264QPEL) += h264qpel.o
OBJS-$(CONFIG_H264_SEI) += h264_sei.o h2645_sei.o
OBJS-$(CONFIG_H264_SEI) += h264_sei.o h2645_sei.o aom_film_grain.o
OBJS-$(CONFIG_HEVCPARSE) += h2645data.o h2645_parse.o h2645_vui.o
OBJS-$(CONFIG_HEVC_SEI) += h2645_sei.o
OBJS-$(CONFIG_HEVC_SEI) += h2645_sei.o aom_film_grain.o \
dynamic_hdr_vivid.o
OBJS-$(CONFIG_HPELDSP) += hpeldsp.o
OBJS-$(CONFIG_HUFFMAN) += huffman.o
OBJS-$(CONFIG_HUFFYUVDSP) += huffyuvdsp.o
@@ -125,12 +126,11 @@ OBJS-$(CONFIG_HUFFYUVENCDSP) += huffyuvencdsp.o
OBJS-$(CONFIG_IDCTDSP) += idctdsp.o simple_idct.o jrevdct.o
OBJS-$(CONFIG_INFLATE_WRAPPER) += zlib_wrapper.o
OBJS-$(CONFIG_INTRAX8) += intrax8.o intrax8dsp.o msmpeg4_vc1_data.o
OBJS-$(CONFIG_ITUT_T35) += itut35.o aom_film_grain.o dynamic_hdr_vivid.o
OBJS-$(CONFIG_IVIDSP) += ivi_dsp.o
OBJS-$(CONFIG_JNI) += ffjni.o jni.o
OBJS-$(CONFIG_JPEGTABLES) += jpegtables.o
OBJS-$(CONFIG_LCMS2) += fflcms2.o
OBJS-$(CONFIG_LIBLCEVC_DEC) += lcevcdec.o lcevctab.o
OBJS-$(CONFIG_LIBLCEVC_DEC) += lcevcdec.o
OBJS-$(CONFIG_LLAUDDSP) += lossless_audiodsp.o
OBJS-$(CONFIG_LLVIDDSP) += lossless_videodsp.o
OBJS-$(CONFIG_LLVIDENCDSP) += lossless_videoencdsp.o
@@ -203,7 +203,7 @@ OBJS-$(CONFIG_AAC_FIXED_DECODER) += aactab.o \
sbrdsp_fixed.o aacpsdsp_fixed.o cbrt_data_fixed.o \
$(if $(!CONFIG_HARDCODED_TABLES), cbrt_tablegen_common.o)
OBJS-$(CONFIG_AAC_ENCODER) += aacenc.o aaccoder.o aacenctab.o \
aacpsy.o aactab.o aacencdsp.o \
aacpsy.o aactab.o \
aacenc_is.o \
aacenc_tns.o \
psymodel.o kbdwin.o \
@@ -252,7 +252,6 @@ OBJS-$(CONFIG_APTX_HD_ENCODER) += aptxenc.o aptx.o
OBJS-$(CONFIG_APNG_DECODER) += png.o pngdec.o pngdsp.o
OBJS-$(CONFIG_APNG_ENCODER) += png.o pngenc.o
OBJS-$(CONFIG_APV_DECODER) += apv_decode.o apv_entropy.o apv_dsp.o
OBJS-$(CONFIG_APV_VULKAN_ENCODER) += apv_encode_vulkan.o
OBJS-$(CONFIG_ARBC_DECODER) += arbc.o
OBJS-$(CONFIG_ARGO_DECODER) += argo.o
OBJS-$(CONFIG_SSA_DECODER) += assdec.o ass.o
@@ -443,6 +442,7 @@ OBJS-$(CONFIG_H264_MMAL_DECODER) += mmaldec.o
OBJS-$(CONFIG_H264_NVENC_ENCODER) += nvenc_h264.o nvenc.o
OBJS-$(CONFIG_H264_OH_DECODER) += ohcodec.o ohdec.o
OBJS-$(CONFIG_H264_OH_ENCODER) += ohcodec.o ohenc.o
OBJS-$(CONFIG_H264_OMX_ENCODER) += omx.o
OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec.o
OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o
OBJS-$(CONFIG_H264_RKMPP_DECODER) += rkmppdec.o
@@ -461,7 +461,7 @@ OBJS-$(CONFIG_HCA_DECODER) += hcadec.o
OBJS-$(CONFIG_HCOM_DECODER) += hcom.o
OBJS-$(CONFIG_HDR_DECODER) += hdrdec.o
OBJS-$(CONFIG_HDR_ENCODER) += hdrenc.o
OBJS-$(CONFIG_HEVC_DECODER) += h274.o
OBJS-$(CONFIG_HEVC_DECODER) += aom_film_grain.o h274.o
OBJS-$(CONFIG_HEVC_AMF_ENCODER) += amfenc_hevc.o
OBJS-$(CONFIG_HEVC_AMF_DECODER) += amfdec.o
OBJS-$(CONFIG_HEVC_CUVID_DECODER) += cuviddec.o
@@ -587,6 +587,7 @@ OBJS-$(CONFIG_MPEG4_ENCODER) += mpeg4videoenc.o
OBJS-$(CONFIG_MPEG4_CUVID_DECODER) += cuviddec.o
OBJS-$(CONFIG_MPEG4_MEDIACODEC_DECODER) += mediacodecdec.o
OBJS-$(CONFIG_MPEG4_MEDIACODEC_ENCODER) += mediacodecenc.o
OBJS-$(CONFIG_MPEG4_OMX_ENCODER) += omx.o
OBJS-$(CONFIG_MPEG4_V4L2M2M_DECODER) += v4l2_m2m_dec.o
OBJS-$(CONFIG_MPEG4_V4L2M2M_ENCODER) += v4l2_m2m_enc.o
OBJS-$(CONFIG_MPL2_DECODER) += mpl2dec.o ass.o
@@ -625,7 +626,6 @@ OBJS-$(CONFIG_PBM_ENCODER) += pnmenc.o
OBJS-$(CONFIG_PCX_DECODER) += pcx.o
OBJS-$(CONFIG_PCX_ENCODER) += pcxenc.o
OBJS-$(CONFIG_PDV_DECODER) += pdvdec.o
OBJS-$(CONFIG_PDV_ENCODER) += pdvenc.o
OBJS-$(CONFIG_PFM_DECODER) += pnmdec.o pnm.o
OBJS-$(CONFIG_PFM_ENCODER) += pnmenc.o
OBJS-$(CONFIG_PGM_DECODER) += pnmdec.o pnm.o
@@ -723,6 +723,9 @@ OBJS-$(CONFIG_SNOW_ENCODER) += snowenc.o snow.o snow_dwt.o
h263data.o ituh263enc.o \
motion_est.o ratecontrol.o
OBJS-$(CONFIG_SOL_DPCM_DECODER) += dpcm.o
OBJS-$(CONFIG_SONIC_DECODER) += sonic.o
OBJS-$(CONFIG_SONIC_ENCODER) += sonic.o
OBJS-$(CONFIG_SONIC_LS_ENCODER) += sonic.o
OBJS-$(CONFIG_SPEEDHQ_DECODER) += speedhqdec.o speedhq.o mpeg12.o \
mpeg12data.o
OBJS-$(CONFIG_SPEEDHQ_ENCODER) += speedhq.o mpeg12data.o mpeg12enc.o speedhqenc.o
@@ -833,7 +836,7 @@ OBJS-$(CONFIG_VP9_V4L2M2M_DECODER) += v4l2_m2m_dec.o
OBJS-$(CONFIG_VQA_DECODER) += vqavideo.o
OBJS-$(CONFIG_VQC_DECODER) += vqcdec.o
OBJS-$(CONFIG_VVC_DECODER) += executor.o h2645data.o
OBJS-$(CONFIG_VVC_SEI) += h2645_sei.o h274.o
OBJS-$(CONFIG_VVC_SEI) += h2645_sei.o aom_film_grain.o h274.o
OBJS-$(CONFIG_WADY_DPCM_DECODER) += dpcm.o
OBJS-$(CONFIG_WAVARC_DECODER) += wavarc.o
OBJS-$(CONFIG_WAVPACK_DECODER) += wavpack.o wavpackdata.o dsd.o
@@ -842,7 +845,6 @@ OBJS-$(CONFIG_WBMP_DECODER) += wbmpdec.o
OBJS-$(CONFIG_WBMP_ENCODER) += wbmpenc.o
OBJS-$(CONFIG_WCMV_DECODER) += wcmv.o
OBJS-$(CONFIG_WEBP_DECODER) += webp.o
OBJS-$(CONFIG_WEBP_ANIM_DECODER) += webp.o
OBJS-$(CONFIG_WEBVTT_DECODER) += webvttdec.o ass.o
OBJS-$(CONFIG_WEBVTT_ENCODER) += webvttenc.o ass_split.o
OBJS-$(CONFIG_WMALOSSLESS_DECODER) += wmalosslessdec.o wma_common.o
@@ -1044,7 +1046,6 @@ OBJS-$(CONFIG_VIDEOTOOLBOX) += videotoolbox.o
OBJS-$(CONFIG_VDPAU) += vdpau.o
OBJS-$(CONFIG_VULKAN) += vulkan.o vulkan_video.o
OBJS-$(CONFIG_APV_VULKAN_HWACCEL) += vulkan_decode.o vulkan_apv.o
OBJS-$(CONFIG_AV1_D3D11VA_HWACCEL) += dxva2_av1.o
OBJS-$(CONFIG_AV1_DXVA2_HWACCEL) += dxva2_av1.o
OBJS-$(CONFIG_AV1_D3D12VA_HWACCEL) += dxva2_av1.o d3d12va_av1.o
@@ -1126,7 +1127,7 @@ OBJS-$(CONFIG_FITS_DEMUXER) += fits.o
OBJS-$(CONFIG_TAK_DEMUXER) += tak.o
# libavformat dependencies for static builds
STLIBOBJS-$(CONFIG_AVFORMAT) += h2645_parse.o lcevctab.o to_upper4.o
STLIBOBJS-$(CONFIG_AVFORMAT) += to_upper4.o
STLIBOBJS-$(CONFIG_ISO_MEDIA) += mpegaudiotabs.o
STLIBOBJS-$(CONFIG_FLV_MUXER) += mpeg4audio_sample_rates.o
STLIBOBJS-$(CONFIG_HLS_DEMUXER) += ac3_channel_layout_tab.o
@@ -1170,6 +1171,7 @@ OBJS-$(CONFIG_LIBAOM_AV1_DECODER) += libaomdec.o libaom.o
OBJS-$(CONFIG_LIBAOM_AV1_ENCODER) += libaomenc.o libaom.o
OBJS-$(CONFIG_LIBARIBB24_DECODER) += libaribb24.o ass.o
OBJS-$(CONFIG_LIBARIBCAPTION_DECODER) += libaribcaption.o ass.o
OBJS-$(CONFIG_LIBCELT_DECODER) += libcelt_dec.o
OBJS-$(CONFIG_LIBCODEC2_DECODER) += libcodec2.o
OBJS-$(CONFIG_LIBCODEC2_ENCODER) += libcodec2.o
OBJS-$(CONFIG_LIBDAV1D_DECODER) += libdav1d.o av1_parse.o
@@ -1328,7 +1330,6 @@ SKIPHEADERS += %_tablegen.h \
%_tables.h \
tableprint.h \
tableprint_vlc.h \
aaccoder_nmr.h \
aaccoder_twoloop.h \
aaccoder_trellis.h \
aacenc_quantization.h \
@@ -1366,7 +1367,6 @@ TESTPROGS = avcodec \
bitstream_be \
bitstream_le \
codec_desc \
encinfo \
htmlsubtitles \
jpeg2000dwt \
mathops \
@@ -1379,6 +1379,7 @@ TESTPROGS-$(CONFIG_GOLOMB) += golomb
TESTPROGS-$(CONFIG_IDCTDSP) += dct
TESTPROGS-$(CONFIG_DXV_ENCODER) += hashtable
TESTPROGS-$(CONFIG_MJPEG_ENCODER) += mjpegenc_huffman
TESTPROGS-$(HAVE_MMX) += motion
TESTPROGS-$(CONFIG_MPEGVIDEO) += mpeg12framerate
TESTPROGS-$(CONFIG_H264_METADATA_BSF) += h264_levels
TESTPROGS-$(CONFIG_HEVC_METADATA_BSF) += h265_levels
+17 -110
View File
@@ -676,7 +676,6 @@ ChannelElement *ff_aac_get_che(AACDecContext *ac, int type, int elem_id)
ac->tags_mapped++;
return ac->tag_che_map[type][elem_id] = ac->che[type][elem_id];
}
av_fallthrough;
case 13:
if (ac->tags_mapped > 3 && ((type == TYPE_CPE && elem_id < 8) ||
(type == TYPE_SCE && elem_id < 6) ||
@@ -684,20 +683,17 @@ ChannelElement *ff_aac_get_che(AACDecContext *ac, int type, int elem_id)
ac->tags_mapped++;
return ac->tag_che_map[type][elem_id] = ac->che[type][elem_id];
}
av_fallthrough;
case 12:
case 7:
if (ac->tags_mapped == 3 && type == TYPE_CPE) {
ac->tags_mapped++;
return ac->tag_che_map[TYPE_CPE][elem_id] = ac->che[TYPE_CPE][2];
}
av_fallthrough;
case 11:
if (ac->tags_mapped == 3 && type == TYPE_SCE) {
ac->tags_mapped++;
return ac->tag_che_map[TYPE_SCE][elem_id] = ac->che[TYPE_SCE][1];
}
av_fallthrough;
case 6:
/* Some streams incorrectly code 5.1 audio as
* SCE[0] CPE[0] CPE[1] SCE[1]
@@ -715,13 +711,11 @@ ChannelElement *ff_aac_get_che(AACDecContext *ac, int type, int elem_id)
ac->tags_mapped++;
return ac->tag_che_map[type][elem_id] = ac->che[TYPE_LFE][0];
}
av_fallthrough;
case 5:
if (ac->tags_mapped == 2 && type == TYPE_CPE) {
ac->tags_mapped++;
return ac->tag_che_map[TYPE_CPE][elem_id] = ac->che[TYPE_CPE][1];
}
av_fallthrough;
case 4:
/* Some streams incorrectly code 4.0 audio as
* SCE[0] CPE[0] LFE[0]
@@ -745,7 +739,6 @@ ChannelElement *ff_aac_get_che(AACDecContext *ac, int type, int elem_id)
ac->tags_mapped++;
return ac->tag_che_map[TYPE_SCE][elem_id] = ac->che[TYPE_SCE][1];
}
av_fallthrough;
case 3:
case 2:
if (ac->tags_mapped == (ac->oc[1].m4ac.chan_config != 2) &&
@@ -757,13 +750,11 @@ ChannelElement *ff_aac_get_che(AACDecContext *ac, int type, int elem_id)
ac->tags_mapped++;
return ac->tag_che_map[TYPE_SCE][elem_id] = ac->che[TYPE_SCE][1];
}
av_fallthrough;
case 1:
if (!ac->tags_mapped && type == TYPE_SCE) {
ac->tags_mapped++;
return ac->tag_che_map[TYPE_SCE][elem_id] = ac->che[TYPE_SCE][0];
}
av_fallthrough;
default:
return NULL;
}
@@ -831,8 +822,8 @@ static int decode_pce(AVCodecContext *avctx, MPEG4AudioConfig *m4ac,
sampling_index = get_bits(gb, 4);
if (m4ac->sampling_index != sampling_index)
av_log(avctx, AV_LOG_WARNING,
"Sample rate index (%d) in program config element does not "
"match the sample rate index (%d) configured by the container.\n", sampling_index, m4ac->sampling_index);
"Sample rate index in program config element does not "
"match the sample rate index configured by the container.\n");
num_front = get_bits(gb, 4);
num_side = get_bits(gb, 4);
@@ -875,91 +866,6 @@ static int decode_pce(AVCodecContext *avctx, MPEG4AudioConfig *m4ac,
av_log(avctx, AV_LOG_ERROR, "decode_pce: " overread_err);
return AVERROR_INVALIDDATA;
}
// Height extension
int height_ext = 0;
if (comment_len >= 16 + (num_front * 2 + num_side * 2 + num_back * 2))
height_ext = show_bits(gb, 8) == 0xAC;
if (height_ext) {
uint8_t height_map[4 /* ChannelPosition */][16 /* Channel */]; // 0 == base, 1 == top, 2 == bottom.
uint8_t tag[6 /* ChannelPosition */ ][16 /* Channel */][3];
int i, invalid = 0, height_tags = 0;
skip_bits(gb, 8);
// Read height extension bits to height_map, which define which layer each element belongs to.
// Also make a copy of layout_map that will then be used to rearrange it.
for (i = 0; i < num_front; i++) {
int height = get_bits(gb, 2);
invalid |= height > 2;
height_map [AAC_CHANNEL_FRONT][i] = height;
memcpy(&tag[AAC_CHANNEL_FRONT][i], layout_map + height_tags, sizeof(*layout_map));
height_tags++;
}
for (i = 0; i < num_side; i++) {
int height = get_bits(gb, 2);
invalid |= height > 2;
height_map [AAC_CHANNEL_SIDE][i] = height;
memcpy(&tag[AAC_CHANNEL_SIDE][i], layout_map + height_tags, sizeof(*layout_map));
height_tags++;
}
for (i = 0; i < num_back; i++) {
int height = get_bits(gb, 2);
invalid |= height > 2;
height_map [AAC_CHANNEL_BACK][i] = height;
memcpy(&tag[AAC_CHANNEL_BACK][i], layout_map + height_tags, sizeof(*layout_map));
height_tags++;
}
for (i = 0; i < num_lfe; i++) {
memcpy(&tag[AAC_CHANNEL_LFE][i], layout_map + height_tags, sizeof(*layout_map));
height_tags++;
}
for (i = 0; i < num_cc; i++) {
memcpy(&tag[AAC_CHANNEL_CC][i], layout_map + height_tags, sizeof(*layout_map));
height_tags++;
}
av_assert0(height_tags == tags);
if (!invalid) {
height_tags = 0;
// For each height layer, check that an element belongs to it and copy it back to layout_map.
// We need to take into account LFE and CC elements that may be present.
for (i = 0; i < 3; i++) {
for (int j = 0; j < num_front; j++) {
if (height_map[AAC_CHANNEL_FRONT][j] == i) {
memcpy(layout_map + height_tags, &tag[AAC_CHANNEL_FRONT][j], sizeof(*layout_map));
height_tags++;
}
}
for (int j = 0; j < num_side; j++) {
if (height_map[AAC_CHANNEL_SIDE][j] == i) {
memcpy(layout_map + height_tags, &tag[AAC_CHANNEL_SIDE][j], sizeof(*layout_map));
height_tags++;
}
}
for (int j = 0; j < num_back; j++) {
if (height_map[AAC_CHANNEL_BACK][j] == i) {
memcpy(layout_map + height_tags, &tag[AAC_CHANNEL_BACK][j], sizeof(*layout_map));
height_tags++;
}
}
if (i == 0) { // Base height, copy LFE and CC elements before moving to Top and Bottom
for (int j = 0; j < num_lfe; j++) {
memcpy(layout_map + height_tags, &tag[AAC_CHANNEL_LFE][j], sizeof(*layout_map));
height_tags++;
}
for (int j = 0; j < num_cc; j++) {
memcpy(layout_map + height_tags, &tag[AAC_CHANNEL_CC][j], sizeof(*layout_map));
height_tags++;
}
}
}
av_assert0(height_tags == tags);
}
comment_len -= 8 + (num_front * 2 + num_side * 2 + num_back * 2);
}
skip_bits_long(gb, comment_len);
return tags;
}
@@ -983,6 +889,12 @@ static int decode_ga_specific_config(AACDecContext *ac, AVCodecContext *avctx,
int tags = 0;
m4ac->frame_length_short = get_bits1(gb);
if (m4ac->frame_length_short && m4ac->sbr == 1) {
avpriv_report_missing_feature(avctx, "SBR with 960 frame length");
if (ac) ac->warned_960_sbr = 1;
m4ac->sbr = 0;
m4ac->ps = 0;
}
if (get_bits1(gb)) // dependsOnCoreCoder
skip_bits(gb, 14); // coreCoderDelay
@@ -1334,7 +1246,7 @@ av_cold int ff_aac_decode_init(AVCodecContext *avctx)
ac->oc[1].m4ac.chan_config = i;
if (ac->oc[1].m4ac.chan_config) {
ret = ff_aac_set_default_channel_config(ac, avctx, layout_map,
int ret = ff_aac_set_default_channel_config(ac, avctx, layout_map,
&layout_map_tags,
ac->oc[1].m4ac.chan_config);
if (!ret)
@@ -2034,11 +1946,17 @@ static int decode_extension_payload(AACDecContext *ac, GetBitContext *gb, int cn
switch (type) { // extension type
case EXT_SBR_DATA_CRC:
crc_flag++;
av_fallthrough;
case EXT_SBR_DATA:
if (!che) {
av_log(ac->avctx, AV_LOG_ERROR, "SBR was found before the first channel element.\n");
return res;
} else if (ac->oc[1].m4ac.frame_length_short) {
if (!ac->warned_960_sbr)
avpriv_report_missing_feature(ac->avctx,
"SBR with 960 frame length");
ac->warned_960_sbr = 1;
skip_bits_long(gb, 8 * cnt - 4);
return res;
} else if (!ac->oc[1].m4ac.sbr) {
av_log(ac->avctx, AV_LOG_ERROR, "SBR signaled to be not-present but was found in the bitstream.\n");
skip_bits_long(gb, 8 * cnt - 4);
@@ -2059,8 +1977,7 @@ static int decode_extension_payload(AACDecContext *ac, GetBitContext *gb, int cn
ac->avctx->profile = AV_PROFILE_AAC_HE;
}
ac->proc.sbr_decode_extension(ac, che, gb, crc_flag, cnt, elem_type,
ac->oc[1].m4ac.frame_length_short);
ac->proc.sbr_decode_extension(ac, che, gb, crc_flag, cnt, elem_type);
if (ac->oc[1].m4ac.ps == 1 && !ac->warned_he_aac_mono) {
av_log(ac->avctx, AV_LOG_VERBOSE, "Treating HE-AAC mono as stereo.\n");
@@ -2170,7 +2087,6 @@ static void spectral_to_sample(AACDecContext *ac, int samples)
}
if (ac->oc[1].m4ac.sbr > 0) {
ac->proc.sbr_apply(ac, che, type,
ac->oc[1].m4ac.frame_length_short,
che->ch[0].output,
che->ch[1].output);
}
@@ -2467,12 +2383,6 @@ static int decode_frame_ga(AVCodecContext *avctx, AACDecContext *ac,
ac->oc[1].status = OC_LOCKED;
}
if (samples && avctx->sample_rate <= 0) {
av_log(avctx, AV_LOG_ERROR,
"Cannot output a frame without a valid sample rate\n");
return AVERROR_INVALIDDATA;
}
if (!ac->frame->data[0] && samples) {
av_log(avctx, AV_LOG_ERROR, "no frame data found\n");
return AVERROR_INVALIDDATA;
@@ -2648,9 +2558,6 @@ static const AVOption options[] = {
{ "coded", "order in which the channels are coded in the bitstream",
0, AV_OPT_TYPE_CONST, { .i64 = CHANNEL_ORDER_CODED }, .flags = AACDEC_FLAGS, .unit = "channel_order" },
{ "target_level", "Target output loudness in dBFS for xHE-AAC normalization (0 = disabled)",
OFF(target_level), AV_OPT_TYPE_INT, { .i64 = 0 }, -70, 0, AACDEC_FLAGS },
{NULL},
};
+4 -31
View File
@@ -98,12 +98,6 @@ enum AACUSACLoudnessExt {
UNIDRCLOUDEXT_EQ = 0x1,
};
enum AACUSACDRCExt {
UNIDRCCONFEXT_TERM = 0x0,
UNIDRCCONFEXT_PARAM_DRC = 0x1,
UNIDRCCONFEXT_V1 = 0x2,
};
// Supposed to be equal to AAC_RENAME() in case of USE_FIXED.
#define RENAME_FIXED(name) name ## _fixed
@@ -308,7 +302,6 @@ typedef struct ChannelElement {
typedef struct AACUSACLoudnessInfo {
uint8_t drc_set_id : 6;
uint8_t eq_set_id : 6; /* loudnessInfoV1() only, 0 otherwise */
uint8_t downmix_id : 7;
struct {
uint16_t lvl : 12;
@@ -384,13 +377,6 @@ typedef struct AACUsacElemConfig {
uint32_t pl_data_offset;
uint8_t *pl_buf;
} ext;
struct {
struct {
int lower;
int upper;
} loudness;
} drc;
} AACUsacElemConfig;
typedef struct AACUSACConfig {
@@ -406,13 +392,6 @@ typedef struct AACUSACConfig {
AACUSACLoudnessInfo album_info[64];
uint8_t nb_info;
AACUSACLoudnessInfo info[64];
/**
* Raw bsMethodValue (μ) of the program/anchor-loudness measurement
* selected for normalization at config time. -1 == none found.
* L_LKFS = -57.75 + 0.25 * input_method_val.
*/
int input_method_val;
} loudness;
} AACUSACConfig;
@@ -454,9 +433,9 @@ typedef struct AACDecProc {
int (*sbr_ctx_alloc_init)(AACDecContext *ac, ChannelElement **che, int id_aac);
int (*sbr_decode_extension)(AACDecContext *ac, ChannelElement *che,
GetBitContext *gb, int crc, int cnt, int id_aac, int fl960);
void (*sbr_apply)(AACDecContext *ac, ChannelElement *che, int id_aac, int fl960,
void /* INTFLOAT */ *L, void /* INTFLOAT */ *R);
GetBitContext *gb, int crc, int cnt, int id_aac);
void (*sbr_apply)(AACDecContext *ac, ChannelElement *che,
int id_aac, void /* INTFLOAT */ *L, void /* INTFLOAT */ *R);
void (*sbr_ctx_close)(ChannelElement *che);
} AACDecProc;
@@ -576,15 +555,9 @@ struct AACDecContext {
enum AACOutputChannelOrder output_channel_order;
/**
* Target output loudness in dBFS, used for xHE-AAC loudness normalization
* based on the parsed loudnessInfoSet() metadata. 0 disables normalization.
*/
int target_level;
int warned_loudness_missing;
OutputConfiguration oc[2];
int warned_num_aac_frames;
int warned_960_sbr;
unsigned warned_71_wide;
int warned_gain_control;
int warned_he_aac_mono;
+1 -1
View File
@@ -75,7 +75,7 @@ const uint8_t ff_aac_channel_layout_map[16][16][3] = {
const int16_t ff_aac_channel_map[3][4][6] = {
{
{ AV_CHAN_FRONT_CENTER, AV_CHAN_FRONT_LEFT_OF_CENTER, AV_CHAN_FRONT_RIGHT_OF_CENTER, AV_CHAN_FRONT_LEFT, AV_CHAN_FRONT_RIGHT, AV_CHAN_NONE },
{ AV_CHAN_UNUSED, AV_CHAN_SIDE_LEFT, AV_CHAN_SIDE_RIGHT, AV_CHAN_NONE, AV_CHAN_NONE, AV_CHAN_NONE },
{ AV_CHAN_UNUSED, AV_CHAN_NONE, AV_CHAN_NONE, AV_CHAN_NONE, AV_CHAN_NONE, AV_CHAN_NONE },
{ AV_CHAN_UNUSED, AV_CHAN_SIDE_LEFT, AV_CHAN_SIDE_RIGHT, AV_CHAN_BACK_LEFT, AV_CHAN_BACK_RIGHT, AV_CHAN_BACK_CENTER },
{ AV_CHAN_LOW_FREQUENCY, AV_CHAN_LOW_FREQUENCY_2, AV_CHAN_NONE, AV_CHAN_NONE, AV_CHAN_NONE, AV_CHAN_NONE },
},
+24 -259
View File
@@ -49,7 +49,7 @@ static inline uint32_t get_escaped_value(GetBitContext *gb, int nb1, int nb2, in
return val;
}
/* ISO/IEC 23003-3, Table 74: bsOutputChannelPos */
/* ISO/IEC 23003-3, Table 74 bsOutputChannelPos */
static const enum AVChannel usac_ch_pos_to_av[64] = {
[0] = AV_CHAN_FRONT_LEFT,
[1] = AV_CHAN_FRONT_RIGHT,
@@ -85,23 +85,10 @@ static const enum AVChannel usac_ch_pos_to_av[64] = {
[31] = AV_CHAN_TOP_SURROUND_RIGHT, ///< -110 degrees, Rvs, TpRS
};
/* ISO/IEC 23003-4, Table A.48: bit width of bsMethodValue depends on methodDef. */
static int methodvalue_width(int method_def)
{
switch (method_def) {
case 7: return 5; /* mixing level */
case 8: return 2; /* room type */
default: return 8; /* loudness (0..6, 9) + reserved */
}
}
/* ISO/IEC 23003-4, Table 58/60: loudnessInfo(), loudnessInfoV1().
* The only difference in V1 is the added eqSetId field. */
static int decode_loudness_info(AACDecContext *ac, AACUSACLoudnessInfo *info,
GetBitContext *gb, int v1)
GetBitContext *gb)
{
info->drc_set_id = get_bits(gb, 6);
info->eq_set_id = v1 ? get_bits(gb, 6) : 0;
info->downmix_id = get_bits(gb, 7);
if ((info->sample_peak.present = get_bits1(gb))) /* samplePeakLevelPresent */
@@ -116,8 +103,7 @@ static int decode_loudness_info(AACDecContext *ac, AACUSACLoudnessInfo *info,
info->nb_measurements = get_bits(gb, 4);
for (int i = 0; i < info->nb_measurements; i++) {
info->measurements[i].method_def = get_bits(gb, 4);
info->measurements[i].method_val =
get_bits(gb, methodvalue_width(info->measurements[i].method_def));
info->measurements[i].method_val = get_unary(gb, 0, 8);
info->measurements[i].measurement = get_bits(gb, 4);
info->measurements[i].reliability = get_bits(gb, 2);
}
@@ -125,56 +111,6 @@ static int decode_loudness_info(AACDecContext *ac, AACUSACLoudnessInfo *info,
return 0;
}
/* ISO/IEC 23003-4, Table 61: loudnessInfoSetExtension(), UNIDRCLOUDEXT_EQ */
static int decode_loudness_set_v1(AACDecContext *ac, AACUSACConfig *usac,
GetBitContext *gb)
{
int ret;
int nb_album = get_bits(gb, 6); /* loudnessInfoV1AlbumCount */
int nb_info = get_bits(gb, 6); /* loudnessInfoV1Count */
for (int i = 0; i < nb_album; i++) {
AACUSACLoudnessInfo tmp;
ret = decode_loudness_info(ac, &tmp, gb, 1);
if (ret < 0)
return ret;
if (usac->loudness.nb_album < FF_ARRAY_ELEMS(usac->loudness.album_info))
usac->loudness.album_info[usac->loudness.nb_album++] = tmp;
}
for (int i = 0; i < nb_info; i++) {
AACUSACLoudnessInfo tmp;
ret = decode_loudness_info(ac, &tmp, gb, 1);
if (ret < 0)
return ret;
if (usac->loudness.nb_info < FF_ARRAY_ELEMS(usac->loudness.info))
usac->loudness.info[usac->loudness.nb_info++] = tmp;
}
return 0;
}
/* Pick the bsMethodValue of a program- or anchor-loudness measurement.
* Per ISO/IEC 23003-4 6.1.2.5, downmixId, drcSetId and eqSetId identify the
* signal a loudnessInfo() applies to; only downmixId == 0 (base layout)
* together with drcSetId == 0 and eqSetId == 0 (no DRC/EQ) describes the
* unprocessed signal we output, so measurements for any other
* downmix/DRC/EQ set must not be used. */
static int select_loudness_measurement(const AACUSACConfig *usac)
{
for (int i = 0; i < usac->loudness.nb_info; i++) {
const AACUSACLoudnessInfo *info = &usac->loudness.info[i];
if (info->downmix_id != 0 || info->drc_set_id != 0 || info->eq_set_id != 0)
continue;
for (int j = 0; j < info->nb_measurements; j++) {
int method = info->measurements[j].method_def;
if (method == 1 || method == 2)
return info->measurements[j].method_val;
}
}
return -1;
}
static int decode_loudness_set(AACDecContext *ac, AACUSACConfig *usac,
GetBitContext *gb)
{
@@ -184,13 +120,13 @@ static int decode_loudness_set(AACDecContext *ac, AACUSACConfig *usac,
usac->loudness.nb_info = get_bits(gb, 6); /* loudnessInfoCount */
for (int i = 0; i < usac->loudness.nb_album; i++) {
ret = decode_loudness_info(ac, &usac->loudness.album_info[i], gb, 0);
ret = decode_loudness_info(ac, &usac->loudness.album_info[i], gb);
if (ret < 0)
return ret;
}
for (int i = 0; i < usac->loudness.nb_info; i++) {
ret = decode_loudness_info(ac, &usac->loudness.info[i], gb, 0);
ret = decode_loudness_info(ac, &usac->loudness.info[i], gb);
if (ret < 0)
return ret;
}
@@ -198,25 +134,16 @@ static int decode_loudness_set(AACDecContext *ac, AACUSACConfig *usac,
if (get_bits1(gb)) { /* loudnessInfoSetExtPresent */
enum AACUSACLoudnessExt type;
while ((type = get_bits(gb, 4)) != UNIDRCLOUDEXT_TERM) {
uint8_t size_bits = get_bits(gb, 4) + 4; /* bitSizeLen */
uint32_t bit_size = get_bits_long(gb, size_bits) + 1; /* bitSize */
int start = get_bits_count(gb);
int skip;
uint8_t size_bits = get_bits(gb, 4) + 4;
uint8_t bit_size = get_bits(gb, size_bits) + 1;
switch (type) {
case UNIDRCLOUDEXT_EQ:
ret = decode_loudness_set_v1(ac, usac, gb);
if (ret < 0)
return ret;
break;
avpriv_report_missing_feature(ac->avctx, "loudnessInfoV1");
return AVERROR_PATCHWELCOME;
default:
break;
for (int i = 0; i < bit_size; i++)
skip_bits1(gb);
}
/* The extension size is explicit, so unparsed (or unknown)
* data can be skipped without desynchronizing. */
skip = bit_size - (get_bits_count(gb) - start);
if (skip < 0)
return AVERROR_INVALIDDATA;
skip_bits_long(gb, skip);
}
}
@@ -288,9 +215,6 @@ static int decode_usac_element_pair(AACDecContext *ac,
if (e->stereo_config_index) {
e->mps.freq_res = get_bits(gb, 3); /* bsFreqRes */
if (!e->mps.freq_res)
return AVERROR_INVALIDDATA; /* value 0 is reserved */
int numBands = ((int[]){0,28,20,14,10,7,5,4})[e->mps.freq_res]; // ISO/IEC 23003-1:2007, 5.2, Table 39
e->mps.fixed_gain = get_bits(gb, 3); /* bsFixedGainDMX */
@@ -300,7 +224,7 @@ static int decode_usac_element_pair(AACDecContext *ac,
e->mps.phase_coding = get_bits1(gb); /* bsPhaseCoding */
e->mps.otts_bands_phase_present = get_bits1(gb);
int otts_bands_phase = ((int[]){0,10,10,7,5,3,2,2})[e->mps.freq_res]; // Table 109: Default value of bsOttBandsPhase
int otts_bands_phase = ((int[]){0,10,10,7,5,3,2,2})[e->mps.freq_res]; // Table 109 Default value of bsOttBandsPhase
if (e->mps.otts_bands_phase_present) { /* bsOttBandsPhasePresent */
otts_bands_phase = get_bits(gb, 5); /* bsOttBandsPhase */
if (otts_bands_phase > numBands)
@@ -326,114 +250,6 @@ static int decode_usac_element_pair(AACDecContext *ac,
return 0;
}
/* ISO/IEC 23003-4, Table 62: channelLayout() */
static int decode_drc_channel_layout(GetBitContext *gb)
{
int base_channel_count = get_bits(gb, 7); /* baseChannelCount */
if (get_bits1(gb)) { /* layoutSignallingPresent */
if (get_bits(gb, 8) == 0) /* definedLayout == 0 */
for (int i = 0; i < base_channel_count; i++)
skip_bits(gb, 7); /* speakerPosition */
}
return base_channel_count;
}
/* ISO/IEC 23003-4, Table 63: downmixInstructions() */
static void skip_drc_downmix_instructions(GetBitContext *gb, int base_channel_count)
{
int target_channel_count;
skip_bits(gb, 7); /* downmixId */
target_channel_count = get_bits(gb, 7); /* targetChannelCount */
skip_bits(gb, 8); /* targetLayout */
if (get_bits1(gb)) /* downmixCoefficientsPresent */
skip_bits_long(gb, 4 * target_channel_count * base_channel_count);
}
/* ISO/IEC 23003-4, Table 70: drcInstructionsBasic(), common with the
* uniDrc variant up to the loudness-target fields. */
static void decode_drc_instructions_basic(AACUsacElemConfig *e, GetBitContext *gb)
{
int set_effects;
skip_bits(gb, 6); /* drcSetId */
skip_bits(gb, 4); /* drcLocation */
skip_bits(gb, 7); /* downmixId */
if (get_bits1(gb)) { /* additionalDownmixIdPresent */
int add_downmix_cnt = get_bits(gb, 3); /* additionalDownmixIdCount */
for (int j = 0; j < add_downmix_cnt; j++)
skip_bits(gb, 7); /* additionalDownmixId */
}
set_effects = get_bits(gb, 16); /* drcSetEffect */
if ((set_effects & (3 << 10)) == 0) {
if (get_bits1(gb)) /* limiterPeakTargetPresent */
skip_bits(gb, 8); /* bsLimiterPeakTarget */
}
if (get_bits1(gb)) { /* drcSetTargetLoudnessPresent */
e->drc.loudness.upper = get_bits(gb, 6); /* bsDrcSetTargetLoudnessValueUpper */
if (get_bits1(gb)) /* drcSetTargetLoudnessValueLowerPresent */
e->drc.loudness.lower = get_bits(gb, 6); /* bsDrcSetTargetLoudnessValueLower */
}
}
/* ISO/IEC 23003-4, Table 57: uniDrcConfig() */
static int decode_drc_config(AACDecContext *ac, AACUsacElemConfig *e,
GetBitContext *gb)
{
int nb_downmix_instr, nb_coeff_basic = 0, nb_instr_basic = 0;
int nb_coeff_uni, nb_instr_uni;
int base_channel_count;
e->drc.loudness.lower = -1;
e->drc.loudness.upper = -1;
if (get_bits1(gb)) /* sampleRatePresent */
skip_bits(gb, 18); /* bsSampleRate */
nb_downmix_instr = get_bits(gb, 7); /* downmixInstructionsCount */
if (get_bits1(gb)) { /* drcDescriptionBasicPresent */
nb_coeff_basic = get_bits(gb, 3); /* drcCoefficientsBasicCount */
nb_instr_basic = get_bits(gb, 4); /* drcInstructionsBasicCount */
}
nb_coeff_uni = get_bits(gb, 3); /* drcCoefficientsUniDrcCount */
nb_instr_uni = get_bits(gb, 6); /* drcInstructionsUniDrcCount */
if (nb_coeff_uni || nb_instr_uni) {
avpriv_report_missing_feature(ac->avctx,
"AAC USAC uniDrc DRC processing");
return AVERROR_PATCHWELCOME;
}
base_channel_count = decode_drc_channel_layout(gb);
for (int i = 0; i < nb_downmix_instr; i++)
skip_drc_downmix_instructions(gb, base_channel_count);
for (int i = 0; i < nb_coeff_basic; i++)
skip_bits(gb, 4 + 7); /* drcLocation, drcCharacteristic */
for (int i = 0; i < nb_instr_basic; i++)
decode_drc_instructions_basic(e, gb);
if (get_bits1(gb)) { /* uniDrcConfigExtPresent */
enum AACUSACDRCExt type;
while ((type = get_bits(gb, 4)) != UNIDRCCONFEXT_TERM) {
uint8_t size_bits = get_bits(gb, 4) + 4; /* bitSizeLen */
uint32_t bit_size = get_bits_long(gb, size_bits) + 1; /* extBitSize */
switch (type) {
default:
skip_bits_long(gb, bit_size);
break;
}
}
}
return 0;
}
static int decode_usac_extension(AACDecContext *ac, AACUsacElemConfig *e,
GetBitContext *gb)
{
@@ -457,25 +273,9 @@ static int decode_usac_extension(AACDecContext *ac, AACUsacElemConfig *e,
break;
case ID_EXT_ELE_SAOC:
break;
#endif
case ID_EXT_ELE_UNI_DRC: {
int start = get_bits_count(gb);
int ret = decode_drc_config(ac, e, gb);
int skip = 8*ext_config_len - (get_bits_count(gb) - start);
if (ret == AVERROR_PATCHWELCOME) {
/* Unsupported uniDrcConfig(): ignore the DRC metadata and treat
* the element as fill so the stream stays decodable. */
e->ext.type = ID_EXT_ELE_FILL;
ret = 0;
}
if (ret < 0)
return ret;
if (skip < 0)
return AVERROR_INVALIDDATA;
/* The config is byte-padded to usacExtElementConfigLength */
skip_bits_long(gb, skip);
case ID_EXT_ELE_UNI_DRC:
break;
}
#endif
case ID_EXT_ELE_FILL:
break; /* This is what the spec does */
case ID_EXT_ELE_AUDIOPREROLL:
@@ -570,13 +370,10 @@ int ff_aac_usac_config_decode(AACDecContext *ac, AVCodecContext *avctx,
return AVERROR_PATCHWELCOME;
memset(usac, 0, sizeof(*usac));
usac->loudness.input_method_val = -1;
freq_idx = get_bits(gb, 5); /* usacSamplingFrequencyIndex */
if (freq_idx == 0x1f) {
samplerate = get_bits(gb, 24); /* usacSamplingFrequency */
if (samplerate == 0)
return AVERROR(EINVAL);
} else {
samplerate = ff_aac_usac_samplerate[freq_idx];
if (samplerate < 0)
@@ -770,13 +567,6 @@ int ff_aac_usac_config_decode(AACDecContext *ac, AVCodecContext *avctx,
ac->avctx->profile = AV_PROFILE_AAC_USAC;
usac->loudness.input_method_val = select_loudness_measurement(usac);
if (usac->loudness.input_method_val >= 0)
av_log(avctx, AV_LOG_VERBOSE,
"USAC input loudness: %.2f LKFS (bsMethodValue=%d)\n",
-57.75f + 0.25f * usac->loudness.input_method_val,
usac->loudness.input_method_val);
ret = ff_aac_usac_reset_state(ac, oc);
if (ret < 0)
return ret;
@@ -1549,13 +1339,13 @@ static void spectrum_decode(AACDecContext *ac, AACUSACConfig *usac,
/* Save coefficients and alpha values for prediction reasons */
if (nb_channels > 1) {
AACUsacStereo *us2 = &cpe->us;
AACUsacStereo *us = &cpe->us;
for (int ch = 0; ch < nb_channels; ch++) {
SingleChannelElement *sce = &cpe->ch[ch];
memcpy(sce->prev_coeffs, sce->coeffs, sizeof(sce->coeffs));
}
memcpy(us2->prev_alpha_q_re, us2->alpha_q_re, sizeof(us2->alpha_q_re));
memcpy(us2->prev_alpha_q_im, us2->alpha_q_im, sizeof(us2->alpha_q_im));
memcpy(us->prev_alpha_q_re, us->alpha_q_re, sizeof(us->alpha_q_re));
memcpy(us->prev_alpha_q_im, us->alpha_q_im, sizeof(us->alpha_q_im));
}
for (int ch = 0; ch < nb_channels; ch++) {
@@ -1595,10 +1385,11 @@ static void decode_tsd(GetBitContext *gb, int *data,
break;
}
int64_t c = k - p + 1;
for (int h = 2; h <= p && c <= s; h++) {
c += c*(k-p)/h;
for (int h = 2; h <= p; h++) {
c *= k - p + h;
c /= h;
}
if (s >= c) {
if (s >= (int)c) { /* c is long long for up to 32 slots */
s -= c;
data[k] = 1;
p--;
@@ -1877,7 +1668,7 @@ static int decode_usac_core_coder(AACDecContext *ac, AACUSACConfig *usac,
spectrum_decode(ac, usac, che, core_nb_channels);
if (ac->oc[1].m4ac.sbr > 0) {
ac->proc.sbr_apply(ac, che, nb_channels == 2 ? TYPE_CPE : TYPE_SCE, 0,
ac->proc.sbr_apply(ac, che, nb_channels == 2 ? TYPE_CPE : TYPE_SCE,
che->ch[0].output,
che->ch[1].output);
}
@@ -1941,8 +1732,8 @@ static int parse_audio_preroll(AACDecContext *ac, GetBitContext *gb)
}
/* Byte alignment is not guaranteed. */
for (int j = 0; j < au_len; j++)
tmp_buf[j] = get_bits(gb, 8);
for (int i = 0; i < au_len; i++)
tmp_buf[i] = get_bits(gb, 8);
ret = init_get_bits8(&gbc, tmp_buf, au_len);
if (ret < 0)
@@ -2033,10 +1824,6 @@ static int parse_ext_ele(AACDecContext *ac, AACUsacElemConfig *e,
case ID_EXT_ELE_AUDIOPREROLL:
ret = parse_audio_preroll(ac, gb2);
break;
case ID_EXT_ELE_UNI_DRC:
/* uniDrcGain() payload: DRC is not applied, just consume the
* bits via skip_bits_long below. */
break;
default:
/* This should never happen */
av_assert0(0);
@@ -2171,28 +1958,6 @@ int ff_aac_usac_decode_frame(AVCodecContext *avctx, AACDecContext *ac,
*got_frame_ptr = 0;
}
if (samples && ac->target_level) {
int method_val = usac->loudness.input_method_val;
if (method_val < 0) {
if (!ac->warned_loudness_missing) {
av_log(avctx, AV_LOG_WARNING,
"target_level set but no program/anchor loudness "
"measurement available; normalization skipped\n");
ac->warned_loudness_missing = 1;
}
} else {
/* Per ISO/IEC 23003-4 Table A.48: L = -57.75 + 0.25 * μ */
float input_loudness = -57.75f + 0.25f * method_val;
float gain_dB = (float)ac->target_level - input_loudness;
float gain = powf(10.0f, gain_dB / 20.0f);
for (int ch = 0; ch < frame->ch_layout.nb_channels; ch++)
ac->fdsp->vector_fmul_scalar((float *)frame->extended_data[ch],
(float *)frame->extended_data[ch],
gain, frame->nb_samples);
}
}
/* for dual-mono audio (SCE + SCE) */
is_dmono = ac->dmono_mode && elem_id[0] == 2 &&
!av_channel_layout_compare(&ac->oc[1].ch_layout,
+3 -3
View File
@@ -240,7 +240,7 @@ static void huff_data_2d(GetBitContext *gb, int16_t *part0_data[2], int16_t (*da
0, 2*esc_cnt, 0, (2*lav + 1));
for (i = 0; i < esc_cnt; i++) {
data[esc_idx[i]][0] = esc_data[0][i] - lav;
data[esc_idx[i]][1] = esc_data[1][i] - lav;
data[esc_idx[i]][0] = esc_data[0][i] - lav;
}
}
}
@@ -645,7 +645,7 @@ int ff_aac_ec_data_dec(GetBitContext *gb, AACMPSLosslessData *ld,
stride_table[ld->freq_res[set_idx]],
start_band, end_band);
if (set_idx + data_pair >= MPS_MAX_PARAM_SETS)
if (set_idx + data_pair > MPS_MAX_PARAM_SETS)
return AVERROR(EINVAL);
for (int j = 0; j < data_bands; j++)
@@ -858,7 +858,7 @@ int ff_aac_map_index_data(AACMPSLosslessData *ld,
for (int i = 0; i < nb_param_sets; i++) {
if (ld->coarse_quant_no[i] == 1) {
coarse_to_fine(tmp_idx_data[i], data_type, start_band,
stop_band);
stop_band - start_band);
ld->coarse_quant_no[i] = 0;
}
}
+36 -23
View File
@@ -59,7 +59,6 @@
#define NOISE_LAMBDA_REPLACE 1.948f
#include "libavcodec/aaccoder_trellis.h"
#include "libavcodec/aaccoder_nmr.h"
typedef float (*quantize_and_encode_band_func)(struct AACEncContext *s, PutBitContext *pb,
const float *in, float *quant, const float *scaled,
@@ -503,12 +502,25 @@ static void search_for_pns(AACEncContext *s, AVCodecContext *avctx, SingleChanne
const float dist_bias = av_clipf(4.f * 120 / lambda, 0.25f, 4.0f);
const float pns_transient_energy_r = FFMIN(0.7f, lambda / 140.f);
int prev = -1000, prev_sf = -1;
int refbits = avctx->bit_rate * 1024.0 / avctx->sample_rate
/ ((avctx->flags & AV_CODEC_FLAG_QSCALE) ? 2.0f : avctx->ch_layout.nb_channels)
* (lambda / 120.f);
/** Keep this in sync with twoloop's cutoff selection */
float rate_bandwidth_multiplier = 1.5f;
int prev = -1000, prev_sf = -1;
int frame_bit_rate = (avctx->flags & AV_CODEC_FLAG_QSCALE)
? (refbits * rate_bandwidth_multiplier * avctx->sample_rate / 1024)
: (avctx->bit_rate / avctx->ch_layout.nb_channels);
frame_bit_rate *= 1.15f;
if (avctx->cutoff > 0) {
bandwidth = avctx->cutoff;
} else {
bandwidth = FFMAX(3000, AAC_CUTOFF_FROM_BITRATE(frame_bit_rate, 1, avctx->sample_rate));
}
/* PNS candidacy must use the coder's actual coding bandwidth (s->bandwidth,
* fixed at init), not a separate heuristic, or it evaluates a different band
* range than the coder later codes. */
bandwidth = s->bandwidth;
cutoff = bandwidth * 2 * wlen / avctx->sample_rate;
memcpy(sce->band_alt, sce->band_type, sizeof(sce->band_type));
@@ -627,10 +639,24 @@ static void mark_pns(AACEncContext *s, AVCodecContext *avctx, SingleChannelEleme
const float spread_threshold = FFMIN(0.75f, NOISE_SPREAD_THRESHOLD*FFMAX(0.5f, lambda/100.f));
const float pns_transient_energy_r = FFMIN(0.7f, lambda / 140.f);
/* PNS candidacy must use the coder's actual coding bandwidth (s->bandwidth,
* fixed at init), not a separate heuristic, or it evaluates a different band
* range than the coder later codes (NMR relies on this output directly). */
bandwidth = s->bandwidth;
int refbits = avctx->bit_rate * 1024.0 / avctx->sample_rate
/ ((avctx->flags & AV_CODEC_FLAG_QSCALE) ? 2.0f : avctx->ch_layout.nb_channels)
* (lambda / 120.f);
/** Keep this in sync with twoloop's cutoff selection */
float rate_bandwidth_multiplier = 1.5f;
int frame_bit_rate = (avctx->flags & AV_CODEC_FLAG_QSCALE)
? (refbits * rate_bandwidth_multiplier * avctx->sample_rate / 1024)
: (avctx->bit_rate / avctx->ch_layout.nb_channels);
frame_bit_rate *= 1.15f;
if (avctx->cutoff > 0) {
bandwidth = avctx->cutoff;
} else {
bandwidth = FFMAX(3000, AAC_CUTOFF_FROM_BITRATE(frame_bit_rate, 1, avctx->sample_rate));
}
cutoff = bandwidth * 2 * wlen / avctx->sample_rate;
memcpy(sce->band_alt, sce->band_type, sizeof(sce->band_type));
@@ -841,17 +867,4 @@ const AACCoefficientsEncoder ff_aac_coders[AAC_CODER_NB] = {
search_for_ms,
ff_aac_search_for_is,
},
[AAC_CODER_NMR] = {
search_for_quantizers_nmr,
codebook_trellis_rate,
quantize_and_encode_band,
ff_aac_encode_tns_info,
ff_aac_apply_tns,
set_special_band_scalefactors,
NULL, /* PNS decided in the trellis (search_for_quantizers_nmr) */
mark_pns,
ff_aac_search_for_tns,
NULL,
NULL,
},
};
-700
View File
@@ -1,700 +0,0 @@
/*
* AAC encoder NMR (noise-to-mask ratio) scalefactor coder
* Copyright (c) 2026 Lynne <dev@lynne.ee>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* AAC encoder NMR scalefactor coder.
*
* Optimizes the same noise-to-mask objective as the two-loop coder, but with an
* optimal Viterbi search over scalefactors instead of a heuristic loop. For each
* coded band the per-scalefactor distortion/bits curve is precomputed, then a
* trellis over the (window-group, band) coding sequence minimizes
* sum_g = dist_g(sf_g)/threshold_g +
* lambda * (spectral_bits_g(sf_g) + scalefactor_differential_bits)
* with |sf_g - sf_{g-1}| <= SCALE_MAX_DIFF as a constraint, and lambda
* binary-searched so the coded size meets the per-frame bit budget
*
* Perceptual noise substitution (PNS) is integrated into the same objective: once
* the trellis settles on its operating lambda, each noise-like band (flagged by
* mark_pns) is offered a terminal "code as noise" candidate whose cost is
* nmr_pns + lambda*NMR_PNS_BITS. Because NMR_PNS_BITS is far below a band's spectral bit
* count, this candidate only wins when lambda is large, i.e. when the encoder is
* struggling to hold the bitrate. The bits freed by the chosen PNS bands are
* then re-spent by a second trellis pass over the remaining bands.
*/
#ifndef AVCODEC_AACCODER_NMR_H
#define AVCODEC_AACCODER_NMR_H
#include <float.h>
#include <string.h>
#include "libavutil/mathematics.h"
#include "mathops.h"
#include "avcodec.h"
#include "put_bits.h"
#include "aac.h"
#include "aacenc.h"
#include "aactab.h"
#include "aacenctab.h"
/* differential scalefactor coding cost, clamped to the legal delta range */
#define NMR_SFBITS(d) ff_aac_scalefactor_bits[av_clip((d) + SCALE_DIFF_ZERO, 0, 2*SCALE_MAX_DIFF)]
#define NMR_ITERS 14 /* lambda binary-search iters */
#define NMR_IFINE 9 /* fine-pass lambda iters */
#define NMR_CITERS 7 /* coarse-pass lambda iters */
#define NMR_CWARM 5 /* coarse-pass iters when warm-started off the previous frame's
* lambda: the bracket spans 10 octaves instead of ~43, so fewer
* bisection steps reach the same resolution */
#define NMR_COARSE 8 /* two-pass coarse->fine grid step, cuts the Viterbi ncand^2 with no
* quality loss, 0 disables it (single full-resolution pass) */
#define NMR_STEP 1 /* fine-pass scalefactor candidate granularity */
#define NMR_PNS_BITS 9 /* approx cost in bits of signalling PNS */
/* Spectral-hole fill: noise-like bands the trellis left mostly empty are filled with
* energy-matched noise (PNS); an audible hole sounds worse than matched noise. */
#define NMR_PNS_HOLE_FRAC 0.5f
#define NMR_PNS_HOLE_SPREAD 0.5f
/* RC servo gain: scale the corridor centre by exp2(-K*fill/R) each frame to hold
* the long-run mean rate; without it a bad centre drifts for dozens of frames. */
#define NMR_RC_K_CBR 0.5f
#define NMR_RC_ITERS 8 /* lambda bisection iters when clamping an over-cap frame */
/* Corridor: bisect within [lam_rc/NMR_RC_CORR, lam_rc*NMR_RC_CORR] so quality stays
* smooth while per-frame demand is tracked; 1.5 cuts lambda jitter ~25%. */
#define NMR_RC_CORR 1.5f
/* Leaky-bucket half-depth (bits/ch); 512 is the sweet spot — tighter rebounds as
* frames cannot hit the narrow window. Clamped to the 6144 bits/ch decoder buffer. */
#define NMR_CBR_BUF 512
#define NMR_RC_CITERS 3 /* corridor coarse-pass iters */
/* Transient bit-burst: an isolated onset (preceded by >= NMR_BURST_GAP long frames)
* is coded NMR_BURST_GAIN x finer, held uniform across the run, repaid from steady stretches. */
#define NMR_BURST_GAP 10
#define NMR_BURST_GAIN 8.0f
#define NMR_RC_FITERS 4 /* corridor fine-pass iters */
#define NMR_RC_TRACK 0.1f /* per-frame pull of the corridor centre toward the realized lambda */
/* PNS noise-distortion gate: only bands coded well above the masking floor become noise. */
#define NMR_PNS_NDGATE 4.0f
/* Energy/threshold cap for PNS: loud bands (energy >> mask) yield clipping random peaks;
* only near-masked bands are safe substitution targets. */
#define NMR_PNS_MAX_ET 8.0f
/* Operating-lambda floor for PNS: below it the encoder is not struggling, so
* substituting real texture for 9 signalling bits is net-negative. */
#define NMR_PNS_LAM 100.0f
/**
* Viterbi over the coding sequence act[0..nact-1] (indices into the per-band
* curves nd/nb), with lambda binary-searched so the coded size ~ destbits.
* Fills chosen[band] for every band referenced by act. Returns the operating
* lambda. node cost = dist/threshold + lambda*spectral_bits;
* edge cost = lambda*sf_differential_bits; |delta sf| <= SCALE_MAX_DIFF hard.
*/
static float nmr_solve(AACEncContext *s,
const float (*nd)[NMR_NCAND], const int (*nb)[NMR_NCAND],
const int *blo, const int *bnc, int step,
const int *act, int nact, int destbits, int *chosen,
float lo_l, float hi_l, int iters)
{
float dp[NMR_NCAND], dpp[NMR_NCAND], node[NMR_NCAND];
float lamsf[2*SCALE_MAX_DIFF + 1]; /* lam*sfdiff bit cost, per lambda */
uint8_t bp[128][NMR_NCAND];
float lam = 1.0f;
if (nact <= 0)
return lam;
for (int it = 0; it < iters; it++) {
lam = sqrtf(lo_l * hi_l);
for (int i = 0; i <= 2*SCALE_MAX_DIFF; i++)
lamsf[i] = lam * ff_aac_scalefactor_bits[i]; /* edge cost for this lambda */
int b0 = act[0];
for (int o = 0; o < bnc[b0]; o++)
dp[o] = nd[b0][o] + lam * nb[b0][o]; /* anchor band node cost */
for (int k = 1; k < nact; k++) {
int b = act[k], pb = act[k-1];
memcpy(dpp, dp, sizeof(dp));
for (int o = 0; o < bnc[b]; o++)
node[o] = nd[b][o] + lam * nb[b][o];
/* dp[o] = node[o] + min_op(dpp[op] + edge cost) */
s->aacdsp.nmr_trellis_step(dp, bp[k], dpp, node, lamsf,
bnc[b], bnc[pb], blo[b] - blo[pb], step,
SCALE_MAX_DIFF);
}
/* backtrack */
int beo = 0, b = act[nact-1];
float bec = FLT_MAX;
for (int o = 0; o < bnc[b]; o++)
if (dp[o] < bec) { bec = dp[o]; beo = o; }
chosen[b] = beo;
for (int k = nact-1; k > 0; k--)
chosen[act[k-1]] = bp[k][chosen[act[k]]];
/* calc cost */
int total = 0;
for (int k = 0; k < nact; k++)
total += nb[act[k]][chosen[act[k]]];
for (int k = 1; k < nact; k++)
total += NMR_SFBITS((blo[act[k]]+chosen[act[k]]*step) - (blo[act[k-1]]+chosen[act[k-1]]*step));
if (it == iters - 1)
break;
/* check if we went over budget, go coarser if we did */
if (total > destbits)
lo_l = lam;
else
hi_l = lam;
}
return lam;
}
/* Build one coded band's (dist/threshold, bits) cost curve, candidates sf = lo + o*step
* for o in [0,maxn), stopping when the band would drop (cb <= 0). Returns the bit count. */
static int nmr_band_curve(AACEncContext *s, SingleChannelElement *sce, int w, int g,
int start, int lo, int step, int maxn, float invthr,
float maxval, float *nd_row, int *nb_row)
{
int ncand = 0;
for (int o = 0; o < maxn && lo + o*step <= SCALE_MAX_POS; o++) {
int sf = lo + o*step, btot = 0, cb = find_min_book(maxval, sf);
float dist = 0.0f;
if (cb <= 0)
break;
for (int w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
int bb;
dist += quantize_band_cost_cached(s, w + w2, g, sce->coeffs + start + w2*128,
s->scoefs + start + w2*128, sce->ics.swb_sizes[g],
sf, cb, 1.0f, INFINITY, &bb, NULL, 0);
btot += bb;
}
nd_row[ncand] = (dist - btot) * invthr;
nb_row[ncand] = btot;
ncand++;
}
return ncand;
}
static void search_for_quantizers_nmr(AVCodecContext *avctx,
AACEncContext *s,
SingleChannelElement *sce,
const float lambda)
{
int bch = ((avctx->flags & AV_CODEC_FLAG_QSCALE) ? 2.0f : avctx->ch_layout.nb_channels);
int destbits = avctx->bit_rate * 1024.0 / avctx->sample_rate / bch * (lambda / 120.f);
int allz = 0, cutoff = 1024, nbnd = 0;
float thr[128]; /* allocation-law effective threshold (drives the trellis) */
float thr_real[128]; /* real masking threshold (perceptual gates: PNS) */
float pener[128]; /* band energy (for PNS noise target) */
float pspread[128]; /* band tonality spread (1 = noise) */
int minsf[128];
float maxvals[128];
/* coded-band trellis state (indexed 0..nbnd-1) */
int bidx[128]; /* sce band index (w*16+g) */
int bw[128], bg[128], bst[128]; /* window group, swb, coef start per coded band */
int blo[128]; /* finest candidate scalefactor */
int bnc[128]; /* number of candidates */
int chosen[128];
int act[128]; /* active (non-PNS) band coding order */
uint8_t is_pns[128]; /* trellis band coded as noise */
float (*nd)[NMR_NCAND] = s->nmr->nd; /* dist / threshold per candidate (heap) */
int (*nb)[NMR_NCAND] = s->nmr->nb; /* spectral bits per candidate (heap) */
/* two-pass coarse->fine grid step (see NMR_COARSE), the lambda search runs on
* the cheap coarse grid, PASS 2 refines the winner at NMR_STEP granularity */
const int cstep = NMR_COARSE > 0 ? NMR_COARSE : NMR_STEP;
s->nmr->counted[s->cur_channel] = 0;
/* Global-lambda RC: one solve per frame at a servoed centre lambda; the reservoir
* holds the long-run mean rate. Bypassed for VBR (-q:a) and the bootstrap frame. */
int rc_eligible = !(avctx->flags & AV_CODEC_FLAG_QSCALE) && avctx->bit_rate > 0 &&
avctx->bit_rate_tolerance != 0;
/* Leaky-bucket reservoir: rc_fill (signed +-rc_bmax); the spend-floor/cap below force
* lambda so no frame banks past +rc_bmax or borrows past -rc_bmax. */
int rc_rate_frame = avctx->bit_rate * 1024.0 / avctx->sample_rate;
int rc_bmax = FFMIN(FFMAX(6144 * s->channels - rc_rate_frame, 256), NMR_CBR_BUF * s->channels);
if (rc_eligible && avctx->frame_num != s->nmr->rc_frame_num) {
if (s->nmr->rc_frame_num > 0 && s->nmr->lam_rc > 0.0f)
s->nmr->rc_fill = av_clip(s->nmr->rc_fill + rc_rate_frame - s->last_frame_pb_count,
-rc_bmax, rc_bmax);
s->nmr->rc_frame_num = avctx->frame_num;
/* Transient burst run state: set at run start and held across the run so
* coding stays uniform; repaid from the reservoir's steady stretches. */
int is_short = sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE;
if (is_short) {
if (!s->nmr->prev_was_short) /* run start */
s->nmr->run_burst = s->nmr->frames_since_short >= NMR_BURST_GAP
? NMR_BURST_GAIN : 1.0f;
s->nmr->frames_since_short = 0;
} else {
s->nmr->run_burst = 1.0f;
s->nmr->frames_since_short++;
}
s->nmr->prev_was_short = is_short;
}
int rc_global = rc_eligible && s->nmr->lam_rc > 0.0f;
if (s->psy.bitres.alloc >= 0)
destbits = s->psy.bitres.alloc *
(lambda / (avctx->global_quality ? avctx->global_quality : 120));
if (rc_global && s->psy.bitres.alloc >= 0)
/* uniform CBR target: nominal rate plus fast reservoir repayment */
destbits = (avctx->bit_rate * 1024.0 / avctx->sample_rate
+ s->nmr->rc_fill / 2.0) / s->channels;
destbits = FFMIN(destbits, 5800);
/* honest budget: subtract the measured non-trellis overhead (section data, ICS,
* sf/PNS signalling), which is rate-dependent hence adaptive. */
if (s->nmr->side_inited)
destbits = av_clip(destbits - (int)(s->nmr->side_ema / s->channels), 64, 5800);
/* Apply the held transient burst factor (set in the run-state machine above). */
if (sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE && s->nmr->run_burst > 1.0f)
destbits = av_clip((int)(destbits * s->nmr->run_burst), 64, 6800);
/* band cutoff index for this frame's window size; the bandwidth is fixed
* at init and shared with the psy model */
cutoff = s->bandwidth * 2 * (1024 / sce->ics.num_windows) / avctx->sample_rate;
/* Short-block transient noise shaping (pairs with short-block TNS): temporal
* premasking clamps each window's threshold toward the preceding windows'
* (Apple's preEchoReduction), and flat-residual flattens each window's thresholds
* to their per-window mean so TNS synthesis has a white floor to concentrate. */
if (sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
const float pm_p1 = 0.1f, pm_p2 = 2.0f, pm_p3 = 4.0f;
for (int g = 0; g < sce->ics.num_swb; g++) {
float t1 = FLT_MAX, t2 = FLT_MAX; /* original thr of w-1, w-2 */
for (int w = 0; w < sce->ics.num_windows; w++) {
FFPsyBand *b = &s->psy.ch[s->cur_channel].psy_bands[w*16+g];
float t = b->threshold;
float c = FFMIN(t, FFMIN(t1*pm_p2, t2*pm_p3));
b->threshold = FFMAX(c, t*pm_p1);
t2 = t1; t1 = t;
}
}
{
for (int w = 0; w < sce->ics.num_windows; w++) {
float sum = 0.0f; int n = 0;
for (int g = 0; g < sce->ics.num_swb; g++) {
FFPsyBand *b = &s->psy.ch[s->cur_channel].psy_bands[w*16+g];
if (b->energy > b->threshold && b->threshold > 0.0f) { sum += b->threshold; n++; }
}
if (n > 0) {
float mean = sum / n;
for (int g = 0; g < sce->ics.num_swb; g++) {
FFPsyBand *b = &s->psy.ch[s->cur_channel].psy_bands[w*16+g];
if (b->energy > b->threshold && b->threshold > 0.0f)
b->threshold = mean;
}
}
}
}
}
/* Allocation curve to favour high frequencies */
const float a_ae = 0.443f, a_at = 0.111f;
for (int w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
int start = 0;
for (int g = 0; g < sce->ics.num_swb; start += sce->ics.swb_sizes[g++]) {
float uplim = 0.0f, ener = 0.0f, spread = 2.0f;
int nz = 0;
if (sce->band_type[w*16+g] == INTENSITY_BT ||
sce->band_type[w*16+g] == INTENSITY_BT2) {
/* pre-decided intensity band (right channel): keep its
* signalling, it is not trellis-coded */
for (int w2 = 0; w2 < sce->ics.group_len[w]; w2++)
sce->zeroes[(w+w2)*16+g] = 0;
continue;
}
for (int w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g];
ener += band->energy;
spread = FFMIN(spread, band->spread);
if (start >= cutoff || band->energy <= band->threshold || band->threshold == 0.0f) {
sce->zeroes[(w+w2)*16+g] = 1;
continue;
}
uplim += band->threshold;
nz = 1;
}
sce->zeroes[w*16+g] = !nz;
thr_real[w*16+g] = uplim; /* real mask, before the allocation law (PNS gate) */
if (nz && ener > 0.0f && uplim > 0.0f)
uplim = expf(a_ae * logf(ener) + a_at * logf(uplim));
thr[w*16+g] = uplim;
pener[w*16+g] = ener;
pspread[w*16+g] = spread;
allz |= nz;
}
}
if (!allz)
goto bail;
s->aacdsp.abs_pow34(s->scoefs, sce->coeffs, 1024);
ff_quantize_band_cost_cache_init(s);
/* finest codeable scalefactor and max value per band */
for (int w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
int start = w*128;
for (int g = 0; g < sce->ics.num_swb; g++) {
maxvals[w*16+g] = find_max_val(sce->ics.group_len[w], sce->ics.swb_sizes[g], s->scoefs + start);
minsf[w*16+g] = maxvals[w*16+g] > 0 ? coef2minsf(maxvals[w*16+g]) : 0;
start += sce->ics.swb_sizes[g];
}
}
/* PASS 1:
* precompute each coded band's cost curve at the coarse candidate step
* (the lambda search runs on this cheap grid, PASS 2 refines the winner) */
{
for (int w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
int start = w*128;
for (int g = 0; g < sce->ics.num_swb; g++) {
if (!sce->zeroes[w*16+g] && maxvals[w*16+g] > 0 && nbnd < 128) {
int lo = av_clip(minsf[w*16+g], 0, SCALE_MAX_POS);
float invthr = 1.0f / FFMAX(thr[w*16+g], 1e-9f);
int ncand = nmr_band_curve(s, sce, w, g, start, lo, cstep, NMR_NCAND,
invthr, maxvals[w*16+g], nd[nbnd], nb[nbnd]);
if (ncand == 0) {
/* nothing codeable -> drop the whole group band. The
* subwindow flags must be cleared too: the encoder later
* re-derives the group flag by ANDing them, which would
* resurrect the band with a never-assigned scalefactor. */
for (int w2 = 0; w2 < sce->ics.group_len[w]; w2++)
sce->zeroes[(w+w2)*16+g] = 1;
} else {
bidx[nbnd] = w*16+g;
bw[nbnd] = w;
bg[nbnd] = g;
bst[nbnd] = start;
blo[nbnd] = lo;
bnc[nbnd] = ncand;
nbnd++;
}
}
start += sce->ics.swb_sizes[g];
}
}
}
if (!nbnd)
goto bail;
/* solve the trellis over all coded bands, then offer PNS at the operating
* lambda and re-solve over the survivors with the freed budget */
{
int nact = nbnd, pns_count = 0;
float lam0 = s->nmr->lam[s->cur_channel];
float lam;
for (int b = 0; b < nbnd; b++) {
act[b] = b;
is_pns[b] = 0;
}
if (rc_global) {
/* bisect to this frame's bit demand within the corridor around the
* servoed lambda: per-frame psy demand is tracked, but lambda cannot
* jump, which keeps quality smooth across frames */
float lo = s->nmr->lam_rc / NMR_RC_CORR;
/* Transient burst: widen the lower lambda bound so the bisection can actually
* pour the boosted destbits into an onset frame (finer coding kills the
* pre-echo); reservoir servo repays it from the steady frames. run_burst==1 on
* non-onset frames leaves the corridor unchanged. */
if (sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE && s->nmr->run_burst > 1.0f)
lo /= s->nmr->run_burst;
lam = nmr_solve(s, nd, nb, blo, bnc, cstep, act, nact, destbits, chosen,
lo, s->nmr->lam_rc * NMR_RC_CORR,
NMR_RC_CITERS);
int tot = 0;
for (int k = 0; k < nact; k++)
tot += nb[act[k]][chosen[act[k]]];
for (int k = 1; k < nact; k++)
tot += NMR_SFBITS((blo[act[k]]+chosen[act[k]]*cstep) - (blo[act[k-1]]+chosen[act[k-1]]*cstep));
int hardcap = av_clip((int)(5800.f * FFMIN(1.f, lambda / 120.f)), 256, 5800);
/* leaky-bucket window: don't borrow past -rc_bmax (cap) or bank past +rc_bmax (floor) */
int rc_cap = FFMIN(hardcap, (s->nmr->rc_fill + rc_rate_frame + rc_bmax) / s->channels);
int rc_floor = FFMAX(0, (s->nmr->rc_fill + rc_rate_frame - rc_bmax) / s->channels);
if (tot > rc_cap)
lam = nmr_solve(s, nd, nb, blo, bnc, cstep, act, nact, rc_cap, chosen,
lam, 1e4f, NMR_CITERS);
else if (tot < rc_floor)
lam = nmr_solve(s, nd, nb, blo, bnc, cstep, act, nact, rc_floor, chosen,
1e-9f, lam, NMR_CITERS);
} else if (NMR_COARSE > 0 && lam0 > 0.0f) {
/* per-frame bisection; lambda is strongly frame-correlated, so when a
* previous frame's operating lambda exists, bisect a narrow bracket
* around it. A result near the bracket edge means the budget crossing
* lies outside (hard content transition) == redo the full search. */
lam = nmr_solve(s, nd, nb, blo, bnc, cstep, act, nact, destbits, chosen,
lam0/32.0f, lam0*32.0f, NMR_CWARM);
if (lam < lam0/16.0f || lam > lam0*16.0f)
lam0 = 0.0f;
}
if (!rc_global && lam0 <= 0.0f)
lam = nmr_solve(s, nd, nb, blo, bnc, cstep, act, nact, destbits, chosen,
1e-9f, 1e4f, NMR_COARSE > 0 ? NMR_CITERS : NMR_ITERS);
/* PASS 2:
* refine each band at full granularity (NMR_STEP) in a +/-cstep window
* around the coarse pick, then re-solve. Recovers single-pass quality while the
* lambda search stayed cheap on the coarse grid. */
if (NMR_COARSE > 0) {
/* nmr_speed, 0 = slowest/best, higher = faster. It narrows the fine
* refine +/-window (scalefactors) below NMR_COARSE: at speed 0 the window
* spans the whole coarse-grid gap, so the two-pass result matches the
* exhaustive single-pass search.
* Each speed level shaves one sf off the window.
* At @64k mono (Zim / xRT): speed 0 -> 0.00095/15x,
* 2 -> 0.00096/18x, 3 -> 0.00100/20x, 4 -> 0.00103/22x */
int win = NMR_COARSE - av_clip(s->options.nmr_speed, 0, 4);
for (int b = 0; b < nbnd; b++) {
int center = blo[b] + chosen[b]*cstep;
int flo = av_clip(center - win, av_clip(minsf[bidx[b]], 0, SCALE_MAX_POS), SCALE_MAX_POS);
int maxn = FFMIN(NMR_NCAND, 2*win/NMR_STEP + 1);
float invthr = 1.0f / FFMAX(thr[bidx[b]], 1e-9f);
int ncand = nmr_band_curve(s, sce, bw[b], bg[b], bst[b], flo, NMR_STEP, maxn,
invthr, maxvals[bidx[b]], nd[b], nb[b]);
blo[b] = flo;
bnc[b] = FFMAX(1, ncand);
}
/* fine pass: narrow corridor around the coarse solve */
if (rc_global)
lam = nmr_solve(s, nd, nb, blo, bnc, NMR_STEP, act, nact, destbits, chosen,
lam/2.0f, lam*2.0f, NMR_RC_FITERS);
else
lam = nmr_solve(s, nd, nb, blo, bnc, NMR_STEP, act, nact, destbits, chosen,
lam/16.0f, lam*16.0f, NMR_IFINE);
}
if (rc_global) {
/* leaky-bucket clamp: keep the frame within [rc_floor, rc_cap] so the reservoir
* stays in +-rc_bmax -- clamp lambda UP if it would borrow past the cap, DOWN if it
* would bank past the floor (spend-floor). The hard cap follows the encoder's outer
* lambda so the (rare) hard-overflow re-encode -- which shrinks that lambda -- always
* converges; on the first pass lambda is nominal and this is 5800. */
int hardcap = av_clip((int)(5800.f * FFMIN(1.f, lambda / 120.f)), 256, 5800);
int tot = 0;
for (int k = 0; k < nact; k++)
tot += nb[act[k]][chosen[act[k]]];
for (int k = 1; k < nact; k++)
tot += NMR_SFBITS((blo[act[k]]+chosen[act[k]]*NMR_STEP) - (blo[act[k-1]]+chosen[act[k-1]]*NMR_STEP));
int rc_cap = FFMIN(hardcap, (s->nmr->rc_fill + rc_rate_frame + rc_bmax) / s->channels);
int rc_floor = FFMAX(0, (s->nmr->rc_fill + rc_rate_frame - rc_bmax) / s->channels);
if (tot > rc_cap)
lam = nmr_solve(s, nd, nb, blo, bnc, NMR_STEP, act, nact, rc_cap, chosen,
lam, 1e4f, NMR_RC_ITERS);
else if (tot < rc_floor)
lam = nmr_solve(s, nd, nb, blo, bnc, NMR_STEP, act, nact, rc_floor, chosen,
1e-9f, lam, NMR_RC_ITERS);
}
s->nmr->lam[s->cur_channel] = lam; /* warm start for the next frame */
if (rc_global) {
/* drag the corridor centre toward the realized lambda so it follows
* content drift faster than the reservoir term alone */
float c = s->nmr->lam_rc * powf(lam / s->nmr->lam_rc, NMR_RC_TRACK);
/* then servo the centre off the reservoir error so the long-run rate
* returns to nominal. rc_fill>0 = bits banked (undershooting) -> lower
* lambda to spend them; <0 -> raise it. This is what holds the mean;
* the corridor tracking alone has no rate authority and a bad centre
* would otherwise drift for dozens of frames, starving each one. */
float R = avctx->bit_rate * 1024.0 / avctx->sample_rate;
c *= exp2f(-NMR_RC_K_CBR * s->nmr->rc_fill / R);
s->nmr->lam_rc = av_clipf(c, 1e-6f, 1e4f);
} else if (rc_eligible && nbnd >= 8) {
/* bootstrap the servo off the first substantive frame; near-silent
* lead-in frames have degenerate budgets that rail the bisection to
* a nonsense lambda and would poison the whole stream */
s->nmr->lam_rc = av_clipf(lam, 1e-4f, 10.0f);
}
{ /* PNS */
const float pns_lam = NMR_PNS_LAM;
/* band 0 (lowest freq) is kept as the global-gain / sf-chain anchor */
for (int b = 1; b < nbnd; b++) {
int bi = bidx[b];
float spread = pspread[bi];
float nmr_pns, cost_keep, cost_pns, frac;
if (!sce->can_pns[bi])
continue;
/* Loud-band guard: never substitute a band whose energy is far above the
* masking threshold -- energy-matched noise on a dominant band clips/pops
* (and is audibly wrong). PNS is for near-masked noise only. */
if (pener[bi] > NMR_PNS_MAX_ET * thr_real[bi])
continue;
/* Struggle gate: no PNS at all unless the encoder is genuinely under bit
* pressure (high operating lambda). */
if (lam <= pns_lam)
continue;
/* Spectral-hole fill: a noise-like band the trellis left mostly empty */
frac = nd[b][chosen[b]] * thr[bi] / FFMAX(pener[bi], 1e-9f);
if (spread > NMR_PNS_HOLE_SPREAD && frac > NMR_PNS_HOLE_FRAC) {
is_pns[b] = 1;
pns_count++;
continue;
}
/* Only replace a band that is being coded audibly badly */
if (nd[b][chosen[b]] * thr[bi] <= NMR_PNS_NDGATE * thr_real[bi])
continue;
/* perceptual cost of replacing the band with energy-matched noise:
* the non-noise-like fraction of its energy, in dist/threshold units */
nmr_pns = FFMAX(0.0f, pener[bi] * (1.0f - spread*spread))
/ FFMAX(thr[bi], 1e-9f);
cost_keep = nd[b][chosen[b]] + lam * nb[b][chosen[b]];
cost_pns = nmr_pns + lam * NMR_PNS_BITS;
if (cost_pns < cost_keep) {
is_pns[b] = 1;
pns_count++;
}
}
if (pns_count) {
int budget2 = destbits - pns_count * NMR_PNS_BITS;
nact = 0;
for (int b = 0; b < nbnd; b++)
if (!is_pns[b])
act[nact++] = b;
/* re-solve over the survivors: at fixed lambda the allocation is
* the same except for the repaired sf-delta chain; in bisection
* mode re-spend the freed budget */
if (rc_global)
nmr_solve(s, nd, nb, blo, bnc, NMR_STEP, act, nact, budget2, chosen,
lam, lam, 1);
else
nmr_solve(s, nd, nb, blo, bnc, NMR_STEP, act, nact, budget2, chosen,
1e-9f, 1e4f, NMR_ITERS);
}
}
for (int b = 0; b < nbnd; b++) {
int bi = bidx[b];
if (is_pns[b]) {
sce->band_type[bi] = NOISE_BT;
sce->zeroes[bi] = 0;
sce->pns_ener[bi] = pener[bi] * FFMIN(1.0f, pspread[bi]*pspread[bi]);
} else {
sce->sf_idx[bi] = av_clip(blo[b] + chosen[b]*NMR_STEP, 0, SCALE_MAX_POS);
}
}
{ /* record the bits this solve accounted for; the encoder compares them
* against the channel's real output to keep the budget honest */
int tot = 0, prevb = -1;
for (int b = 0; b < nbnd; b++) {
if (is_pns[b])
continue;
tot += nb[b][chosen[b]];
if (prevb >= 0)
tot += NMR_SFBITS((blo[b]+chosen[b]*NMR_STEP) - (blo[prevb]+chosen[prevb]*NMR_STEP));
prevb = b;
}
s->nmr->counted[s->cur_channel] = tot;
}
}
/* SCALE_MAX_DIFF condition:
* re-clamp, codebook fixup, drop uncodeable, set global gain
* NOISE_BT bands keep their own scalefactor chain via set_special_band_scalefactors) */
{
uint8_t nextband[128];
int prev = -1;
ff_init_nextband_map(sce, nextband);
for (int w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
for (int g = 0; g < sce->ics.num_swb; g++) {
if (sce->band_type[w*16+g] == NOISE_BT ||
sce->band_type[w*16+g] == INTENSITY_BT ||
sce->band_type[w*16+g] == INTENSITY_BT2)
continue;
if (sce->zeroes[w*16+g]) {
sce->band_type[w*16+g] = 0;
continue;
}
if (prev != -1)
sce->sf_idx[w*16+g] = av_clip(sce->sf_idx[w*16+g], prev - SCALE_MAX_DIFF, prev + SCALE_MAX_DIFF);
sce->band_type[w*16+g] = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]);
if (sce->band_type[w*16+g] <= 0) {
if (!ff_sfdelta_can_remove_band(sce, nextband, prev, w*16+g)) {
sce->band_type[w*16+g] = 1;
} else {
/* drop subwindow flags too, see the PASS 1 drop above */
for (int w2 = 0; w2 < sce->ics.group_len[w]; w2++)
sce->zeroes[(w+w2)*16+g] = 1;
sce->band_type[w*16+g] = 0;
continue;
}
}
if (prev == -1)
sce->sf_idx[0] = sce->sf_idx[w*16+g]; /* global gain */
prev = sce->sf_idx[w*16+g];
}
}
/* Every band, coded or not, must carry a chain-legal scalefactor: the
* codebook trellis (encode_window_bands_info) may later absorb a dropped
* band into a nonzero section, resurrecting it, and its sf then gets
* coded. Forward-fill with the previous coded sf (delta 0, cheapest);
* leading bands get the global gain. */
if (prev != -1) {
int last = sce->sf_idx[0];
for (int w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
for (int g = 0; g < sce->ics.num_swb; g++) {
if (!sce->zeroes[w*16+g] && sce->band_type[w*16+g] != NOISE_BT &&
sce->band_type[w*16+g] < RESERVED_BT)
last = sce->sf_idx[w*16+g];
else if (sce->band_type[w*16+g] < RESERVED_BT && (w*16+g) > 0)
sce->sf_idx[w*16+g] = last;
}
}
}
}
return;
bail:
/* Nothing codeable in this channel. Leave a fully consistent state: any
* stale nonzero band_type acts as a codebook lower bound in the encoder's
* section trellis (encode_window_bands_info), which would forbid the zero
* section and resurrect the band with a stale, chain-illegal scalefactor.
* Pre-decided intensity bands keep their signalling. */
for (int i = 0; i < 128; i++) {
if (sce->band_type[i] == INTENSITY_BT || sce->band_type[i] == INTENSITY_BT2)
continue;
sce->zeroes[i] = 1;
sce->band_type[i] = 0;
}
}
#endif /* AVCODEC_AACCODER_NMR_H */
+27 -2
View File
@@ -71,6 +71,7 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx,
int destbits = avctx->bit_rate * 1024.0 / avctx->sample_rate
/ ((avctx->flags & AV_CODEC_FLAG_QSCALE) ? 2.0f : avctx->ch_layout.nb_channels)
* (lambda / 120.f);
int refbits = destbits;
int toomanybits, toofewbits;
char nzs[128];
uint8_t nextband[128];
@@ -171,8 +172,32 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx,
/** and zero out above cutoff frequency */
{
int wlen = 1024 / sce->ics.num_windows;
/* the bandwidth is fixed at init and shared with the psy model */
cutoff = s->bandwidth * 2 * wlen / avctx->sample_rate;
int bandwidth;
/**
* Scale, psy gives us constant quality, this LP only scales
* bitrate by lambda, so we save bits on subjectively unimportant HF
* rather than increase quantization noise. Adjust nominal bitrate
* to effective bitrate according to encoding parameters,
* AAC_CUTOFF_FROM_BITRATE is calibrated for effective bitrate.
*/
float rate_bandwidth_multiplier = 1.5f;
int frame_bit_rate = (avctx->flags & AV_CODEC_FLAG_QSCALE)
? (refbits * rate_bandwidth_multiplier * avctx->sample_rate / 1024)
: (avctx->bit_rate / avctx->ch_layout.nb_channels);
/** Compensate for extensions that increase efficiency */
if (s->options.pns || s->options.intensity_stereo)
frame_bit_rate *= 1.15f;
if (avctx->cutoff > 0) {
bandwidth = avctx->cutoff;
} else {
bandwidth = FFMAX(3000, AAC_CUTOFF_FROM_BITRATE(frame_bit_rate, 1, avctx->sample_rate));
s->psy.cutoff = bandwidth;
}
cutoff = bandwidth * 2 * wlen / avctx->sample_rate;
pns_start_pos = NOISE_LOW_LIMIT * 2 * wlen / avctx->sample_rate;
}
+148 -496
View File
@@ -123,40 +123,40 @@ static const AACPCEInfo aac_pce_configs[] = {
{
.layout = AV_CHANNEL_LAYOUT_SURROUND,
.num_ele = { 2, 0, 0, 0 },
.pairing = { { 0, 1 }, },
.pairing = { { 1, 0 }, },
.index = { { 0, 0 }, },
.config_map = { 2, TYPE_SCE, TYPE_CPE },
.reorder_map = { 2, 0, 1 },
.config_map = { 2, TYPE_CPE, TYPE_SCE, },
.reorder_map = { 0, 1, 2 },
},
{
.layout = AV_CHANNEL_LAYOUT_3POINT1,
.num_ele = { 2, 0, 0, 1 },
.pairing = { { 0, 1 }, },
.pairing = { { 1, 0 }, },
.index = { { 0, 0 }, { 0 }, { 0 }, { 0 }, },
.config_map = { 3, TYPE_SCE, TYPE_CPE, TYPE_LFE },
.reorder_map = { 2, 0, 1, 3 },
.config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_LFE },
.reorder_map = { 0, 1, 2, 3 },
},
{
.layout = AV_CHANNEL_LAYOUT_4POINT0,
.num_ele = { 2, 0, 1, 0 },
.pairing = { { 0, 1 }, { 0 }, { 0 }, },
.pairing = { { 1, 0 }, { 0 }, { 0 }, },
.index = { { 0, 0 }, { 0 }, { 1 } },
.config_map = { 3, TYPE_SCE, TYPE_CPE, TYPE_SCE },
.reorder_map = { 2, 0, 1, 3 },
.config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_SCE },
.reorder_map = { 0, 1, 2, 3 },
},
{
.layout = AV_CHANNEL_LAYOUT_4POINT1,
.num_ele = { 2, 0, 1, 1 },
.pairing = { { 0, 1 }, { 0 }, { 0 }, },
.index = { { 0, 0 }, { 0 }, { 1 }, { 0 } },
.config_map = { 4, TYPE_SCE, TYPE_CPE, TYPE_SCE, TYPE_LFE },
.reorder_map = { 2, 0, 1, 4, 3 },
.num_ele = { 2, 1, 1, 0 },
.pairing = { { 1, 0 }, { 0 }, { 0 }, },
.index = { { 0, 0 }, { 1 }, { 2 }, { 0 } },
.config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_SCE },
.reorder_map = { 0, 1, 2, 3, 4 },
},
{
.layout = AV_CHANNEL_LAYOUT_2_2,
.num_ele = { 1, 0, 1, 0 },
.pairing = { { 1 }, { 0 }, { 1 }, },
.index = { { 0 }, { 0 }, { 1 } },
.num_ele = { 1, 1, 0, 0 },
.pairing = { { 1 }, { 1 }, },
.index = { { 0 }, { 1 }, },
.config_map = { 2, TYPE_CPE, TYPE_CPE },
.reorder_map = { 0, 1, 2, 3 },
},
@@ -170,131 +170,158 @@ static const AACPCEInfo aac_pce_configs[] = {
},
{
.layout = AV_CHANNEL_LAYOUT_5POINT0,
.num_ele = { 2, 0, 1, 0 },
.pairing = { { 0, 1 }, { 0 }, { 1 } },
.index = { { 0, 0 }, { 0 }, { 1 } },
.config_map = { 3, TYPE_SCE, TYPE_CPE, TYPE_CPE },
.reorder_map = { 2, 0, 1, 3, 4 },
.num_ele = { 2, 1, 0, 0 },
.pairing = { { 1, 0 }, { 1 }, },
.index = { { 0, 0 }, { 1 } },
.config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_CPE },
.reorder_map = { 0, 1, 2, 3, 4 },
},
{
.layout = AV_CHANNEL_LAYOUT_5POINT1,
.num_ele = { 2, 0, 1, 1 },
.pairing = { { 0, 1 }, { 0 }, { 1 }, },
.index = { { 0, 0 }, { 0 }, { 1 }, { 0 } },
.config_map = { 4, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_LFE },
.reorder_map = { 2, 0, 1, 4, 5, 3 },
.num_ele = { 2, 1, 1, 0 },
.pairing = { { 1, 0 }, { 0 }, { 1 }, },
.index = { { 0, 0 }, { 1 }, { 1 } },
.config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE },
.reorder_map = { 0, 1, 2, 3, 4, 5 },
},
{
.layout = AV_CHANNEL_LAYOUT_5POINT0_BACK,
.num_ele = { 2, 0, 1, 0 },
.pairing = { { 0, 1 }, { 0 }, { 1 } },
.pairing = { { 1, 0 }, { 0 }, { 1 } },
.index = { { 0, 0 }, { 0 }, { 1 } },
.config_map = { 3, TYPE_SCE, TYPE_CPE, TYPE_CPE },
.reorder_map = { 2, 0, 1, 3, 4 },
.config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_CPE },
.reorder_map = { 0, 1, 2, 3, 4 },
},
{
.layout = AV_CHANNEL_LAYOUT_5POINT1_BACK,
.num_ele = { 2, 0, 1, 1 },
.pairing = { { 0, 1 }, { 0 }, { 1 }, },
.index = { { 0, 0 }, { 0 }, { 1 }, { 0 } },
.config_map = { 4, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_LFE },
.reorder_map = { 2, 0, 1, 4, 5, 3 },
.num_ele = { 2, 1, 1, 0 },
.pairing = { { 1, 0 }, { 0 }, { 1 }, },
.index = { { 0, 0 }, { 1 }, { 1 } },
.config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE },
.reorder_map = { 0, 1, 2, 3, 4, 5 },
},
{
.layout = AV_CHANNEL_LAYOUT_6POINT0,
.num_ele = { 2, 0, 2, 0 },
.pairing = { { 0, 1 }, { 0 }, { 1, 0 } },
.index = { { 0, 0 }, { 0 }, { 1, 1 } },
.config_map = { 4, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_SCE },
.reorder_map = { 2, 0, 1, 4, 5, 3 },
.num_ele = { 2, 1, 1, 0 },
.pairing = { { 1, 0 }, { 1 }, { 0 }, },
.index = { { 0, 0 }, { 1 }, { 1 } },
.config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE },
.reorder_map = { 0, 1, 2, 3, 4, 5 },
},
{
.layout = AV_CHANNEL_LAYOUT_6POINT0_FRONT,
.num_ele = { 2, 0, 1, 0 },
.pairing = { { 1, 1 }, { 0 }, { 1 } },
.index = { { 0, 1 }, { 0 }, { 2 }, },
.num_ele = { 2, 1, 0, 0 },
.pairing = { { 1, 1 }, { 1 } },
.index = { { 1, 0 }, { 2 }, },
.config_map = { 3, TYPE_CPE, TYPE_CPE, TYPE_CPE, },
.reorder_map = { 2, 3, 0, 1, 4, 5 },
.reorder_map = { 0, 1, 2, 3, 4, 5 },
},
{
.layout = AV_CHANNEL_LAYOUT_HEXAGONAL,
.num_ele = { 2, 0, 2, 0 },
.pairing = { { 0, 1 }, { 0 }, { 1, 0 } },
.index = { { 0, 0 }, { 0 }, { 1, 1 } },
.config_map = { 4, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_SCE },
.reorder_map = { 2, 0, 1, 3, 4, 5 },
.pairing = { { 1, 0 },{ 0 },{ 1, 0 }, },
.index = { { 0, 0 },{ 0 },{ 1, 1 } },
.config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE, },
.reorder_map = { 0, 1, 2, 3, 4, 5 },
},
{
.layout = AV_CHANNEL_LAYOUT_6POINT1,
.num_ele = { 2, 0, 2, 1 },
.pairing = { { 0, 1 }, { 0 }, { 1, 0 }, },
.index = { { 0, 0 }, { 0 }, { 1, 1 }, { 0 } },
.config_map = { 5, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_SCE, TYPE_LFE },
.reorder_map = { 2, 0, 1, 5, 6, 4, 3 },
.num_ele = { 2, 1, 2, 0 },
.pairing = { { 1, 0 },{ 0 },{ 1, 0 }, },
.index = { { 0, 0 },{ 1 },{ 1, 2 } },
.config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_SCE },
.reorder_map = { 0, 1, 2, 3, 4, 5, 6 },
},
{
.layout = AV_CHANNEL_LAYOUT_6POINT1_BACK,
.num_ele = { 2, 0, 2, 1 },
.pairing = { { 0, 1 },{ 0 },{ 1, 0 }, },
.index = { { 0, 0 },{ 0 },{ 1, 1 },{ 0 } },
.config_map = { 5, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_SCE, TYPE_LFE },
.reorder_map = { 2, 0, 1, 4, 5, 6, 3 },
.num_ele = { 2, 1, 2, 0 },
.pairing = { { 1, 0 }, { 0 }, { 1, 0 }, },
.index = { { 0, 0 }, { 1 }, { 1, 2 } },
.config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_SCE },
.reorder_map = { 0, 1, 2, 3, 4, 5, 6 },
},
{
.layout = AV_CHANNEL_LAYOUT_6POINT1_FRONT,
.num_ele = { 2, 0, 1, 1 },
.pairing = { { 1, 1 }, { 0 }, { 1 }, },
.index = { { 0, 1 }, { 0 }, { 2 }, { 0 }, },
.config_map = { 4, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_LFE, },
.reorder_map = { 3, 4, 0, 1, 5, 6, 2 },
.num_ele = { 2, 1, 2, 0 },
.pairing = { { 1, 0 }, { 0 }, { 1, 0 }, },
.index = { { 0, 0 }, { 1 }, { 1, 2 } },
.config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_SCE },
.reorder_map = { 0, 1, 2, 3, 4, 5, 6 },
},
{
.layout = AV_CHANNEL_LAYOUT_7POINT0,
.num_ele = { 2, 0, 2, 0 },
.pairing = { { 0, 1 }, { 0 }, { 1, 1 }, },
.index = { { 0, 0 }, { 0 }, { 2, 1 }, },
.config_map = { 4, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE },
.reorder_map = { 2, 0, 1, 3, 4, 5, 6 },
.num_ele = { 2, 1, 1, 0 },
.pairing = { { 1, 0 }, { 1 }, { 1 }, },
.index = { { 0, 0 }, { 1 }, { 2 }, },
.config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE },
.reorder_map = { 0, 1, 2, 3, 4, 5, 6 },
},
{
.layout = AV_CHANNEL_LAYOUT_7POINT0_FRONT,
.num_ele = { 3, 0, 1, 0 },
.pairing = { { 0, 1, 1 }, { 0 }, { 1 }, },
.index = { { 0, 0, 1 }, { 0 }, { 2 }, },
.config_map = { 4, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE },
.reorder_map = { 2, 3, 4, 0, 1, 5, 6 },
.num_ele = { 2, 1, 1, 0 },
.pairing = { { 1, 0 }, { 1 }, { 1 }, },
.index = { { 0, 0 }, { 1 }, { 2 }, },
.config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE },
.reorder_map = { 0, 1, 2, 3, 4, 5, 6 },
},
{
.layout = AV_CHANNEL_LAYOUT_7POINT1,
.num_ele = { 2, 0, 2, 1 },
.pairing = { { 0, 1 }, { 0 }, { 1, 1 }, },
.index = { { 0, 0 }, { 0 }, { 2, 1 }, { 0 } },
.config_map = { 5, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_LFE },
.reorder_map = { 2, 0, 1, 4, 5, 6, 7, 3 },
.num_ele = { 2, 1, 2, 0 },
.pairing = { { 1, 0 }, { 0 }, { 1, 1 }, },
.index = { { 0, 0 }, { 1 }, { 1, 2 }, { 0 } },
.config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_CPE },
.reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 },
},
{
.layout = AV_CHANNEL_LAYOUT_7POINT1_WIDE,
.num_ele = { 3, 0, 1, 1 },
.pairing = { { 0, 1, 1 }, { 0 }, { 1 }, },
.index = { { 0, 0, 1 }, { 0 }, { 2 }, { 0 }, },
.config_map = { 5, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_LFE },
.reorder_map = { 2, 4, 5, 0, 1, 6, 7, 3 },
.num_ele = { 2, 1, 2, 0 },
.pairing = { { 1, 0 }, { 0 },{ 1, 1 }, },
.index = { { 0, 0 }, { 1 }, { 1, 2 }, { 0 } },
.config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_CPE },
.reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 },
},
{
.layout = AV_CHANNEL_LAYOUT_7POINT1_WIDE_BACK,
.num_ele = { 3, 0, 1, 1 },
.pairing = { { 0, 1, 1 }, { 0 }, { 1 } },
.index = { { 0, 0, 1 }, { 0 }, { 2 }, { 0 } },
.config_map = { 5, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_LFE },
.reorder_map = { 2, 6, 7, 0, 1, 4, 5, 3 },
.num_ele = { 2, 1, 2, 0 },
.pairing = { { 1, 0 }, { 0 }, { 1, 1 }, },
.index = { { 0, 0 }, { 1 }, { 1, 2 }, { 0 } },
.config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_CPE },
.reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 },
},
{
.layout = AV_CHANNEL_LAYOUT_OCTAGONAL,
.num_ele = { 2, 0, 3, 0 },
.pairing = { { 0, 1 }, { 0 }, { 1, 1, 0 }, },
.index = { { 0, 0 }, { 0 }, { 1, 2, 1 }, },
.config_map = { 5, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_SCE },
.reorder_map = { 2, 0, 1, 6, 7, 3, 4, 5 },
.num_ele = { 2, 1, 2, 0 },
.pairing = { { 1, 0 }, { 1 }, { 1, 0 }, },
.index = { { 0, 0 }, { 1 }, { 2, 1 } },
.config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_SCE },
.reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 },
},
{ /* Meant for order 2/mixed ambisonics */
.layout = { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 9,
.u.mask = AV_CH_LAYOUT_OCTAGONAL | AV_CH_TOP_CENTER },
.num_ele = { 2, 2, 2, 0 },
.pairing = { { 1, 0 }, { 1, 0 }, { 1, 0 }, },
.index = { { 0, 0 }, { 1, 1 }, { 2, 2 } },
.config_map = { 6, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE },
.reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7, 8 },
},
{ /* Meant for order 2/mixed ambisonics */
.layout = { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 10,
.u.mask = AV_CH_LAYOUT_6POINT0_FRONT | AV_CH_BACK_CENTER |
AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT | AV_CH_TOP_CENTER },
.num_ele = { 2, 2, 2, 0 },
.pairing = { { 1, 1 }, { 1, 0 }, { 1, 0 }, },
.index = { { 0, 1 }, { 2, 0 }, { 3, 1 } },
.config_map = { 6, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE },
.reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
},
{
.layout = AV_CHANNEL_LAYOUT_HEXADECAGONAL,
.num_ele = { 4, 2, 4, 0 },
.pairing = { { 1, 0, 1, 0 }, { 1, 1 }, { 1, 0, 1, 0 }, },
.index = { { 0, 0, 1, 1 }, { 2, 3 }, { 4, 2, 5, 3 } },
.config_map = { 10, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE },
.reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
},
};
@@ -339,10 +366,11 @@ static void put_pce(PutBitContext *pb, AVCodecContext *avctx)
* Make AAC audio config object.
* @see 1.6.2.1 "Syntax - AudioSpecificConfig"
*/
static int put_audio_specific_config(AVCodecContext *avctx, int chcfg)
static int put_audio_specific_config(AVCodecContext *avctx)
{
PutBitContext pb;
AACEncContext *s = avctx->priv_data;
int channels = (!s->needs_pce)*(s->channels - (s->channels == 8 ? 1 : 0));
const int max_size = 32;
avctx->extradata = av_mallocz(max_size);
@@ -352,7 +380,7 @@ static int put_audio_specific_config(AVCodecContext *avctx, int chcfg)
init_put_bits(&pb, avctx->extradata, max_size);
put_bits(&pb, 5, s->profile+1); //profile
put_bits(&pb, 4, s->samplerate_index); //sample rate index
put_bits(&pb, 4, chcfg);
put_bits(&pb, 4, channels);
//GASpecificConfig
put_bits(&pb, 1, 0); //frame length - 1024 samples
put_bits(&pb, 1, 0); //does not depend on core coder
@@ -577,222 +605,6 @@ static void apply_intensity_stereo(ChannelElement *cpe)
}
}
/* Intensity stereo is only allowed when its irreducible image error */
#define NMR_IS_IMG_GATE 0.5f
/* Frequency in Hz for the lower limit of intensity stereo */
#define NMR_IS_LOW_LIMIT 6100
/* Rate ceiling (bits/sample/channel) above which intensity is skipped, ~145kbps */
#define NMR_IS_MAXBPS 1.52f
/* The rate ceiling is lifted on hard-to-code frames. The signal is the bit
* reservoir going into deficit: a negative fill means the trellis is spending
* more than the nominal rate to hold quality (operating lambda has climbed). */
#define NMR_IS_FILLGAIN 0.27f
#define NMR_IS_FILLMAX 0.40f
/* M/S thresholds: a band is recoded as mid+side when the side is negligible */
#define NMR_MS_EQUIV 0.01f
#define NMR_MS_MASK 0.0f
/* PNS-stereo decorrelation gate: a band may be noise-substituted in a CPE only if its
* side energy is at least this fraction of its mid energy, i.e. the image is genuinely
* wide (channels decorrelated). PNS renders uncorrelated noise per channel, so it only
* preserves the image on already-wide bands; a much stricter bar than I/S (which can
* collapse correlated bands). Lower = more PNS / more imaging risk. */
#define NMR_PNS_STEREO_DECORR 0.6f
/* Recode one band's window group as mid+side in place, updating the psy band
* energies/thresholds to the M/S spectra. The threshold is halved as a coarse guard
* against L/R unmasking of the independently-quantized M/S noise (M/S is a lossless
* rotation but lossy coding). Used for the M/S decision and the intensity fallback. */
static void nmr_apply_ms_band(AACEncContext *s, ChannelElement *cpe,
int w, int g, int start, int len, int gl)
{
SingleChannelElement *sce0 = &cpe->ch[0];
SingleChannelElement *sce1 = &cpe->ch[1];
cpe->ms_mask[w*16+g] = 1;
for (int w2 = 0; w2 < gl; w2++) {
FFPsyBand *b0 = &s->psy.ch[s->cur_channel+0].psy_bands[(w+w2)*16+g];
FFPsyBand *b1 = &s->psy.ch[s->cur_channel+1].psy_bands[(w+w2)*16+g];
float *L = sce0->coeffs + start + (w+w2)*128;
float *R = sce1->coeffs + start + (w+w2)*128;
float em = 0.0f, es = 0.0f;
for (int i = 0; i < len; i++) {
float m = (L[i] + R[i]) * 0.5f;
R[i] = m - R[i]; L[i] = m;
em += L[i]*L[i]; es += R[i]*R[i];
}
b0->threshold = b1->threshold = FFMIN(b0->threshold, b1->threshold) * 0.5f;
b0->energy = em; b1->energy = es;
}
}
/* Intensity-stereo perceptual test for one band's window group: collapse the pair
* to a single carrier (L + p*R)*scale that the decoder rescales per channel, and
* check that the irreducible image error, which no bit budget can reduce, is
* masked in both channels. On success returns 1 and fills the carrier scale, the
* decoder's R/carrier ratio sr_, and the phase p. The caller restricts this to HF
* bands with energy in both channels. */
static int nmr_is_image_masked(AACEncContext *s, ChannelElement *cpe,
int w, int g, int start, int len, int gl,
float ener0, float ener1, float dot,
float minthr0, float minthr1,
float *scale_out, float *sr_out, int *p_out)
{
int p = dot >= 0.0f ? 1 : -1;
float ener01 = ener0 + ener1 + 2*p*dot; /* energy of L + p*R */
if (ener01 <= FLT_MIN)
return 0;
float scale = sqrtf(ener0 / ener01); /* carrier = (L + p*R)*scale */
float sr_ = sqrtf(ener1 / ener0); /* decoder: R = p*sr_*carrier */
float img0 = 0.0f, img1 = 0.0f;
for (int w2 = 0; w2 < gl; w2++) {
const float *L = cpe->ch[0].coeffs + start + (w+w2)*128;
const float *R = cpe->ch[1].coeffs + start + (w+w2)*128;
for (int i = 0; i < len; i++) {
float c = (L[i] + p*R[i]) * scale;
float dl = L[i] - c, dr = R[i] - p*sr_*c;
img0 += dl*dl; img1 += dr*dr;
}
}
if (img0 >= NMR_IS_IMG_GATE * minthr0 * gl ||
img1 >= NMR_IS_IMG_GATE * minthr1 * gl)
return 0;
*scale_out = scale; *sr_out = sr_; *p_out = p;
return 1;
}
/* Recode one band's window group as intensity stereo in place: replace L with the
* carrier, zero R, signal the phase via the side channel's band type, and fold the
* pair's masking into the surviving (carrier) channel. */
static void nmr_apply_is_band(AACEncContext *s, ChannelElement *cpe,
int w, int g, int start, int len, int gl,
float scale, float sr_, int p,
float ener0, float ener1)
{
cpe->is_mask[w*16+g] = 1;
cpe->ch[0].is_ener[w*16+g] = scale;
cpe->ch[1].is_ener[w*16+g] = ener0 / ener1;
cpe->ch[1].band_type[w*16+g] = p > 0 ? INTENSITY_BT : INTENSITY_BT2;
for (int w2 = 0; w2 < gl; w2++) {
FFPsyBand *b0 = &s->psy.ch[s->cur_channel+0].psy_bands[(w+w2)*16+g];
FFPsyBand *b1 = &s->psy.ch[s->cur_channel+1].psy_bands[(w+w2)*16+g];
float *L = cpe->ch[0].coeffs + start + (w+w2)*128;
float *R = cpe->ch[1].coeffs + start + (w+w2)*128;
float ec = 0.0f;
for (int i = 0; i < len; i++) {
L[i] = (L[i] + p*R[i]) * scale;
R[i] = 0.0f;
ec += L[i]*L[i];
}
b0->threshold = FFMIN(b0->threshold, b1->threshold / FFMAX(sr_*sr_, 1e-9f));
b0->energy = ec; b1->energy = 0.0f;
}
}
/*
* Per-band stereo-mode decision (L/R vs M/S vs intensity) for the NMR coder,
* made before quantization from the psychoacoustic model alone, so the
* quantizer search allocates natively on the spectra that are actually coded.
*/
static void nmr_decide_stereo(AACEncContext *s, ChannelElement *cpe)
{
SingleChannelElement *sce0 = &cpe->ch[0];
SingleChannelElement *sce1 = &cpe->ch[1];
IndividualChannelStream *ics = &sce0->ics;
const AVCodecContext *avctx = s->psy.avctx;
const float freq_mult = avctx->sample_rate / (1024.0f / ics->num_windows) / 2.0f;
const float bps = avctx->bit_rate > 0 ?
(float)avctx->bit_rate / avctx->sample_rate / avctx->ch_layout.nb_channels : 0.0f;
int is_count = 0;
/* Stereo decision, with no bitrate dependence. Start from full L/R and depart from
* it only where the change is inaudible. M/S and I/S differ in what they trade:
* M/S recodes the pair as mid+side -- an invertible rotation, but the M and S
* are quantized independently, so it is lossy coding whose noise un-mixes
* back to L/R. Used where it barely changes the result (the side is
* negligible vs the mid, so it is ~equivalent to L/R at the same rate) --
* OR where the doubled side energy is masked.
* I/S drops the side phase and keeps its energy, where the residual image error
* is masked. Used for the decorrelated HF that M/S cannot help.
* Both tests are content/perceptual and frame-stable, so the image holds. */
/* I/S rate gate: eligible at/below ~128 kbps, with the ceiling lifted on hard
* frames (bit reservoir in deficit) so a starved high-rate passage can still
* call on intensity. Where an I/S candidate is found but IS is not eligible, fall
* back to M/S: not free, but ~equivalent to L/R there and it lets the energy
* compact into the mid. */
const float rate_frame = avctx->bit_rate * 1024.0f / FFMAX(avctx->sample_rate, 1);
const float deficit = (s->nmr && rate_frame > 0.0f)
? FFMAX(0.0f, -(float)s->nmr->rc_fill / rate_frame) : 0.0f;
const float is_bonus = FFMIN(NMR_IS_FILLMAX, NMR_IS_FILLGAIN * deficit);
const int allow_is = s->options.intensity_stereo && bps < NMR_IS_MAXBPS + is_bonus;
for (int w = 0; w < ics->num_windows; w += ics->group_len[w]) {
int start = 0;
for (int g = 0; g < ics->num_swb; start += ics->swb_sizes[g++]) {
int len = ics->swb_sizes[g], gl = ics->group_len[w];
float ener0 = 0.0f, ener1 = 0.0f, dot = 0.0f, es_tot = 0.0f, em_tot = 0.0f;
float minthr0 = FLT_MAX, minthr1 = FLT_MAX;
cpe->is_mask[w*16+g] = 0;
cpe->ms_mask[w*16+g] = 0;
for (int w2 = 0; w2 < gl; w2++) {
FFPsyBand *b0 = &s->psy.ch[s->cur_channel+0].psy_bands[(w+w2)*16+g];
FFPsyBand *b1 = &s->psy.ch[s->cur_channel+1].psy_bands[(w+w2)*16+g];
const float *L = sce0->coeffs + start + (w+w2)*128;
const float *R = sce1->coeffs + start + (w+w2)*128;
float el = 0.0f, er = 0.0f, em = 0.0f, es = 0.0f, d = 0.0f;
for (int i = 0; i < len; i++) {
float m = (L[i] + R[i]) * 0.5f;
float sv = m - R[i];
el += L[i]*L[i]; er += R[i]*R[i];
em += m*m; es += sv*sv; d += L[i]*R[i];
}
ener0 += el; ener1 += er; dot += d; es_tot += es; em_tot += em;
minthr0 = FFMIN(minthr0, b0->threshold);
minthr1 = FFMIN(minthr1, b1->threshold);
}
float thr_g = FFMIN(minthr0, minthr1) * gl; /* group masking budget */
/* PNS-stereo reservation. Reserve a band for noise substitution only if it
* is noise-like in both channels (intersected can_pns) and clearly
* decorrelated (wide image). */
if (cpe->ch[0].can_pns[w*16+g] && cpe->ch[1].can_pns[w*16+g] &&
es_tot > NMR_PNS_STEREO_DECORR * em_tot)
continue;
cpe->ch[0].can_pns[w*16+g] = cpe->ch[1].can_pns[w*16+g] = 0;
int ms_ok = s->options.mid_side &&
(s->options.mid_side == 1 ||
es_tot < NMR_MS_EQUIV * em_tot ||
es_tot < NMR_MS_MASK * thr_g);
float scale, sr_; int p;
int is_ok = !ms_ok &&
start * freq_mult > NMR_IS_LOW_LIMIT &&
ener0 > FLT_MIN && ener1 > FLT_MIN &&
nmr_is_image_masked(s, cpe, w, g, start, len, gl,
ener0, ener1, dot, minthr0, minthr1,
&scale, &sr_, &p);
if (ms_ok) {
nmr_apply_ms_band(s, cpe, w, g, start, len, gl);
} else if (is_ok && allow_is) {
nmr_apply_is_band(s, cpe, w, g, start, len, gl,
scale, sr_, p, ener0, ener1);
is_count++;
} else if (is_ok && s->options.mid_side) {
nmr_apply_ms_band(s, cpe, w, g, start, len, gl);
}
/* else: keep full L/R stereo */
}
}
cpe->is_mode = !!is_count;
}
static void apply_mid_side_stereo(ChannelElement *cpe)
{
int w, w2, g, i;
@@ -1166,6 +978,12 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
s->psy.bitres.alloc /= chans;
}
s->cur_type = tag;
for (ch = 0; ch < chans; ch++) {
s->cur_channel = start_ch + ch;
if (s->options.pns && s->coder->mark_pns)
s->coder->mark_pns(s, avctx, &cpe->ch[ch]);
s->coder->search_for_quantizers(avctx, s, &cpe->ch[ch], s->lambda);
}
if (chans > 1
&& wi[0].window_type[0] == wi[1].window_type[0]
&& wi[0].window_shape == wi[1].window_shape) {
@@ -1178,75 +996,26 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
}
}
}
const int use_tns = s->options.tns && s->coder->search_for_tns &&
s->coder->apply_tns_filt;
/* The NMR coder rate-controls itself and never re-quantizes, so TNS must run
* before the quantizer */
const int tns_first = s->options.coder == AAC_CODER_NMR;
if (tns_first && use_tns) {
for (ch = 0; ch < chans; ch++) {
sce = &cpe->ch[ch];
s->cur_channel = start_ch + ch;
/* mono: mark_pns before TNS so the region cap sees PNS bands. Stereo
* PNS is marked in its own block (below) after the stereo decision. */
if (chans == 1 && s->options.pns && s->coder->mark_pns)
s->coder->mark_pns(s, avctx, sce);
s->coder->search_for_tns(s, sce);
s->coder->apply_tns_filt(s, sce);
if (sce->tns.present)
tns_mode = 1;
}
}
/* NMR stereo PNS (imaging-safe). Mark each channel's noise-like bands on the
* original L/R psy, then keep PNS only where BOTH channels are noise-like. */
if (chans == 2 && cpe->common_window && tns_first &&
s->options.pns && s->coder->mark_pns) {
s->cur_channel = start_ch; s->coder->mark_pns(s, avctx, &cpe->ch[0]);
s->cur_channel = start_ch + 1; s->coder->mark_pns(s, avctx, &cpe->ch[1]);
for (int b = 0; b < 128; b++)
if (!cpe->ch[0].can_pns[b] || !cpe->ch[1].can_pns[b])
cpe->ch[0].can_pns[b] = cpe->ch[1].can_pns[b] = 0;
}
/* The NMR coder decides I/S and M/S BEFORE quantization, from the psy model,
* and the trellis then allocates natively on the coeffs actually coded. */
if (chans == 2 && cpe->common_window && s->options.coder == AAC_CODER_NMR &&
(s->options.mid_side || s->options.intensity_stereo)) {
s->cur_channel = start_ch;
nmr_decide_stereo(s, cpe);
}
for (ch = 0; ch < chans; ch++) {
s->cur_channel = start_ch + ch;
/* NMR PNS is mono-only */
if (s->options.pns && s->coder->mark_pns && !tns_first)
s->coder->mark_pns(s, avctx, &cpe->ch[ch]);
s->coder->search_for_quantizers(avctx, s, &cpe->ch[ch], s->lambda);
}
for (ch = 0; ch < chans; ch++) { /* TNS (non-NMR) and PNS */
for (ch = 0; ch < chans; ch++) { /* TNS and PNS */
sce = &cpe->ch[ch];
s->cur_channel = start_ch + ch;
if (!tns_first && use_tns) {
if (s->options.tns && s->coder->search_for_tns)
s->coder->search_for_tns(s, sce);
if (s->options.tns && s->coder->apply_tns_filt)
s->coder->apply_tns_filt(s, sce);
if (sce->tns.present)
tns_mode = 1;
}
if (sce->tns.present)
tns_mode = 1;
if (s->options.pns && s->coder->search_for_pns)
s->coder->search_for_pns(s, avctx, sce);
}
s->cur_channel = start_ch;
if (s->options.intensity_stereo) { /* Intensity Stereo */
if (s->options.coder != AAC_CODER_NMR) { /* NMR: decided pre-search */
if (s->coder->search_for_is)
s->coder->search_for_is(s, avctx, cpe);
apply_intensity_stereo(cpe);
}
if (s->coder->search_for_is)
s->coder->search_for_is(s, avctx, cpe);
if (cpe->is_mode) is_mode = 1;
apply_intensity_stereo(cpe);
}
if (s->options.mid_side && s->options.coder != AAC_CODER_NMR) { /* Mid/Side stereo */
if (s->options.mid_side) { /* Mid/Side stereo */
if (s->options.mid_side == -1 && s->coder->search_for_ms)
s->coder->search_for_ms(s, cpe);
else if (cpe->common_window)
@@ -1274,19 +1043,11 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
break;
}
frame_bits = put_bits_count(&s->pb);
/* The NMR coder rate-controls itself (global-lambda reservoir servo):
* per-frame bits intentionally float around the nominal rate, so skip
* the lambda rate loop and only intervene on a hard overflow. */
if (s->options.coder == AAC_CODER_NMR && avctx->bit_rate_tolerance != 0 &&
frame_bits < 6144 * s->channels - 3)
break;
/* rate control stuff
* allow between the nominal bitrate, and what psy's bit reservoir says to target
* but drift towards the nominal bitrate always
*/
frame_bits = put_bits_count(&s->pb);
rate_bits = avctx->bit_rate * 1024 / avctx->sample_rate;
rate_bits = FFMIN(rate_bits, 6144 * s->channels - 3);
too_many_bits = FFMAX(target_bits, rate_bits);
@@ -1350,80 +1111,18 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
}
} while (1);
/* tool-usage stats over the final per-band decisions of this frame */
for (i = 0; i < s->chan_map[0]; i++) {
int etag = s->chan_map[i + 1], echans = etag == TYPE_CPE ? 2 : 1;
ChannelElement *ce = &s->cpe[i];
IndividualChannelStream *ics = &ce->ch[0].ics;
for (ch = 0; ch < echans; ch++) { /* per-channel frame stats */
int is_short = ce->ch[ch].ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE;
s->stat_chans++;
if (is_short)
s->stat_short++;
if (ce->ch[ch].tns.present) {
if (is_short) s->stat_tns_short++;
else s->stat_tns_long++;
}
}
for (w = 0; w < ics->num_windows; w += ics->group_len[w]) {
for (int g = 0; g < ics->num_swb; g++) {
int idx = w*16 + g, coded = 0;
for (ch = 0; ch < echans; ch++) {
SingleChannelElement *sce = &ce->ch[ch];
if (sce->zeroes[idx] && sce->band_type[idx] == 0)
continue;
s->stat_ch_bands++;
if (sce->band_type[idx] == NOISE_BT)
s->stat_pns++;
coded = 1;
}
if (etag == TYPE_CPE && coded) {
s->stat_cpe_bands++;
if (ce->ms_mask[idx]) s->stat_ms++;
if (ce->is_mask[idx]) s->stat_is++;
}
}
}
}
put_bits(&s->pb, 3, TYPE_END);
flush_put_bits(&s->pb);
s->last_frame_pb_count = put_bits_count(&s->pb);
/* NMR rate accounting: how many bits the frame really took beyond what the
* trellis counted; feeds the next frame's budget correction */
if (s->nmr) {
int counted = 0;
for (i = 0; i < s->channels; i++)
counted += s->nmr->counted[i];
if (counted > 0) {
float side = (float)s->last_frame_pb_count - counted;
if (s->nmr->side_inited) {
s->nmr->side_ema += 0.125f * (side - s->nmr->side_ema);
} else {
s->nmr->side_ema = side;
s->nmr->side_inited = 1;
}
}
}
avpkt->size = put_bytes_output(&s->pb);
s->lambda_sum += (s->nmr && s->nmr->lam_rc > 0.0f) ? s->nmr->lam_rc : s->lambda;
s->lambda_sum += s->lambda;
s->lambda_count++;
ff_af_queue_remove(&s->afq, avctx->frame_size, &avpkt->pts,
&avpkt->duration);
int discard_padding = avctx->frame_size - ff_samples_from_time_base(avctx, avpkt->duration);
if (discard_padding > 0) {
uint8_t *side_data =
av_packet_new_side_data(avpkt, AV_PKT_DATA_SKIP_SAMPLES, 10);
if (!side_data)
return AVERROR(ENOMEM);
AV_WL32(side_data + 4, discard_padding);
}
avpkt->flags |= AV_PKT_FLAG_KEY;
*got_packet_ptr = 1;
@@ -1434,15 +1133,7 @@ static av_cold int aac_encode_end(AVCodecContext *avctx)
{
AACEncContext *s = avctx->priv_data;
av_log(avctx, AV_LOG_INFO,
"Qavg: %.3f Tr: %.1f%% TNS(L): %.1f%% TNS(S): %.1f%% M/S: %.1f%% I/S: %.1f%% PNS: %.1f%%\n",
s->lambda_count ? s->lambda_sum / s->lambda_count : NAN,
s->stat_chans ? 100.0 * s->stat_short / s->stat_chans : 0.0,
s->stat_chans - s->stat_short ? 100.0 * s->stat_tns_long / (s->stat_chans - s->stat_short) : 0.0,
s->stat_short ? 100.0 * s->stat_tns_short / s->stat_short : 0.0,
s->stat_cpe_bands ? 100.0 * s->stat_ms / s->stat_cpe_bands : 0.0,
s->stat_cpe_bands ? 100.0 * s->stat_is / s->stat_cpe_bands : 0.0,
s->stat_ch_bands ? 100.0 * s->stat_pns / s->stat_ch_bands : 0.0);
av_log(avctx, AV_LOG_INFO, "Qavg: %.3f\n", s->lambda_count ? s->lambda_sum / s->lambda_count : NAN);
av_tx_uninit(&s->mdct1024);
av_tx_uninit(&s->mdct128);
@@ -1451,7 +1142,6 @@ static av_cold int aac_encode_end(AVCodecContext *avctx)
av_freep(&s->buffer.samples);
av_freep(&s->cpe);
av_freep(&s->fdsp);
av_freep(&s->nmr);
ff_af_queue_close(&s->afq);
return 0;
}
@@ -1485,12 +1175,6 @@ static av_cold int alloc_buffers(AVCodecContext *avctx, AACEncContext *s)
for(ch = 0; ch < s->channels; ch++)
s->planar_samples[ch] = s->buffer.samples + 3 * 1024 * ch;
if (s->options.coder == AAC_CODER_NMR) {
s->nmr = av_mallocz(sizeof(*s->nmr));
if (!s->nmr)
return AVERROR(ENOMEM);
}
return 0;
}
@@ -1498,7 +1182,6 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
{
AACEncContext *s = avctx->priv_data;
int i, ret = 0;
int chcfg;
const uint8_t *sizes[2];
uint8_t grouping[AAC_MAX_CHANNELS];
int lengths[2];
@@ -1513,8 +1196,8 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
s->channels = avctx->ch_layout.nb_channels;
s->needs_pce = 1;
for (chcfg = 1; chcfg < FF_ARRAY_ELEMS(aac_normal_chan_layouts); chcfg++) {
if (!av_channel_layout_compare(&avctx->ch_layout, &aac_normal_chan_layouts[chcfg])) {
for (i = 0; i < FF_ARRAY_ELEMS(aac_normal_chan_layouts); i++) {
if (!av_channel_layout_compare(&avctx->ch_layout, &aac_normal_chan_layouts[i])) {
s->needs_pce = s->options.pce;
break;
}
@@ -1534,10 +1217,9 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
s->pce = aac_pce_configs[i];
s->reorder_map = s->pce.reorder_map;
s->chan_map = s->pce.config_map;
chcfg = 0;
} else {
s->reorder_map = aac_chan_maps[chcfg - 1];
s->chan_map = aac_chan_configs[chcfg - 1];
s->reorder_map = aac_chan_maps[s->channels - 1];
s->chan_map = aac_chan_configs[s->channels - 1];
}
if (!avctx->bit_rate) {
@@ -1587,34 +1269,6 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
if (s->channels > 3)
s->options.mid_side = 0;
/* Coding bandwidth, fixed at init time */
if (avctx->cutoff > 0) {
s->bandwidth = avctx->cutoff;
} else {
int frame_br = (avctx->flags & AV_CODEC_FLAG_QSCALE) ?
(avctx->bit_rate / 2.0f * (s->lambda / 120.f) * 1.5f) :
(avctx->bit_rate / avctx->ch_layout.nb_channels);
/* For NMR, the rate to bandwidth conversion was tuned to maximize metrics
* over a variable cutoff x bitrate combo */
if (s->options.coder == AAC_CODER_NMR && frame_br >= 32000) {
static const int rates[] = { 32000, 48000, 64000, 96000, 192000 };
static const int bws[] = { 14000, 15000, 16000, 18000, 20000 };
int bw_i = 0;
for (; bw_i < FF_ARRAY_ELEMS(rates) - 2 && frame_br > rates[bw_i + 1]; bw_i++);
s->bandwidth = bws[bw_i] + (int)((int64_t)(bws[bw_i + 1] - bws[bw_i]) *
(frame_br - rates[bw_i]) / (rates[bw_i + 1] - rates[bw_i]));
s->bandwidth = FFMIN3(s->bandwidth, 22000, avctx->sample_rate / 2);
} else {
if (s->options.pns || s->options.intensity_stereo)
frame_br *= 1.15f;
s->bandwidth = FFMAX(3000, AAC_CUTOFF_FROM_BITRATE(frame_br, 1,
avctx->sample_rate));
}
s->bandwidth = FFMIN(FFMAX(s->bandwidth, 8000), avctx->sample_rate / 2);
}
// Initialize static tables
ff_aac_float_common_init();
@@ -1624,7 +1278,7 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
if ((ret = alloc_buffers(avctx, s)) < 0)
return ret;
if ((ret = put_audio_specific_config(avctx, chcfg)))
if ((ret = put_audio_specific_config(avctx)))
return ret;
sizes[0] = ff_aac_swb_size_1024[s->samplerate_index];
@@ -1634,7 +1288,7 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
for (i = 0; i < s->chan_map[0]; i++)
grouping[i] = s->chan_map[i + 1] == TYPE_CPE;
if ((ret = ff_psy_init(&s->psy, avctx, 2, sizes, lengths,
s->chan_map[0], grouping, s->bandwidth)) < 0)
s->chan_map[0], grouping)) < 0)
return ret;
ff_lpc_init(&s->lpc, 2*avctx->frame_size, TNS_MAX_ORDER, FF_LPC_TYPE_LEVINSON);
s->random_state = 0x1f2e3d4c;
@@ -1648,16 +1302,14 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
#define AACENC_FLAGS AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM
static const AVOption aacenc_options[] = {
{"aac_coder", "Coding algorithm", offsetof(AACEncContext, options.coder), AV_OPT_TYPE_INT, {.i64 = AAC_CODER_NMR}, 0, AAC_CODER_NB-1, AACENC_FLAGS, .unit = "coder"},
{"aac_coder", "Coding algorithm", offsetof(AACEncContext, options.coder), AV_OPT_TYPE_INT, {.i64 = AAC_CODER_TWOLOOP}, 0, AAC_CODER_NB-1, AACENC_FLAGS, .unit = "coder"},
{"twoloop", "Two loop searching method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_TWOLOOP}, INT_MIN, INT_MAX, AACENC_FLAGS, .unit = "coder"},
{"fast", "Fast search", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAST}, INT_MIN, INT_MAX, AACENC_FLAGS, .unit = "coder"},
{"nmr", "Noise-to-mask ratio scalefactor trellis", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_NMR}, INT_MIN, INT_MAX, AACENC_FLAGS, .unit = "coder"},
{"aac_ms", "Force M/S stereo coding", offsetof(AACEncContext, options.mid_side), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AACENC_FLAGS},
{"aac_is", "Intensity stereo coding", offsetof(AACEncContext, options.intensity_stereo), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS},
{"aac_pns", "Perceptual noise substitution", offsetof(AACEncContext, options.pns), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS},
{"aac_tns", "Temporal noise shaping", offsetof(AACEncContext, options.tns), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS},
{"aac_pce", "Forces the use of PCEs", offsetof(AACEncContext, options.pce), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS},
{"aac_nmr_speed", "NMR coder speed level: 0 = slowest/best, higher trades quality for speed", offsetof(AACEncContext, options.nmr_speed), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 4, AACENC_FLAGS},
FF_AAC_PROFILE_OPTS
{NULL}
};
+3 -35
View File
@@ -44,7 +44,6 @@
typedef enum AACCoder {
AAC_CODER_TWOLOOP,
AAC_CODER_FAST,
AAC_CODER_NMR,
AAC_CODER_NB,
}AACCoder;
@@ -70,7 +69,6 @@ typedef struct AACEncOptions {
int pce;
int mid_side;
int intensity_stereo;
int nmr_speed; ///< NMR coder speed level: 0 = slowest/best, higher is faster
} AACEncOptions;
/**
@@ -167,33 +165,11 @@ typedef struct AACQuantizeBandCostCacheEntry {
uint16_t generation;
} AACQuantizeBandCostCacheEntry;
/** per-band scalefactor candidates above the finest codeable sf (NMR coder) */
#define NMR_NCAND 96
/**
* NMR coder per-band candidate cost curves (~96 KiB) and rate-control carry-over
*/
typedef struct AACNMRCurves {
float nd[128][NMR_NCAND]; ///< dist / threshold per candidate
int nb[128][NMR_NCAND]; ///< spectral bits per candidate
float lam[16]; ///< per-channel operating lambda of the previous frame, 0 = none yet
int counted[16]; ///< per-channel bits the trellis accounted for in the last solve
float side_ema; ///< running estimate of real-minus-counted bits per frame
int side_inited; ///< side_ema holds a measurement
int64_t rc_frame_num; ///< frame the reservoir was last advanced for
float lam_rc; ///< global-lambda rate control: operating lambda, 0 until bootstrapped
int rc_fill; ///< virtual bit reservoir fill, + = bits saved vs nominal
int frames_since_short; ///< long-block frames since the last short run (the "gap"): large = isolated transient
int prev_was_short; ///< previous frame was a short block (for run-start detection)
float run_burst; ///< transient bit-burst factor, set at run start and held across the short run
} AACNMRCurves;
typedef struct AACPCEInfo {
AVChannelLayout layout;
uint8_t num_ele[4]; ///< front, side, back, lfe
uint8_t pairing[3][8]; ///< front, side, back
uint8_t index[4][8]; ///< front, side, back, lfe
int num_ele[4]; ///< front, side, back, lfe
int pairing[3][8]; ///< front, side, back
int index[4][8]; ///< front, side, back, lfe
uint8_t config_map[16]; ///< configs the encoder's channel specific settings
uint8_t reorder_map[16]; ///< maps channels from lavc to aac order
} AACPCEInfo;
@@ -218,7 +194,6 @@ typedef struct AACEncContext {
LPCContext lpc; ///< used by TNS
int samplerate_index; ///< MPEG-4 samplerate index
int channels; ///< channel count
int bandwidth; ///< coding bandwidth in Hz, fixed at init; the psy model and the coders' band cutoff agree on it
const uint8_t *reorder_map; ///< lavc to aac reorder map
const uint8_t *chan_map; ///< channel configuration map
@@ -231,12 +206,6 @@ typedef struct AACEncContext {
int last_frame_pb_count; ///< number of bits for the previous frame
float lambda_sum; ///< sum(lambda), for Qvg reporting
int lambda_count; ///< count(lambda), for Qvg reporting
/* tool-usage stats, reported at close: per-coded-band for PNS (channel bands),
* per-coded-pair-band for M/S and I/S (CPE bands) */
uint64_t stat_ch_bands, stat_pns; ///< coded channel-bands, of which PNS
uint64_t stat_cpe_bands, stat_ms, stat_is; ///< coded CPE pair-bands, of which M/S, I/S
uint64_t stat_chans, stat_short; ///< coded channels, of which short-block (transient)
uint64_t stat_tns_long, stat_tns_short; ///< TNS-active channels among long / short blocks
enum RawDataBlockType cur_type; ///< channel group type cur_channel belongs to
AudioFrameQueue afq;
@@ -247,7 +216,6 @@ typedef struct AACEncContext {
AACQuantizeBandCostCacheEntry quantize_band_cost_cache[256][128]; ///< memoization area for quantize_band_cost
AACEncDSPContext aacdsp;
AACNMRCurves *nmr; ///< NMR coder scratch (NULL unless coder == nmr)
struct {
float *samples;
+52 -135
View File
@@ -41,13 +41,9 @@
/* We really need the bits we save here elsewhere */
#define TNS_ENABLE_COEF_COMPRESSION
/* Apple-derived TNS: weighted-spectrum predictor, accepted only if the measured
* post-quantization prediction gain clears a block-type-dependent bar (Apple RE). */
#define TNS_PREDGAIN_GATE 1.4f /* first gate: predicted LPC gain */
#define TNS_PG_C1_LONG 1.4f /* min measured gain, long blocks */
#define TNS_PG_C1_SHORT 3.2f /* min measured gain, short blocks */
#define TNS_PG_CLAMP 6.0f /* upper bound: poles near unit circle → noise blowup */
#define TNS_WEIGHT_FLOOR 0.01f /* per-bin masking floor for the weighted spectrum */
/* TNS will only be used if the LPC gain is within these margins */
#define TNS_GAIN_THRESHOLD_LOW 1.4f
#define TNS_GAIN_THRESHOLD_HIGH 1.16f*TNS_GAIN_THRESHOLD_LOW
static inline int compress_coeffs(int *coef, int order, int c_bits)
{
@@ -66,7 +62,11 @@ static inline int compress_coeffs(int *coef, int order, int c_bits)
return 1;
}
/** Encode TNS data. */
/**
* Encode TNS data.
* Coefficient compression is simply not lossless as it should be
* on any decoder tested and as such is not active.
*/
void ff_aac_encode_tns_info(AACEncContext *s, SingleChannelElement *sce)
{
TemporalNoiseShaping *tns = &sce->tns;
@@ -98,28 +98,15 @@ void ff_aac_encode_tns_info(AACEncContext *s, SingleChannelElement *sce)
}
}
/* Cap the TNS band range at the first PNS band to avoid TNS+PNS conflicts. */
static int tns_max_nonpns(const SingleChannelElement *sce, int mmm)
{
for (int w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w])
for (int g = 0; g < mmm; g++)
if (sce->band_type[w*16+g] == NOISE_BT) { mmm = g; break; }
return mmm;
}
/* Apply TNS filter */
void ff_aac_apply_tns(AACEncContext *s, SingleChannelElement *sce)
{
TemporalNoiseShaping *tns = &sce->tns;
IndividualChannelStream *ics = &sce->ics;
int w, filt, m, i, top, order, bottom, start, end, size, inc;
const int mmm = tns_max_nonpns(sce, FFMIN(ics->tns_max_bands, ics->max_sfb));
const int mmm = FFMIN(ics->tns_max_bands, ics->max_sfb);
float lpc[TNS_MAX_ORDER];
/* TNS predicts from the post-M/S and post-I/S coefficients. */
float hist[1024];
memcpy(hist, sce->coeffs, sizeof(hist));
for (w = 0; w < ics->num_windows; w++) {
bottom = ics->num_swb;
for (filt = 0; filt < tns->n_filt[w]; filt++) {
@@ -147,7 +134,7 @@ void ff_aac_apply_tns(AACEncContext *s, SingleChannelElement *sce)
/* AR filter */
for (m = 0; m < size; m++, start += inc) {
for (i = 1; i <= FFMIN(m, order); i++) {
sce->coeffs[start] += lpc[i-1]*hist[start - i*inc];
sce->coeffs[start] += lpc[i-1]*sce->pcoeffs[start - i*inc];
}
}
}
@@ -174,8 +161,9 @@ static inline void quantize_coefs(double *coef, int *idx, float *lpc, int order,
void ff_aac_search_for_tns(AACEncContext *s, SingleChannelElement *sce)
{
TemporalNoiseShaping *tns = &sce->tns;
int w, count = 0;
const int mmm = tns_max_nonpns(sce, FFMIN(sce->ics.tns_max_bands, sce->ics.max_sfb));
int w, g, count = 0;
double gain, coefs[MAX_LPC_ORDER];
const int mmm = FFMIN(sce->ics.tns_max_bands, sce->ics.max_sfb);
const int is8 = sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE;
const int c_bits = is8 ? TNS_Q_BITS_IS8 == 4 : TNS_Q_BITS == 4;
const int sfb_start = av_clip(tns_min_sfb[is8][s->samplerate_index], 0, mmm);
@@ -186,127 +174,56 @@ void ff_aac_search_for_tns(AACEncContext *s, SingleChannelElement *sce)
const int sfb_len = sfb_end - sfb_start;
const int coef_len = sce->ics.swb_offset[sfb_end] - sce->ics.swb_offset[sfb_start];
const int n_filt = is8 ? 1 : order != TNS_MAX_ORDER ? 2 : 3;
const int ord_g = order / n_filt;
/* Apple's accept bar (minimum measured prediction gain): higher on short blocks,
* where a weak filter's shaped-noise tail spreads across the 50% overlap. */
const float c1 = is8 ? TNS_PG_C1_SHORT : TNS_PG_C1_LONG;
FFPsyBand *const psy_bands = &s->psy.ch[s->cur_channel].psy_bands[0];
if (coef_len <= 0 || sfb_len <= 0) {
sce->tns.present = 0;
return;
}
/* time-domain window length backing one coding window: a long MDCT block is
* fed 2048 windowed samples (current 1024 + overlap), each short block 256. */
const int tlen = is8 ? 256 : 2048;
for (w = 0; w < sce->ics.num_windows; w++) {
int filt, any = 0;
float en[4] = {0.0f, 0.0f, 0.0f, 0.0f};
int oc_start = 0;
int coef_start = sce->ics.swb_offset[sfb_start];
/* The filter gets ran in the direction of the signal's *temporal* energy,
* so the quantization noise stays in the loud masked part rather than spilling
* into the quiet part. */
const float *tw = sce->ret_buf + w*tlen;
float e_early = 0.0f, e_late = 0.0f;
int ti;
for (ti = 0; ti < tlen/2; ti++)
e_early += tw[ti]*tw[ti];
for (; ti < tlen; ti++)
e_late += tw[ti]*tw[ti];
const int tdir = e_early > e_late;
/* Walk the frequency regions exactly as the decoder does: filter 0 is the
* topmost band region, each subsequent filter covers the next region down,
* clamped to mmm. Each filter gets its own LPC over its own region. */
int top_sfb = sce->ics.num_swb;
for (filt = 0; filt < n_filt; filt++) {
double coefs[MAX_LPC_ORDER];
float wspec[1024], tmp[1024], lpc_q[TNS_MAX_ORDER];
int len_sfb = (filt == n_filt - 1) ? sfb_len - filt*(sfb_len/n_filt)
: sfb_len/n_filt;
int bot_sfb = FFMAX(0, top_sfb - len_sfb);
int g_lo = FFMIN(bot_sfb, mmm), g_hi = FFMIN(top_sfb, mmm);
int c_lo = sce->ics.swb_offset[g_lo];
int c_hi = sce->ics.swb_offset[g_hi];
int clen = c_hi - c_lo;
const int dir = slant != 2 ? slant : tdir;
float gain, orig_e = 0.0f, filt_e = 0.0f;
int m, i, g, inc, st;
tns->length[w][filt] = len_sfb;
tns->order[w][filt] = 0; /* default: region carries no filter */
top_sfb = bot_sfb;
if (clen <= 2*ord_g) /* too short for a stable order-ord_g LPC */
continue;
/* Fit LPC on the perceptually-weighted spectrum X/sqrt(thr), floored
* to avoid a near-zero threshold blowing up a single bin (Apple). */
{
float maxrms = 0.0f, floorrms;
int k;
for (g = g_lo; g < g_hi; g++) {
int s0 = sce->ics.swb_offset[g], s1 = sce->ics.swb_offset[g+1];
float rms = sqrtf(FFMAX(psy_bands[w*16 + g].threshold, 0.0f) /
FFMAX(s1 - s0, 1));
maxrms = FFMAX(maxrms, rms);
}
floorrms = FFMAX(maxrms * TNS_WEIGHT_FLOOR, 1e-9f);
for (g = g_lo; g < g_hi; g++) {
int s0 = sce->ics.swb_offset[g], s1 = sce->ics.swb_offset[g+1];
float rms = sqrtf(FFMAX(psy_bands[w*16 + g].threshold, 0.0f) /
FFMAX(s1 - s0, 1));
float wgt = 1.0f / FFMAX(rms, floorrms);
for (k = s0; k < s1; k++)
wspec[k - c_lo] = sce->coeffs[w*128 + k] * wgt;
}
/* Short blocks: unwindowed fit; Hann window zeros the edges of the
* tiny region, wrecking the LPC. Long blocks keep the window. */
gain = ff_lpc_calc_ref_coefs_f(&s->lpc, wspec, clen, ord_g, coefs, !is8);
if (n_filt == 2) {
for (g = sfb_start; g < sce->ics.num_swb && g <= sfb_end; g++) {
FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[w*16+g];
if (g > sfb_start + (sfb_len/2))
en[1] += band->energy; /* End */
else
en[0] += band->energy; /* Start */
}
/* Reject below the first gate and above the clamp (poles near unit circle). */
if (!isfinite(gain) || gain < TNS_PREDGAIN_GATE || gain > TNS_PG_CLAMP)
continue;
/* Negate: ff_lpc_calc_ref_coefs_f sign convention is opposite to what
* ff_aac_apply_tns's MA filter needs; fed unnegated, it anti-whitens. */
for (i = 0; i < ord_g; i++)
coefs[i] = -coefs[i];
/* Quantize, then build the decoder's direct-form LPC. */
quantize_coefs(coefs, tns->coef_idx[w][filt], tns->coef[w][filt],
ord_g, c_bits);
compute_lpc_coefs(tns->coef[w][filt], 0, ord_g, lpc_q, 0, 0, 0, NULL);
/* Apply the quantized filter to the weighted spectrum and measure gain. */
const float *msrc = wspec;
inc = dir ? -1 : 1;
st = dir ? clen - 1 : 0;
for (m = 0; m < clen; m++) {
int idx = st + m*inc;
float acc = msrc[idx];
for (i = 1; i <= FFMIN(m, ord_g); i++)
acc += lpc_q[i-1] * msrc[idx - i*inc];
tmp[idx] = acc;
en[2] = en[0];
} else {
for (g = sfb_start; g < sce->ics.num_swb && g <= sfb_end; g++) {
FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[w*16+g];
if (g > sfb_start + (sfb_len/2) + (sfb_len/4))
en[2] += band->energy; /* End */
else if (g > sfb_start + (sfb_len/2) - (sfb_len/4))
en[1] += band->energy; /* Middle */
else
en[0] += band->energy; /* Start */
}
for (m = 0; m < clen; m++) {
orig_e += msrc[m]*msrc[m];
filt_e += tmp[m]*tmp[m];
}
filt_e = FFMAX(filt_e, 1e-9f);
/* Keep only if measured post-quantization gain clears C1 (Apple's outcome gate). */
if (orig_e < c1*filt_e)
continue;
tns->order[w][filt] = ord_g;
tns->direction[w][filt] = dir;
any = 1;
en[3] = en[0];
}
tns->n_filt[w] = any ? n_filt : 0;
if (any)
count++;
/* LPC */
gain = ff_lpc_calc_ref_coefs_f(&s->lpc, &sce->coeffs[w*128 + coef_start],
coef_len, order, coefs);
if (!order || !isfinite(gain) || gain < TNS_GAIN_THRESHOLD_LOW || gain > TNS_GAIN_THRESHOLD_HIGH)
continue;
tns->n_filt[w] = n_filt;
for (g = 0; g < tns->n_filt[w]; g++) {
tns->direction[w][g] = slant != 2 ? slant : en[g] < en[g + 1];
tns->order[w][g] = order/tns->n_filt[w];
tns->length[w][g] = sfb_len/tns->n_filt[w];
quantize_coefs(&coefs[oc_start], tns->coef_idx[w][g], tns->coef[w][g],
tns->order[w][g], c_bits);
oc_start += tns->order[w][g];
}
count++;
}
sce->tns.present = !!count;
}

Some files were not shown because too many files have changed in this diff Show More