mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-12 13:08:24 -10:00
Compare commits
179
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd97d63021 | ||
|
|
d7446f1609 | ||
|
|
baa6ff33c2 | ||
|
|
9e333a55eb | ||
|
|
5aaea68b34 | ||
|
|
28579236c9 | ||
|
|
a4d0a85439 | ||
|
|
0d1f649a2d | ||
|
|
e3120a9c87 | ||
|
|
54a6926a3f | ||
|
|
094d4192aa | ||
|
|
df859b6ca0 | ||
|
|
4206fe8f52 | ||
|
|
72e8b02333 | ||
|
|
4ef383d2da | ||
|
|
655c5b53fe | ||
|
|
3685e90f99 | ||
|
|
f10151d1c8 | ||
|
|
fc99649544 | ||
|
|
677c749aad | ||
|
|
e7d01e8638 | ||
|
|
04c6866bcb | ||
|
|
7c0a5c3a5b | ||
|
|
0042a8cca7 | ||
|
|
6fc9ae8ee8 | ||
|
|
c9260506ee | ||
|
|
92656bf572 | ||
|
|
9ce6ee410f | ||
|
|
42270588f9 | ||
|
|
d391508ed1 | ||
|
|
1ab9e85b97 | ||
|
|
807245ddcd | ||
|
|
696d89e08c | ||
|
|
33e757d6be | ||
|
|
f79bba8e95 | ||
|
|
adf99cb980 | ||
|
|
46053b4a54 | ||
|
|
cbc415f2ba | ||
|
|
b376553a31 | ||
|
|
4ac90ce105 | ||
|
|
519d06c0f6 | ||
|
|
78f4141ad7 | ||
|
|
31f517fcd7 | ||
|
|
323d3a2367 | ||
|
|
2850df3006 | ||
|
|
6b24a2bcf5 | ||
|
|
5c6b76a0eb | ||
|
|
d8bd21a89e | ||
|
|
edd39fca42 | ||
|
|
dc09718372 | ||
|
|
be70b9eaea | ||
|
|
ec1fc806d5 | ||
|
|
12ff7f9842 | ||
|
|
d7f44832a6 | ||
|
|
a232f38143 | ||
|
|
edeecb928d | ||
|
|
48b9aef3f4 | ||
|
|
8d85478046 | ||
|
|
c5cd9ae6f8 | ||
|
|
65539f234e | ||
|
|
34fd7248c0 | ||
|
|
2a688d8f43 | ||
|
|
ae907bff65 | ||
|
|
fd7e99a94c | ||
|
|
2440f44bb3 | ||
|
|
e856942f86 | ||
|
|
c78b4fa0b7 | ||
|
|
c531bd56fe | ||
|
|
ec71393b7b | ||
|
|
2cc624e8dc | ||
|
|
c38dbd516f | ||
|
|
cec7ea5aae | ||
|
|
05a67973bf | ||
|
|
5ab2152e6a | ||
|
|
376782248d | ||
|
|
fa4ecbff83 | ||
|
|
f6d00b124b | ||
|
|
bce2444917 | ||
|
|
23807ce20f | ||
|
|
a2cd6efcb4 | ||
|
|
100a62c152 | ||
|
|
ba979c1110 | ||
|
|
a187644490 | ||
|
|
679e334c72 | ||
|
|
3c4c202cfd | ||
|
|
cc1da39e23 | ||
|
|
ab6a34d345 | ||
|
|
bfcc408883 | ||
|
|
081d1be095 | ||
|
|
372e82f37a | ||
|
|
57e45b09cb | ||
|
|
0ae51eb6b9 | ||
|
|
54000281fe | ||
|
|
e3ec135821 | ||
|
|
1269811da5 | ||
|
|
66376b18c5 | ||
|
|
697d251723 | ||
|
|
2c80e1abd6 | ||
|
|
dedc4dfc42 | ||
|
|
8a9d7eece3 | ||
|
|
7f88ccd7ea | ||
|
|
9c92dae502 | ||
|
|
8ba38e325e | ||
|
|
583785e886 | ||
|
|
2f07aac229 | ||
|
|
a51c0facf1 | ||
|
|
8fa6a2ea24 | ||
|
|
ac3ca0bc44 | ||
|
|
a5668b1a9a | ||
|
|
fddf92b579 | ||
|
|
59ffefa9c7 | ||
|
|
37713cbc45 | ||
|
|
ade67cf50d | ||
|
|
a78fbce8fe | ||
|
|
4cbd463b25 | ||
|
|
ccc4165176 | ||
|
|
e216b5083e | ||
|
|
3bce3840e6 | ||
|
|
8ae89c9d76 | ||
|
|
c2762af1b6 | ||
|
|
22c3146900 | ||
|
|
60a78b0fb1 | ||
|
|
8a14f39367 | ||
|
|
654744fbce | ||
|
|
1442117a5e | ||
|
|
cb5d4d6597 | ||
|
|
a6b3361aae | ||
|
|
e630ac2e02 | ||
|
|
0b7881fcb7 | ||
|
|
2f6cdda706 | ||
|
|
9522cd8060 | ||
|
|
6ee48d2f87 | ||
|
|
d9b00b7e61 | ||
|
|
4d06a59a07 | ||
|
|
56af306e27 | ||
|
|
122da7195a | ||
|
|
a5d7f8b5bd | ||
|
|
183ba70c15 | ||
|
|
1a6a5c2e91 | ||
|
|
65f332c151 | ||
|
|
1b87a9af45 | ||
|
|
bbbc50f1f6 | ||
|
|
fed60b7e05 | ||
|
|
49582a9383 | ||
|
|
5f5f2f47ea | ||
|
|
1087a448da | ||
|
|
67c4a68f89 | ||
|
|
bf5c84a903 | ||
|
|
58ccb33e28 | ||
|
|
798dcd7f33 | ||
|
|
024dcba88c | ||
|
|
a86d86a22c | ||
|
|
4c1412cd0f | ||
|
|
cddfd368da | ||
|
|
c1c815b33e | ||
|
|
4356847c42 | ||
|
|
afcfce0d67 | ||
|
|
0580d2d6fc | ||
|
|
378865087c | ||
|
|
7600667d1b | ||
|
|
86a5c9918b | ||
|
|
0484a6d4f7 | ||
|
|
095b916b08 | ||
|
|
97dd672cc6 | ||
|
|
8c62b973fd | ||
|
|
dd3a2d0831 | ||
|
|
dd8f53271f | ||
|
|
22b987902c | ||
|
|
5dd6fbbfc8 | ||
|
|
d10f7ab438 | ||
|
|
a27ef55d56 | ||
|
|
c867b2a34a | ||
|
|
085bf1bf56 | ||
|
|
1dbab030d4 | ||
|
|
ce3ee5174c | ||
|
|
7370c1a268 | ||
|
|
0803d4be13 | ||
|
|
9cbbbcbacf | ||
|
|
1f59acacbe |
No files matched your search
@@ -102,6 +102,7 @@ jobs:
|
||||
./vfs_v5_metadata_test
|
||||
./vfs_readahead_test
|
||||
./vfs_close_result_test
|
||||
./vfs_descriptor_rw_test
|
||||
}
|
||||
# Mapping on (what the platform actually ships), mapping off
|
||||
# with the descriptor path forced (what the consoles have),
|
||||
@@ -146,7 +147,26 @@ jobs:
|
||||
# The system upgrade runs in the action: an msys2-runtime update
|
||||
# kills every MSYS2 process, which a run step's own shell would
|
||||
# not survive.
|
||||
- uses: msys2/setup-msys2@v2
|
||||
- name: Set up MSYS2
|
||||
id: msys2
|
||||
continue-on-error: true
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.sys }}
|
||||
update: true
|
||||
|
||||
# setup-msys2 has no retry of its own, and its system upgrade fails
|
||||
# the job when mirror.msys2.org stalls ("Operation too slow") on the
|
||||
# package databases. A failed attempt is run once more after a
|
||||
# minute; the second reinstalls over the first.
|
||||
- name: Wait before retrying MSYS2
|
||||
if: steps.msys2.outcome == 'failure'
|
||||
shell: bash
|
||||
run: sleep 60
|
||||
|
||||
- name: Set up MSYS2 (retry)
|
||||
if: steps.msys2.outcome == 'failure'
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.sys }}
|
||||
update: true
|
||||
@@ -206,6 +226,15 @@ jobs:
|
||||
./vfs_prefetch_offthread_test.exe
|
||||
# The descriptor path's close() result, with PS2's semantics.
|
||||
./vfs_close_result_test.exe
|
||||
# Read-write descriptor streams on the Windows C runtimes,
|
||||
# and that a file they create is writable afterwards.
|
||||
./vfs_descriptor_rw_test.exe
|
||||
# Reads and appends at offsets from several threads through
|
||||
# the second handle: opened relative to the stream's, the same
|
||||
# checked as before Vista, and by the path; a -1 fails each.
|
||||
./vfs_positional_nommap_test.exe
|
||||
./vfs_positional_ntverify_test.exe
|
||||
./vfs_positional_pathreopen_test.exe
|
||||
|
||||
# The Win64 fastjmp_set stores xmm6-xmm15 with movaps and faults
|
||||
# on a misaligned buffer. Linux has no such stores, so the Linux
|
||||
|
||||
@@ -7,6 +7,10 @@ name: CI Linux EGL hardware core
|
||||
# bound to the window surface the video thread holds, and with it off.
|
||||
# Mesa takes the surfaceless path by itself; a preloaded shim hides
|
||||
# parts of its EGL so the pbuffer paths run too.
|
||||
#
|
||||
# Then a core that draws on a thread of its own through
|
||||
# RETRO_ENVIRONMENT_GET_HW_SHARED_CONTEXT_INTERFACE, on GLX and on EGL,
|
||||
# threaded and not: the colour on screen must be that thread's drawing.
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -21,6 +25,10 @@ on:
|
||||
- 'gfx/video_thread_hw.c'
|
||||
- 'gfx/video_thread_wrapper.c'
|
||||
- 'samples/gfx/egl_hw_core/**'
|
||||
- 'samples/gfx/gl_shared_context/**'
|
||||
- 'gfx/drivers_context/x_ctx.c'
|
||||
- 'runloop.c'
|
||||
- 'libretro-common/include/libretro.h'
|
||||
- '.github/workflows/Linux-egl-hw-core.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
@@ -32,6 +40,10 @@ on:
|
||||
- 'gfx/video_thread_hw.c'
|
||||
- 'gfx/video_thread_wrapper.c'
|
||||
- 'samples/gfx/egl_hw_core/**'
|
||||
- 'samples/gfx/gl_shared_context/**'
|
||||
- 'gfx/drivers_context/x_ctx.c'
|
||||
- 'runloop.c'
|
||||
- 'libretro-common/include/libretro.h'
|
||||
- '.github/workflows/Linux-egl-hw-core.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
@@ -125,6 +137,13 @@ jobs:
|
||||
make -C samples/gfx/egl_hw_core
|
||||
timeout 600 python3 samples/gfx/egl_hw_core/egl_hw_core_test.py ./retroarch
|
||||
|
||||
- name: Run gl_shared_context_test
|
||||
shell: bash
|
||||
run: |
|
||||
set -eu
|
||||
make -C samples/gfx/gl_shared_context
|
||||
timeout 300 python3 samples/gfx/gl_shared_context/gl_shared_context_test.py ./retroarch
|
||||
|
||||
- name: Save ccache
|
||||
# Only master's pushes keep a cache: pull requests restore
|
||||
# master's, so one push does not evict the next one's.
|
||||
|
||||
@@ -171,6 +171,9 @@ jobs:
|
||||
make -C ../tls_retro clean
|
||||
SSL_BACKEND=$be ../tls_retro/verify_hook_test.sh
|
||||
make -C ../tls_retro clean
|
||||
SSL_BACKEND=$be CFLAGS='-O1 -g1 -std=gnu89 -Wall -Wextra -Werror=declaration-after-statement -fsanitize=address,undefined -fno-omit-frame-pointer' \
|
||||
sh ../tls_retro/handshake_test.sh
|
||||
make -C ../tls_retro clean
|
||||
|
||||
- name: Operate the libsmb2 backend (SMB VFS against a local smbd)
|
||||
if: matrix.lane == 'libsmb2'
|
||||
|
||||
@@ -125,7 +125,12 @@ jobs:
|
||||
rtmp_publish_test
|
||||
rtmp_control_test
|
||||
rtmp_session_test
|
||||
rtmp_client_test
|
||||
rtmp_socket_test
|
||||
rtmp_connect_test
|
||||
rtmp_connect_select_test
|
||||
rtmp_resolve_test
|
||||
rtmp_resolve_native_test
|
||||
rslc_test
|
||||
rslc_build_test
|
||||
rslc_ext_test
|
||||
@@ -134,6 +139,8 @@ jobs:
|
||||
s16_to_float_test
|
||||
float_to_s16_test
|
||||
float_to_s32_test
|
||||
# G.711 mu-law; a step below compares it with FFmpeg's.
|
||||
float_to_ulaw_test
|
||||
compat_fnmatch_test
|
||||
snprintf
|
||||
unbase64_test
|
||||
@@ -146,8 +153,11 @@ jobs:
|
||||
rzstd_raw_block_test_novec
|
||||
rzstd_dict_test
|
||||
rbzip2_test
|
||||
shiftjis_test
|
||||
rinflate_window_test
|
||||
rdeflate_hash_test
|
||||
rdeflate_flush_test
|
||||
encoding_adler32_test
|
||||
emscripten_mmap_test
|
||||
archive_zip_test
|
||||
archive_zstd_test
|
||||
@@ -163,7 +173,19 @@ jobs:
|
||||
fill_pathname_test
|
||||
path_mkdir_test
|
||||
path_parent_dir_test
|
||||
# path_remove_tree and path_copy_tree on a real tree, links
|
||||
path_tree_test
|
||||
rpng
|
||||
# a PNG a row at a time, as stored, from input in pieces
|
||||
rpng_rows_test
|
||||
# a GIF's first image, straight into the caller's rows
|
||||
rgif_test
|
||||
# YAML: configurations, block scalars, a patch file whose
|
||||
# entries name anchored sequences by alias, node locations
|
||||
ryaml_test
|
||||
# what the YAML writer writes reads back the same, over
|
||||
# tricky scalars and 3000 random documents
|
||||
ryaml_writer_test
|
||||
rzip_chunk_size_test
|
||||
rzip_matches_buf_test
|
||||
rzip_codec_test
|
||||
@@ -175,6 +197,41 @@ jobs:
|
||||
# rvorbis' codebook size bound, and a real stream past it.
|
||||
rvorbis_codebook_test
|
||||
rjpeg_test
|
||||
# Baseline JPEG encoding, decoded back with rjpeg; a step
|
||||
# below has FFmpeg decode what it writes.
|
||||
rjpeg_encode_test
|
||||
# MP4 writing, read back with rmp4; a step below has FFmpeg
|
||||
# decode the files.
|
||||
rmp4_mux_test
|
||||
# MPEG-2 video through rmpeg1_video, on its own fixtures; the
|
||||
# step below runs it again over FFmpeg's and the conformance
|
||||
# streams.
|
||||
rmpeg2_test
|
||||
# MPEG-4 Part 2 video through rmpeg4_video, on its own
|
||||
# fixtures, whole, a unit at a time and damaged; a step below
|
||||
# runs it over FFmpeg's and Xvid's streams.
|
||||
rmpeg4_test
|
||||
# MPEG-4 Part 2 encoding, decoded back with rmpeg4_video; a
|
||||
# step below has FFmpeg decode the streams.
|
||||
rmpeg4_encode_test
|
||||
# AAC-LC encoding, decoded back with raac; a step below has
|
||||
# FFmpeg decode the streams.
|
||||
raac_encode_test
|
||||
# H.264 encoding, decoded back with rh264; a step below has
|
||||
# FFmpeg decode the streams.
|
||||
rh264_encode_test
|
||||
# Tags in each container and ID3 version, and every prefix
|
||||
# and corruption of each file read inside it.
|
||||
rtags_test
|
||||
# A file's audio_transfer arm from its bytes, and the folds.
|
||||
audio_transfer_sniff_test
|
||||
# ATRAC3 and ATRAC3plus in WAVE and OpenMG through audio_transfer.
|
||||
audio_transfer_atrac_test
|
||||
# AVI and ASF headers: streams, codecs, sizes, rates, length.
|
||||
rcontainer_test
|
||||
# 4:2:0 to bytes in memory order and to UYVY, and bytes to
|
||||
# 4:2:0; a step below compares the latter with swscale's.
|
||||
image_yuv_test
|
||||
rh264_lossless_test
|
||||
rh264_lossless_test_nothreads
|
||||
rh264_lossless_test_volatile
|
||||
@@ -184,6 +241,8 @@ jobs:
|
||||
rh264_state_test
|
||||
# rmp3's frame-at-a-time API against its pull API.
|
||||
rmp3_frame_test
|
||||
# rmp3's gapless trimming against ffmpeg's, and its tag parser.
|
||||
rmp3_gapless_test
|
||||
# raac_last_size over units followed by more.
|
||||
raac_size_test
|
||||
# raac's savestates: saved between units, loaded into a new decoder.
|
||||
@@ -203,6 +262,7 @@ jobs:
|
||||
r7z_stored_test
|
||||
r7z_methods_test
|
||||
r7z_stream_test
|
||||
r7z_peek_threads_test
|
||||
rzip_archive_test
|
||||
# The RAR reader on real archives (LZ and PPMd blocks,
|
||||
# filters, Unicode names) and on mangled copies of them.
|
||||
@@ -225,6 +285,25 @@ jobs:
|
||||
filestream_rbuf_fault_test
|
||||
vfs_rename_replace_test
|
||||
vfs_close_result_test
|
||||
# A read-write stream on the descriptor path, as an emulated
|
||||
# file system uses it: in-place writes, truncate, reopen.
|
||||
vfs_descriptor_rw_test
|
||||
# Positional I/O (VFS v6): reads at offsets and appends from
|
||||
# several threads on one stream, with no lock.
|
||||
vfs_positional_test
|
||||
# intfstream reads at offsets on file, buffered and memory
|
||||
# streams: position kept, window kept, four threads.
|
||||
intfstream_read_at_test
|
||||
# The same without HAVE_MMAP (Android's build): pread/pwrite
|
||||
# are still there, so a -1 fails.
|
||||
vfs_positional_nommap_test
|
||||
# Where off_t is 32 bits: past 4 GiB refused, never read
|
||||
# 4 GiB lower.
|
||||
vfs_positional_off32_test
|
||||
# Windows NT before Vista's second handle (the path, checked);
|
||||
# the same run as vfs_positional_test here.
|
||||
vfs_positional_pathreopen_test
|
||||
vfs_positional_ntverify_test
|
||||
cdrom_cuesheet_overflow_test
|
||||
rdvd_h262_test
|
||||
rdvd_lpcm_test
|
||||
@@ -253,6 +332,15 @@ jobs:
|
||||
http_parse_test
|
||||
# UPnP gateway client: parsers, and SOAP against a fake gateway.
|
||||
net_upnp_test
|
||||
# net_http: a 3xx handed back unfollowed, a DELETE body's
|
||||
# Content-Length, the caller's Accept-Encoding/User-Agent.
|
||||
net_http_options_test
|
||||
# socket_poll past FD_SETSIZE sockets.
|
||||
socket_poll_test
|
||||
# Half floats both ways, against F16C.
|
||||
float16_test
|
||||
# TrueType and CID-keyed CFF glyphs, metrics and kerning.
|
||||
rtt_test
|
||||
rjson_test
|
||||
rm3u_test
|
||||
rmp4_fragment_test
|
||||
@@ -364,6 +452,16 @@ jobs:
|
||||
# forces every tier on Linux, Windows and macOS runners.
|
||||
retro_procbarrier_test
|
||||
retro_asym_eventcount_test
|
||||
# Two processes hand a counter back and forth 200000 times,
|
||||
# each parked between turns: a lost wake hangs it, and its
|
||||
# own watchdog reports that as a failure.
|
||||
retro_shared_eventcount_test
|
||||
# A writer updates a record two million times while three
|
||||
# threads copy it: no copy torn, none going back.
|
||||
retro_seqlock_test
|
||||
# Twenty threads change one record two million times in all
|
||||
# while three copy it: no change lost, no copy torn.
|
||||
retro_cas_record_test
|
||||
sthread_ex_test
|
||||
fast_cores_test
|
||||
memshm_test
|
||||
@@ -407,6 +505,11 @@ jobs:
|
||||
# stereo stream (tones, gain points, swap and negate masks)
|
||||
# and a mono one, then bad frames and garbage.
|
||||
ratrac3p_test
|
||||
# ATRAC9 against a reference decoder's output for generated
|
||||
# streams in every channel layout, rate and superframe size,
|
||||
# with reset and savestates; then its own unit checks.
|
||||
ratrac9_vectors_test
|
||||
ratrac9_test
|
||||
# Animation playback against a scripted stream: order,
|
||||
# pacing, loops, catch-up, the worker's two jobs.
|
||||
video_player_test
|
||||
@@ -696,6 +799,435 @@ jobs:
|
||||
ffmpeg -hide_banner -loglevel error -i "$fixture" -pix_fmt yuv420p -f rawvideo -y "$reference"
|
||||
./rdvd_h262_test "$fixture" "$reference"
|
||||
|
||||
# The ISO/IEC 13818-4 streams never change (their md5s are checked):
|
||||
# one good download is kept in the Actions cache
|
||||
- name: Restore the MPEG-2 conformance streams
|
||||
if: matrix.group == 'formats'
|
||||
id: mpeg2_conformance
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: ~/mpeg2-conformance
|
||||
key: mpeg2-conformance-main-8-1
|
||||
|
||||
# MPEG-2 video against FFmpeg's decode, within 3 per sample (two
|
||||
# IEEE 1180 inverse transforms): streams FFmpeg writes, progressive,
|
||||
# interlaced (field DCT, field motion) and with Table B.15, alternate
|
||||
# scan, the non-linear quantiser and 10-bit intra DC; and conformance
|
||||
# streams with field pictures, dual prime, frame and field pictures
|
||||
# mixed, slices starting mid-row
|
||||
- name: Decode MPEG-2 video against FFmpeg and conformance streams
|
||||
if: matrix.group == 'formats'
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/formats/mpeg2
|
||||
run: |
|
||||
set -euo pipefail
|
||||
make -j2 SANITIZER=address,undefined
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
src="-f lavfi -i testsrc2=size=352x288:rate=25,format=yuv420p -frames:v 24"
|
||||
i=0
|
||||
for opts in "-bf 2 -g 12 -q:v 4" "-bf 2 -g 12 -q:v 4 -flags +ildct+ilme -top 1" \
|
||||
"-bf 2 -g 12 -q:v 3 -qmax 28 -intra_vlc 1 -non_linear_quant 1 -alternate_scan 1 -dc 10"; do
|
||||
i=$((i+1))
|
||||
ffmpeg -hide_banner -loglevel error $src -c:v mpeg2video $opts -f mpeg2video -y "$work/g$i.m2v"
|
||||
ffmpeg -hide_banner -loglevel error -i "$work/g$i.m2v" -fps_mode passthrough \
|
||||
-pix_fmt yuv420p -f rawvideo -y "$work/g$i.yuv"
|
||||
./rmpeg2_test "$work/g$i.m2v" "$work/g$i.yuv"
|
||||
done
|
||||
conf="$HOME/mpeg2-conformance"
|
||||
mkdir -p "$conf"
|
||||
base=https://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_IEC_13818-4_2004_Conformance_Testing/Video/bitstreams/main-profile
|
||||
# A stream the server will not give is reported and left out
|
||||
# rather than failing the job; the cache is saved only once every
|
||||
# stream is in it, and kept from then on
|
||||
missing=0
|
||||
while read -r path md5; do
|
||||
f="$conf/$(basename "$path")"
|
||||
if ! { [ -f "$f" ] && echo "$md5 $f" | md5sum --quiet -c -; }; then
|
||||
if ! curl --fail --silent --show-error --location --retry 3 --retry-all-errors \
|
||||
--retry-max-time 60 --connect-timeout 10 --max-time 60 "$base/$path" -o "$f" \
|
||||
|| ! echo "$md5 $f" | md5sum --quiet -c -; then
|
||||
echo "::warning title=MPEG-2 conformance::$path could not be fetched; left out"
|
||||
rm -f "$f"
|
||||
missing=1
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
gunzip -c "$f" > "$work/c.m2v"
|
||||
ffmpeg -nostdin -hide_banner -loglevel error -i "$work/c.m2v" -fps_mode passthrough \
|
||||
-pix_fmt yuv420p -f rawvideo -y "$work/c.yuv"
|
||||
./rmpeg2_test "$work/c.m2v" "$work/c.yuv"
|
||||
done <<'LIST'
|
||||
tcela/tcela-8-fp-dp/tcela-8.bits.gz f0ef12c0e4f4a6cdb9ba42d000054c8b
|
||||
hhi/hhi_burst_short/hhi_burst_short.bits.gz a68d3436d89ffc896393b18e8556a33c
|
||||
nokia/nokia6/nokia6_dual.bit.gz 9890f21e949716f67469240d4e3105c0
|
||||
toshiba/toshiba_DPall-0/toshiba_DPall-0.mpg.gz d92090842a0c2e37cf1cda7212868cc3
|
||||
sony/sony-ct3/sony-ct3.bs.gz 31bb0abfaf802c754254b38b500d7685
|
||||
tcela/tcela-6-slices/tcela-6.bits.gz 1247cf986205e7dfe4413bd223be8ee6
|
||||
mei/mei.2conftest.4f/mei_2stream.4f.gz 505375e1f68fe527f52eb3604cc8edae
|
||||
ti/TI_cl_2/TI_c1_2.bits.gz 3b25d76d4b517ec3ab493f2f3fb767c0
|
||||
LIST
|
||||
[ "$missing" = 0 ] && touch "$conf/complete" || rm -f "$conf/complete"
|
||||
|
||||
- name: Save the MPEG-2 conformance streams
|
||||
if: matrix.group == 'formats' && steps.mpeg2_conformance.outputs.cache-hit != 'true' && hashFiles('~/mpeg2-conformance/complete') != ''
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: ~/mpeg2-conformance
|
||||
key: mpeg2-conformance-main-8-1
|
||||
|
||||
# MPEG-4 Part 2 video against FFmpeg's decode, within 3 per sample:
|
||||
# streams FFmpeg's mpeg4 encoder writes (B-VOPs, quarter sample, four
|
||||
# vectors, MPEG quantisation, interlaced field DCT and motion with
|
||||
# alternate scan, AC prediction, resync markers, data partitioning, a
|
||||
# size not a multiple of 16), Xvid's
|
||||
# (GMC S-VOPs), and H.263 for the short video header, with and
|
||||
# without GOB headers. FFmpeg decodes with one thread: its frame
|
||||
# threads do not share the field vectors interlaced direct mode reads.
|
||||
# What rjpeg_encode writes - 4:2:0 and 4:2:2, sizes in and out of
|
||||
# whole MCUs, qualities 20 to 100 - must decode in FFmpeg with no
|
||||
# error
|
||||
- name: Decode rjpeg_encode's JPEGs with FFmpeg
|
||||
if: matrix.group == 'formats'
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/formats/jpeg_encode
|
||||
run: |
|
||||
set -euo pipefail
|
||||
make -j2 SANITIZER=address,undefined
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
./rjpeg_encode_test "$work"
|
||||
n=0
|
||||
for f in "$work"/*.jpg; do
|
||||
ffmpeg -nostdin -hide_banner -loglevel error -xerror -i "$f" -f null -
|
||||
n=$((n+1))
|
||||
done
|
||||
[ "$n" = 9 ]
|
||||
|
||||
# What rmp4_mux writes - MPEG-4 video with B-VOPs and 16-bit PCM,
|
||||
# motion JPEG and float PCM - must decode in FFmpeg with no error,
|
||||
# every frame there and the first shown at time zero
|
||||
- name: Read rmp4_mux's files with FFmpeg
|
||||
if: matrix.group == 'formats'
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/formats/mp4_mux
|
||||
run: |
|
||||
set -euo pipefail
|
||||
make -j2 SANITIZER=address,undefined
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
./rmp4_mux_test "$work"
|
||||
for f in mpeg4_pcm:8 mjpeg_f32:6; do
|
||||
file="$work/${f%%:*}.mp4"
|
||||
ffmpeg -nostdin -hide_banner -loglevel error -xerror -i "$file" -f null -
|
||||
got=$(ffprobe -v error -count_frames -select_streams v \
|
||||
-show_entries stream=nb_read_frames,start_time -of csv=p=0 "$file")
|
||||
echo "$file: $got"
|
||||
[ "$got" = "0.000000,${f##*:}" ]
|
||||
done
|
||||
|
||||
- name: Decode MPEG-4 video against FFmpeg
|
||||
if: matrix.group == 'formats'
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/formats/mpeg4
|
||||
run: |
|
||||
set -euo pipefail
|
||||
make -j2 SANITIZER=address,undefined
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
i=0
|
||||
while IFS='|' read -r size fmt opts; do
|
||||
i=$((i+1))
|
||||
ffmpeg -nostdin -hide_banner -loglevel error \
|
||||
-f lavfi -i "testsrc2=size=$size:rate=25,format=yuv420p" -frames:v 24 \
|
||||
$opts -f "$fmt" -y "$work/s$i.bin"
|
||||
ffmpeg -nostdin -hide_banner -loglevel error -threads 1 -flags +bitexact -idct simple \
|
||||
-f "$fmt" -i "$work/s$i.bin" -fps_mode passthrough -pix_fmt yuv420p -f rawvideo -y "$work/s$i.yuv"
|
||||
./rmpeg4_test "$work/s$i.bin" "$work/s$i.yuv"
|
||||
done <<'LIST'
|
||||
352x288|m4v|-c:v mpeg4 -g 12 -bf 2 -q:v 4
|
||||
352x288|m4v|-c:v mpeg4 -g 12 -bf 2 -q:v 4 -flags +qpel+mv4
|
||||
352x288|m4v|-c:v mpeg4 -g 12 -bf 2 -q:v 4 -mpeg_quant 1
|
||||
352x288|m4v|-c:v mpeg4 -g 12 -bf 2 -q:v 4 -flags +ildct+ilme
|
||||
352x288|m4v|-c:v mpeg4 -g 12 -bf 2 -q:v 3 -mpeg_quant 1 -flags +ildct+ilme+qpel -alternate_scan 1
|
||||
352x288|m4v|-c:v mpeg4 -g 12 -bf 2 -q:v 8 -flags +aic
|
||||
352x288|m4v|-c:v mpeg4 -g 12 -bf 2 -q:v 4 -ps 400
|
||||
352x288|m4v|-c:v mpeg4 -g 12 -bf 0 -q:v 6 -ps 300 -data_partitioning 1 -flags +mv4+aic
|
||||
350x286|m4v|-c:v mpeg4 -g 12 -bf 2 -q:v 4 -flags +mv4+qpel
|
||||
352x288|m4v|-c:v libxvid -g 8 -bf 0 -q:v 4 -gmc 1 -flags +qpel+mv4
|
||||
352x288|m4v|-c:v libxvid -g 8 -bf 0 -q:v 4 -flags +ildct
|
||||
176x144|h263|-c:v h263 -g 12 -q:v 5
|
||||
352x288|h263|-c:v h263 -g 12 -q:v 5 -ps 300
|
||||
LIST
|
||||
|
||||
# What rmpeg4_encode writes - whole macroblocks and not, fine and
|
||||
# coarse quantisers, a bit rate - FFmpeg decodes within 3 per sample
|
||||
# of rmpeg4_video, which decodes it exactly as the encoder
|
||||
# reconstructed it (the sample checks that)
|
||||
- name: Decode rmpeg4_encode's streams with FFmpeg
|
||||
if: matrix.group == 'formats'
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/formats
|
||||
run: |
|
||||
set -euo pipefail
|
||||
make -C mpeg4 -j2 SANITIZER=address,undefined
|
||||
make -C mpeg4_encode -j2 SANITIZER=address,undefined
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
./mpeg4_encode/rmpeg4_encode_test "$work"
|
||||
n=0
|
||||
for f in "$work"/*.m4v; do
|
||||
ffmpeg -nostdin -hide_banner -loglevel error -xerror -threads 1 -flags +bitexact -idct simple \
|
||||
-i "$f" -pix_fmt yuv420p -f rawvideo -y "${f%.m4v}.yuv"
|
||||
./mpeg4/rmpeg4_test "$f" "${f%.m4v}.yuv"
|
||||
n=$((n+1))
|
||||
done
|
||||
[ "$n" = 5 ]
|
||||
|
||||
# What raac_encode writes - tones, noise, an attack, mono and
|
||||
# stereo, 8 to 96 kHz - FFmpeg decodes within 2 per sample of raac
|
||||
# (the sample checks raac's decoding against the input)
|
||||
- name: Decode raac_encode's streams with FFmpeg
|
||||
if: matrix.group == 'formats'
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/formats/aac_encode
|
||||
run: |
|
||||
set -euo pipefail
|
||||
make -j2 SANITIZER=address,undefined
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
./raac_encode_test "$work"
|
||||
n=0
|
||||
for f in "$work"/*.aac; do
|
||||
ffmpeg -nostdin -hide_banner -loglevel error -xerror -i "$f" \
|
||||
-f s16le -y "${f%.aac}.ff.s16"
|
||||
./raac_encode_test --compare "${f%.aac}.s16" "${f%.aac}.ff.s16"
|
||||
n=$((n+1))
|
||||
done
|
||||
[ "$n" = 9 ]
|
||||
|
||||
# What rh264_encode writes - whole macroblocks and cropped, fine
|
||||
# and coarse quantisers, a bit rate - FFmpeg decodes to exactly the
|
||||
# encoder's reconstruction, as rh264 does (the sample checks that)
|
||||
- name: Decode rh264_encode's streams with FFmpeg
|
||||
if: matrix.group == 'formats'
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/formats/h264_encode
|
||||
run: |
|
||||
set -euo pipefail
|
||||
make -j2 SANITIZER=address,undefined
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
./rh264_encode_test "$work"
|
||||
n=0
|
||||
for f in "$work"/*.264; do
|
||||
ffmpeg -nostdin -hide_banner -loglevel error -xerror -i "$f" \
|
||||
-f rawvideo -pix_fmt yuv420p -y "${f%.264}.ff.yuv"
|
||||
cmp "${f%.264}.yuv" "${f%.264}.ff.yuv"
|
||||
n=$((n+1))
|
||||
done
|
||||
[ "$n" = 5 ]
|
||||
|
||||
# What FFmpeg writes as tags - ID3v2.3 and 2.4, ID3v1 alone, FLAC,
|
||||
# Vorbis and Opus in Ogg, MP4, ASF, WAVE - rtags reads as ffprobe
|
||||
# does, non-ASCII text, numbered genres and full dates in
|
||||
- name: Read FFmpeg's tags with rtags
|
||||
if: matrix.group == 'formats'
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/formats/tags
|
||||
run: |
|
||||
set -euo pipefail
|
||||
make -j2 SANITIZER=address,undefined
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
tags=(-metadata 'title=Tïtle ☃' -metadata 'artist=Ärtist'
|
||||
-metadata 'album=Albüm' -metadata genre=Rock -metadata track=3/12
|
||||
-metadata disc=1/2 -metadata date=2004)
|
||||
enc() { ffmpeg -nostdin -hide_banner -loglevel error -f lavfi -i sine=d=0.2 "$@"; }
|
||||
enc "${tags[@]}" -id3v2_version 3 -y "$work/v23.mp3"
|
||||
enc "${tags[@]}" -id3v2_version 4 -y "$work/v24.mp3"
|
||||
enc -id3v2_version 3 -metadata genre=17 -metadata date=2004-05-01 \
|
||||
-metadata 'title=a long title with a snowman, ☃' -y "$work/genre.mp3"
|
||||
enc "${tags[@]}" -write_id3v1 1 -y "$work/both.mp3"
|
||||
# ID3v1 alone: the ID3v2 tag in front cut off
|
||||
python3 -c 'import sys
|
||||
d = open(sys.argv[1], "rb").read()
|
||||
s = (d[6] & 127) << 21 | (d[7] & 127) << 14 | (d[8] & 127) << 7 | (d[9] & 127)
|
||||
open(sys.argv[2], "wb").write(d[10 + s:])' "$work/both.mp3" "$work/v1.mp3"
|
||||
rm "$work/both.mp3"
|
||||
enc "${tags[@]}" -y "$work/a.flac"
|
||||
enc "${tags[@]}" -c:a libvorbis -y "$work/a.ogg"
|
||||
enc "${tags[@]}" -c:a libopus -y "$work/a.opus"
|
||||
enc "${tags[@]}" -y "$work/a.m4a"
|
||||
enc -metadata genre=17 -metadata date=2004-05-01 -y "$work/b.m4a"
|
||||
enc "${tags[@]}" -y "$work/a.wma"
|
||||
enc "${tags[@]}" -y "$work/a.wav"
|
||||
n=0
|
||||
for f in "$work"/*.*; do
|
||||
ffprobe -v error -show_entries format_tags:stream_tags \
|
||||
-of default=nw=1 "$f" > "$f.tags"
|
||||
./rtags_test --ffprobe "$f" "$f.tags"
|
||||
n=$((n+1))
|
||||
done
|
||||
[ "$n" = 11 ]
|
||||
|
||||
# Files FFmpeg writes - MP3 with and without ID3v2, ADTS with and
|
||||
# without, M4A, FLAC, Ogg Vorbis, Opus, WAVE PCM and float, WMA1/2,
|
||||
# AC-3 - each sniffed as its arm and decoded where the sniffer
|
||||
# says; and 5.1 with a tone a channel in each multichannel arm,
|
||||
# folded with audio_transfer_stereo_matrix: every tone on its side
|
||||
- name: Sniff and fold FFmpeg's files with audio_transfer
|
||||
if: matrix.group == 'formats'
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/formats/audio_transfer_sniff
|
||||
run: |
|
||||
set -euo pipefail
|
||||
make -j2 SANITIZER=address,undefined
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
enc() { ffmpeg -nostdin -hide_banner -loglevel error \
|
||||
-f lavfi -i sine=f=440:d=1:sample_rate=48000 -ac 2 "$@"; }
|
||||
enc -metadata title=t -y "$work/id3.mp3"
|
||||
enc -id3v2_version 0 -write_xing 0 -y "$work/bare.mp3"
|
||||
enc -c:a aac -f adts -y "$work/bare.aac"
|
||||
enc -c:a aac -f adts -write_id3v2 1 -metadata title=t -y "$work/id3.aac"
|
||||
enc -y "$work/a.m4a"
|
||||
enc -y "$work/a.flac"
|
||||
enc -c:a libvorbis -y "$work/a.ogg"
|
||||
enc -c:a libopus -y "$work/a.opus"
|
||||
enc -y "$work/s16.wav"
|
||||
enc -c:a pcm_f32le -y "$work/f32.wav"
|
||||
enc -c:a wmav1 -y "$work/v1.wma"
|
||||
enc -y "$work/v2.wma"
|
||||
enc -c:a ac3 -y "$work/a.ac3"
|
||||
for p in id3.mp3:mp3 bare.mp3:mp3 bare.aac:aac id3.aac:aac a.m4a:aac \
|
||||
a.flac:flac a.ogg:vorbis a.opus:opus s16.wav:wav f32.wav:wav \
|
||||
v1.wma:wma v2.wma:wma a.ac3:ac3; do
|
||||
./audio_transfer_sniff_test --file "$work/${p%%:*}" "${p#*:}"
|
||||
done
|
||||
# MP3, gapless (LAME tag) and not: FFmpeg's samples, where they
|
||||
# start and end
|
||||
for f in id3.mp3 bare.mp3; do
|
||||
ffmpeg -nostdin -hide_banner -loglevel error -i "$work/$f" -f f32le -y "$work/$f.f32"
|
||||
./audio_transfer_sniff_test --file "$work/$f" mp3 --pcm "$work/$f.f32"
|
||||
done
|
||||
# WMA: the length the ASF header states, as ffprobe reads it
|
||||
for f in v1.wma v2.wma; do
|
||||
frames=$(ffprobe -v error -show_entries format=duration:stream=sample_rate \
|
||||
-of csv=p=0 "$work/$f" | tr '\n' ' ' | awk '{ printf "%d", $1 * $2 + 0.5 }')
|
||||
./audio_transfer_sniff_test --file "$work/$f" wma --frames "$frames"
|
||||
done
|
||||
# WMA1 and WMA2, gapless at each frame size (2048, 1024 and 512
|
||||
# samples): the signal FFmpeg's encoder was given, from its
|
||||
# first sample, at the length the header states
|
||||
for codec in wmav1 wmav2; do
|
||||
for rate in 44100 22050 16000 8000; do
|
||||
src="sine=f=440:d=0.73:sample_rate=$rate"
|
||||
ffmpeg -nostdin -hide_banner -loglevel error -f lavfi -i "$src" -ac 2 \
|
||||
-c:a "$codec" -y "$work/g.wma"
|
||||
ffmpeg -nostdin -hide_banner -loglevel error -f lavfi -i "$src" -ac 2 \
|
||||
-f f32le -y "$work/g.f32"
|
||||
./audio_transfer_sniff_test --file "$work/g.wma" wma --source "$work/g.f32"
|
||||
done
|
||||
done
|
||||
six=""
|
||||
n=0
|
||||
for hz in 300 500 700 80 1100 1300; do
|
||||
six="${six}sine=f=$hz:d=2:sample_rate=48000[c$n];"
|
||||
n=$((n+1))
|
||||
done
|
||||
six="${six}[c0][c1][c2][c3][c4][c5]join=inputs=6:channel_layout=5.1"
|
||||
six="$six:map=0.0-FL|1.0-FR|2.0-FC|3.0-LFE|4.0-BL|5.0-BR"
|
||||
for p in m4a:aac:aac ogg:libvorbis:vorbis opus:libopus:opus \
|
||||
flac:flac:flac ac3:ac3:ac3 wav:pcm_s16le:wav; do
|
||||
IFS=: read -r ext codec type <<< "$p"
|
||||
ffmpeg -nostdin -hide_banner -loglevel error -filter_complex "$six" \
|
||||
-c:a "$codec" -y "$work/six.$ext"
|
||||
./audio_transfer_sniff_test --file "$work/six.$ext" "$type" --tones
|
||||
done
|
||||
|
||||
# ATRAC3 and ATRAC3plus - stereo, joint stereo, mono, 4.0, 5.1,
|
||||
# 6.1, 7.1 - in WAVE and OpenMG files the sample writes: FFmpeg
|
||||
# decodes each to the samples audio_transfer gives (in FFmpeg's
|
||||
# channel layout), and ffprobe reads the OpenMG ea3 tags as rtags
|
||||
# does
|
||||
- name: Decode audio_transfer's ATRAC files with FFmpeg
|
||||
if: matrix.group == 'formats'
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/formats
|
||||
run: |
|
||||
set -euo pipefail
|
||||
make -C audio_transfer_atrac -j2 SANITIZER=address,undefined
|
||||
make -C tags -j2 SANITIZER=address,undefined
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
./audio_transfer_atrac/audio_transfer_atrac_test --write "$work"
|
||||
n=0
|
||||
for f in "$work"/*.wav "$work"/*.oma; do
|
||||
ffmpeg -nostdin -hide_banner -loglevel fatal -i "$f" -f f32le -y "$f.f32"
|
||||
./audio_transfer_atrac/audio_transfer_atrac_test --compare "$f" "$f.f32"
|
||||
n=$((n+1))
|
||||
done
|
||||
[ "$n" = 11 ]
|
||||
for f in "$work"/*.oma; do
|
||||
ffprobe -v error -show_entries format_tags:stream_tags \
|
||||
-of default=nw=1 "$f" > "$f.tags"
|
||||
./tags/rtags_test --ffprobe "$f" "$f.tags"
|
||||
done
|
||||
|
||||
# AVI (MPEG-4 Part 2 with MP3, AVC with AC-3, MPEG-4 alone,
|
||||
# MS-MPEG4 with PCM) and WMV (WMV2 with WMA2) from FFmpeg: rcontainer
|
||||
# reads the streams, tags, sizes, rates, bit rates and length as
|
||||
# ffprobe does
|
||||
- name: Read FFmpeg's AVI and ASF headers with rcontainer
|
||||
if: matrix.group == 'formats'
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/formats/container
|
||||
run: |
|
||||
set -euo pipefail
|
||||
make -j2 SANITIZER=address,undefined
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
v=(-f lavfi -i testsrc2=s=96x64:r=25:d=1)
|
||||
a=(-f lavfi -i sine=f=440:d=1:sample_rate=44100)
|
||||
ff() { ffmpeg -nostdin -hide_banner -loglevel error "$@"; }
|
||||
ff "${v[@]}" "${a[@]}" -c:v mpeg4 -vtag XVID -c:a libmp3lame -y "$work/a.avi"
|
||||
ff "${v[@]}" "${a[@]}" -c:v libx264 -c:a ac3 -y "$work/b.avi"
|
||||
ff "${v[@]}" -c:v mpeg4 -y "$work/c.avi"
|
||||
ff "${v[@]}" "${a[@]}" -c:v msmpeg4 -c:a pcm_s16le -ac 1 -y "$work/d.avi"
|
||||
ff "${v[@]}" "${a[@]}" -c:v wmv2 -c:a wmav2 -y "$work/e.wmv"
|
||||
n=0
|
||||
for f in "$work"/*.avi "$work"/*.wmv; do
|
||||
ffprobe -v error -show_entries \
|
||||
stream=codec_type,codec_tag,width,height,sample_rate,channels,bit_rate,duration \
|
||||
-of default=nw=1 "$f" > "$f.probe"
|
||||
./rcontainer_test --ffprobe "$f" "$f.probe"
|
||||
n=$((n+1))
|
||||
done
|
||||
[ "$n" = 5 ]
|
||||
|
||||
# RGBA to 4:2:0 against swscale's with the same 2x2 chroma average
|
||||
# (area): every sample within 1, in each of FFmpeg's test patterns
|
||||
- name: Convert RGBA to yuv420p as swscale does
|
||||
if: matrix.group == 'formats'
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/formats/image_yuv
|
||||
run: |
|
||||
set -euo pipefail
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
for src in testsrc2=size=160x120 smptehdbars=size=320x180 \
|
||||
"gradients=size=256x144:speed=0.05" mandelbrot=size=200x150; do
|
||||
ffmpeg -nostdin -hide_banner -loglevel error -f lavfi -i "$src:rate=25" \
|
||||
-frames:v 8 -pix_fmt rgba -f rawvideo -y "$work/f.rgba"
|
||||
size=$(ffprobe -v error -f lavfi -i "$src:rate=25" -show_entries stream=width,height \
|
||||
-of csv=p=0 | head -1)
|
||||
ffmpeg -nostdin -hide_banner -loglevel error -f rawvideo -pix_fmt rgba \
|
||||
-s "${size/,/x}" -i "$work/f.rgba" -sws_flags area+accurate_rnd \
|
||||
-pix_fmt yuv420p -f rawvideo -y "$work/f.yuv"
|
||||
./image_yuv_test --ffmpeg "$work/f.rgba" "$work/f.yuv" ${size/,/ }
|
||||
done
|
||||
|
||||
- name: Frontend H.264 decode interface, v1 to v4, plain and under ASan/UBSan
|
||||
if: matrix.group == 'codecs'
|
||||
shell: bash
|
||||
@@ -841,6 +1373,20 @@ jobs:
|
||||
|
||||
TSAN_OPTIONS=halt_on_error=1 ./retro_atomic_test
|
||||
|
||||
- name: Run r7z_peek_threads_test under Clang + ThreadSanitizer
|
||||
if: matrix.group == 'core'
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/formats/r7z
|
||||
run: |
|
||||
# A folder peeked at while another thread decodes it, through
|
||||
# its being held: never torn, never the other folder's.
|
||||
set -u
|
||||
set -o pipefail
|
||||
|
||||
make clean
|
||||
CC=clang make -j$(nproc) r7z_peek_threads_test SANITIZER=thread
|
||||
TSAN_OPTIONS=halt_on_error=1 ./r7z_peek_threads_test
|
||||
|
||||
- name: Run video_player_test under Clang + ThreadSanitizer, and threadless
|
||||
if: matrix.group == 'core'
|
||||
shell: bash
|
||||
@@ -912,6 +1458,22 @@ jobs:
|
||||
|
||||
TSAN_OPTIONS=halt_on_error=1 ./audio_mixer_voice_threads_test
|
||||
|
||||
# Every 16-bit sample through convert_s16_to_ulaw against FFmpeg's
|
||||
# pcm_mulaw: all 65536 codes the same
|
||||
- name: Encode mu-law as FFmpeg's pcm_mulaw does
|
||||
if: matrix.group == 'core'
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/audio/float_to_ulaw
|
||||
run: |
|
||||
set -euo pipefail
|
||||
work=$(mktemp -d)
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
make -j2 all
|
||||
./float_to_ulaw_test --ramp "$work/ramp.s16"
|
||||
ffmpeg -nostdin -hide_banner -loglevel error -f s16le -ar 8000 -ac 1 \
|
||||
-i "$work/ramp.s16" -c:a pcm_mulaw -f mulaw -y "$work/ramp.ul"
|
||||
./float_to_ulaw_test --ffmpeg "$work/ramp.ul"
|
||||
|
||||
- name: Run mpsc_stack_test under Clang + ThreadSanitizer
|
||||
if: matrix.group == 'core'
|
||||
shell: bash
|
||||
@@ -1420,6 +1982,34 @@ jobs:
|
||||
-lwinmm -o thread_cleanup_test.exe
|
||||
timeout 30 wine ./thread_cleanup_test.exe
|
||||
|
||||
- name: rtt under Wine
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/gfx/font
|
||||
env:
|
||||
WINEDEBUG: -all
|
||||
run: |
|
||||
set -eu
|
||||
. "$GITHUB_WORKSPACE/.github/workflows/scripts/wine-server.sh"
|
||||
make clean
|
||||
make CC=x86_64-w64-mingw32-gcc all
|
||||
timeout 60 wine ./rtt_test.exe
|
||||
make clean
|
||||
|
||||
- name: socket_poll past FD_SETSIZE under Wine
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/net/socket_poll
|
||||
env:
|
||||
WINEDEBUG: -all
|
||||
run: |
|
||||
set -eu
|
||||
. "$GITHUB_WORKSPACE/.github/workflows/scripts/wine-server.sh"
|
||||
# select() takes 64 sockets a set; past that the sets are sized
|
||||
# for the call.
|
||||
make clean
|
||||
make CC=x86_64-w64-mingw32-gcc all
|
||||
timeout 60 wine ./socket_poll_test.exe
|
||||
make clean
|
||||
|
||||
- name: Build and run the NVIDIA loaders under Wine
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/gfx/nvidia
|
||||
|
||||
@@ -64,6 +64,15 @@ jobs:
|
||||
run: python3 samples/menu/rgui_media/run.py --c89 --cadence-hz 30 --driver materialui samples/menu/rgui_media/fixture.mp4
|
||||
- name: Real XMB file-browser playback controls
|
||||
run: python3 samples/menu/rgui_media/run.py --c89 --cadence-hz 30 --driver xmb samples/menu/rgui_media/fixture.mp4
|
||||
- name: QuickTime MOV browsing and external launch across all menus
|
||||
run: |
|
||||
ffmpeg -v error -y -i samples/menu/rgui_media/fixture.mp4 -map 0 -c copy -f mov samples/menu/rgui_media/fixture.mov
|
||||
python3 -c "import json,subprocess; p='samples/menu/rgui_media/fixture.mov'; d=json.loads(subprocess.check_output(['ffprobe','-v','error','-show_format','-of','json',p])); assert d['format']['tags']['major_brand']=='qt '"
|
||||
cp samples/menu/rgui_media/fixture.mov samples/menu/rgui_media/fixture-upper.MOV
|
||||
for driver in rgui materialui xmb ozone; do
|
||||
python3 samples/menu/rgui_media/run.py --c89 --driver "$driver" samples/menu/rgui_media/fixture.mov
|
||||
python3 samples/menu/rgui_media/run.py --c89 --external --driver "$driver" samples/menu/rgui_media/fixture-upper.MOV
|
||||
done
|
||||
- name: Real Ozone file-browser playback controls
|
||||
run: python3 samples/menu/rgui_media/run.py --c89 --cadence-hz 30 --driver ozone samples/menu/rgui_media/fixture.mp4
|
||||
- name: UTF-8 subtitle sidecars across all four menus
|
||||
@@ -188,6 +197,13 @@ jobs:
|
||||
xvfb-run -a python3 samples/menu/rgui_media/run.py --c89 --continuous-error --video-driver gl --driver "$driver" $threaded samples/menu/rgui_media/window-toggle.webm
|
||||
done
|
||||
done
|
||||
- name: External movie settings retain the playing preview
|
||||
run: |
|
||||
for driver in materialui xmb ozone; do
|
||||
for threaded in '' --threaded; do
|
||||
MEDIA_TEST_SETTINGS_ORANGE=1 xvfb-run -a python3 samples/menu/rgui_media/run.py --c89 --external --external-settings --video-driver gl --driver "$driver" $threaded samples/menu/rgui_media/settings-preview.webm
|
||||
done
|
||||
done
|
||||
- name: Generate delayed first-picture fixture
|
||||
run: ffmpeg -v error -y -f lavfi -i "testsrc2=size=320x240:rate=30,hue=h=90*t" -vf "setpts=PTS+0.2/TB" -t 3 -c:v libvpx -deadline realtime -cpu-used 8 -g 90 -auto-alt-ref 0 samples/menu/rgui_media/delayed.webm
|
||||
- name: Compare actual visible pictures after delayed-start seeks
|
||||
|
||||
@@ -87,10 +87,22 @@ jobs:
|
||||
# IP address matches only an iPAddress SAN entry, never the
|
||||
# same address written as a DNS name.
|
||||
samples/network/tls_retro/local_server_test.sh
|
||||
# One connection read and written from two threads at once
|
||||
# (SSL_RETRO_DUPLEX), under ThreadSanitizer
|
||||
make -C samples/network/tls_retro clean
|
||||
make -C samples/network/tls_retro tls_duplex CFLAGS='-O1 -g -fsanitize=thread -fno-omit-frame-pointer'
|
||||
TLS_TEST_DUPLEX_ONLY=1 TSAN_OPTIONS=halt_on_error=1 RUNNER="setarch $(uname -m) -R" \
|
||||
samples/network/tls_retro/local_server_test.sh
|
||||
# The same tool cross-linked for Windows: the sample's link
|
||||
# line has to carry Winsock, which nothing on Linux checks.
|
||||
make -C samples/network/tls_retro clean
|
||||
|
||||
- name: Incremental built-in TLS handshakes
|
||||
shell: bash
|
||||
run: |
|
||||
set -eu
|
||||
TLS_TEST_HANDSHAKE_STEP=1 samples/network/tls_retro/local_server_test.sh
|
||||
make -C samples/network/tls_retro clean
|
||||
|
||||
- name: Built-in SMB2/3 client against a local smbd
|
||||
shell: bash
|
||||
|
||||
@@ -1265,6 +1265,26 @@ jobs:
|
||||
make clean
|
||||
echo "[pass] udev_devices_test (ASan)"
|
||||
|
||||
- name: Build and run udev_touch_test (ASan + UBSan)
|
||||
shell: bash
|
||||
working-directory: samples/input/udev_touch
|
||||
run: |
|
||||
set -eu
|
||||
# The udev input driver's touchscreen support
|
||||
# (UDEV_TOUCH_SUPPORT), handed a panel in memory: its
|
||||
# ioctls are answered by the test and evdev frames are fed
|
||||
# to its event handler. The pointer is pressed while any
|
||||
# contact is down and released after the last; the pointer
|
||||
# device answers X, Y and pressed; a multi-touch panel's
|
||||
# single-touch emulation leaves the slots alone; a
|
||||
# single-touch panel's contact is slot 0; positions are
|
||||
# taken from the axis minimum.
|
||||
make clean SANITIZER=address,undefined && make -j$(nproc) all SANITIZER=address,undefined
|
||||
ASAN_OPTIONS=detect_leaks=1 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
|
||||
timeout 60 ./udev_touch_test
|
||||
make clean
|
||||
echo "[pass] udev_touch_test (ASan)"
|
||||
|
||||
- name: Build and run device_pins_test
|
||||
shell: bash
|
||||
working-directory: samples/input/device_pins
|
||||
|
||||
@@ -7,6 +7,10 @@ on:
|
||||
paths:
|
||||
- 'record/**'
|
||||
- 'libretro-common/net/net_rtmp*'
|
||||
- 'libretro-common/net/net_socket.c'
|
||||
- 'libretro-common/net/net_resolve.c'
|
||||
- 'libretro-common/include/net/net_resolve.h'
|
||||
- 'libretro-common/include/net/net_socket.h'
|
||||
- 'libretro-common/include/net/net_rtmp*'
|
||||
- 'libretro-common/formats/flv/**'
|
||||
- 'libretro-common/include/formats/rflv_mux.h'
|
||||
@@ -24,6 +28,10 @@ on:
|
||||
paths:
|
||||
- 'record/**'
|
||||
- 'libretro-common/net/net_rtmp*'
|
||||
- 'libretro-common/net/net_socket.c'
|
||||
- 'libretro-common/net/net_resolve.c'
|
||||
- 'libretro-common/include/net/net_resolve.h'
|
||||
- 'libretro-common/include/net/net_socket.h'
|
||||
- 'libretro-common/include/net/net_rtmp*'
|
||||
- 'libretro-common/formats/flv/**'
|
||||
- 'libretro-common/include/formats/rflv_mux.h'
|
||||
@@ -52,7 +60,7 @@ jobs:
|
||||
name: Build and run samples/record
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
APT_PKGS: mingw-w64 wine build-essential pkg-config ffmpeg libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev ccache
|
||||
APT_PKGS: clang mingw-w64 wine build-essential pkg-config ffmpeg openssl python3 libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev ccache
|
||||
timeout-minutes: 25
|
||||
|
||||
steps:
|
||||
@@ -141,6 +149,8 @@ jobs:
|
||||
make clean && make check CC=x86_64-w64-mingw32-gcc EXE=.exe RUNNER=wine
|
||||
make clean
|
||||
|
||||
|
||||
|
||||
- name: Native MP4 mux (ASan + UBSan, mingw-w64)
|
||||
shell: bash
|
||||
working-directory: samples/record/mp4_mux
|
||||
@@ -161,14 +171,73 @@ jobs:
|
||||
make clean && make check stream-check CC=x86_64-w64-mingw32-gcc EXE=.exe RUNNER=wine
|
||||
make clean
|
||||
|
||||
- name: RTMP protocol and sockets (ASan + UBSan, mingw-w64)
|
||||
- name: Media Foundation AAC portable and cross builds
|
||||
shell: bash
|
||||
working-directory: samples/record/mf_audio
|
||||
run: |
|
||||
set -eu
|
||||
make clean all SANITIZER=address,undefined
|
||||
make clean all CC=x86_64-w64-mingw32-gcc EXE=.exe
|
||||
x86_64-w64-mingw32-objdump -p encode_test.exe > imports.txt
|
||||
if grep -Ei 'DLL Name:.*(mfplat|mfaacenc|ole32)\.dll' imports.txt; then
|
||||
echo 'Native AAC must load optional entry points at runtime'
|
||||
exit 1
|
||||
fi
|
||||
make clean
|
||||
|
||||
- name: Pollable producer wake (Clang ASan + UBSan, mingw-w64)
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/net/wake
|
||||
run: |
|
||||
set -eu
|
||||
. "$GITHUB_WORKSPACE/.github/workflows/scripts/wine-server.sh"
|
||||
make clean && make check CC=clang SANITIZER=address,undefined
|
||||
make clean && make check CC=x86_64-w64-mingw32-gcc EXE=.exe RUNNER=wine
|
||||
make clean
|
||||
|
||||
- name: RTMP protocol and sockets (ASan + UBSan, TSan, mingw-w64)
|
||||
shell: bash
|
||||
working-directory: libretro-common/samples/net/rtmp
|
||||
run: |
|
||||
set -eu
|
||||
. "$GITHUB_WORKSPACE/.github/workflows/scripts/wine-server.sh"
|
||||
make clean && make rtmp_handshake_test CC=clang SANITIZER=address,undefined
|
||||
./rtmp_handshake_test
|
||||
make clean && make check peer-check SANITIZER=address,undefined
|
||||
make rtmps_socket_native_test SANITIZER=address,undefined
|
||||
python3 media_peer.py --mux --tls 1.2 ./rtmps_socket_native_test
|
||||
python3 media_peer.py --mux --tls 1.3 ./rtmps_socket_native_test
|
||||
make rtmps_client_native_test SANITIZER=address,undefined
|
||||
python3 media_peer.py --caps --mux --tls 1.2 ./rtmps_client_native_test
|
||||
python3 media_peer.py --caps --mux --tls 1.3 ./rtmps_client_native_test
|
||||
python3 media_peer.py --codec av1 --caps --mux --tls 1.2 ./rtmps_client_native_test
|
||||
python3 media_peer.py --codec av1 --caps --mux --tls 1.3 ./rtmps_client_native_test
|
||||
python3 media_peer.py --codec hevc --caps --mux --tls 1.2 ./rtmps_client_native_test
|
||||
python3 media_peer.py --codec hevc --caps --mux --tls 1.3 ./rtmps_client_native_test
|
||||
make clean && make rtmp_resolve_native_test SANITIZER=thread
|
||||
TSAN_OPTIONS=halt_on_error=1 timeout 30 ./rtmp_resolve_native_test
|
||||
make clean && make check peer-check CC=x86_64-w64-mingw32-gcc EXE=.exe RUNNER=wine
|
||||
make rtmps_socket_native_test.exe CC=x86_64-w64-mingw32-gcc EXE=.exe
|
||||
python3 media_peer.py --runner wine --mux --tls 1.2 ./rtmps_socket_native_test.exe
|
||||
python3 media_peer.py --runner wine --mux --tls 1.3 ./rtmps_socket_native_test.exe
|
||||
make rtmps_client_native_test.exe CC=x86_64-w64-mingw32-gcc EXE=.exe
|
||||
python3 media_peer.py --runner wine --caps --mux --tls 1.2 ./rtmps_client_native_test.exe
|
||||
python3 media_peer.py --runner wine --caps --mux --tls 1.3 ./rtmps_client_native_test.exe
|
||||
python3 media_peer.py --runner wine --codec av1 --caps --mux --tls 1.2 ./rtmps_client_native_test.exe
|
||||
python3 media_peer.py --runner wine --codec av1 --caps --mux --tls 1.3 ./rtmps_client_native_test.exe
|
||||
python3 media_peer.py --runner wine --codec hevc --caps --mux --tls 1.2 ./rtmps_client_native_test.exe
|
||||
python3 media_peer.py --runner wine --codec hevc --caps --mux --tls 1.3 ./rtmps_client_native_test.exe
|
||||
make clean
|
||||
|
||||
- name: Native encoder stream ownership contracts
|
||||
working-directory: samples/record/rtmp_stream
|
||||
run: |
|
||||
set -eu
|
||||
. "$GITHUB_WORKSPACE/.github/workflows/scripts/wine-server.sh"
|
||||
make clean check SANITIZER=address,undefined
|
||||
make clean vt_thread_test SANITIZER=thread
|
||||
TSAN_OPTIONS=halt_on_error=1 timeout 120 ./vt_thread_test
|
||||
make clean check CC=x86_64-w64-mingw32-gcc EXE=.exe RUNNER=wine
|
||||
make clean
|
||||
|
||||
- name: GPU PCM output pipeline (ASan + UBSan, TSan, mingw-w64)
|
||||
@@ -208,6 +277,16 @@ jobs:
|
||||
make clean && make check CC=x86_64-w64-mingw32-gcc EXE=.exe RUNNER=wine
|
||||
make clean
|
||||
|
||||
- name: AudioToolbox AAC input and packet ownership contracts
|
||||
working-directory: samples/record/audiotoolbox_audio
|
||||
run: |
|
||||
set -eu
|
||||
. "$GITHUB_WORKSPACE/.github/workflows/scripts/wine-server.sh"
|
||||
make clean && make check CC=clang
|
||||
make clean && make check SANITIZER=address,undefined
|
||||
make clean && make check CC=x86_64-w64-mingw32-gcc EXE=.exe RUNNER=wine
|
||||
make clean
|
||||
|
||||
# The Apple API stand-in checks ownership/configuration only. Native
|
||||
# compilation and hardware encode run in MacOS-videotoolbox-encode.yml.
|
||||
- name: VideoToolbox encode callback and session contracts
|
||||
@@ -241,3 +320,79 @@ jobs:
|
||||
with:
|
||||
path: ~/.ccache
|
||||
key: ccache-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}
|
||||
|
||||
mf-audio-native:
|
||||
name: Native Windows AAC packets and source clock
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Ensure the server media component is installed
|
||||
shell: pwsh
|
||||
run: |
|
||||
if ((Get-CimInstance Win32_OperatingSystem).ProductType -ne 1) {
|
||||
$feature = Get-WindowsFeature Server-Media-Foundation -ErrorAction Stop
|
||||
if (-not $feature.Installed) {
|
||||
$result = Install-WindowsFeature Server-Media-Foundation -ErrorAction Stop
|
||||
if (-not $result.Success) { throw 'Media Foundation installation failed' }
|
||||
}
|
||||
}
|
||||
|
||||
- name: Native compiler and independent decoder
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW64
|
||||
update: false
|
||||
install: make mingw-w64-x86_64-gcc mingw-w64-x86_64-python mingw-w64-x86_64-ffmpeg
|
||||
|
||||
- name: Encode and independently decode native AAC
|
||||
shell: msys2 {0}
|
||||
working-directory: samples/record/mf_audio
|
||||
run: |
|
||||
set -eu
|
||||
make clean native-check CC=gcc EXE=.exe
|
||||
objdump -p encode_test.exe > imports.txt
|
||||
if grep -Ei 'DLL Name:.*(mfplat|mfaacenc|ole32)\.dll' imports.txt; then
|
||||
echo 'Native AAC must load optional entry points at runtime'
|
||||
exit 1
|
||||
fi
|
||||
make clean
|
||||
|
||||
- name: Native Metal frontend profiles and source clocks
|
||||
shell: msys2 {0}
|
||||
working-directory: samples/record/metal_frontend
|
||||
run: |
|
||||
set -eu
|
||||
make clean
|
||||
make check CC=gcc EXE=.exe
|
||||
make clean
|
||||
|
||||
- name: Config include ownership and stack budget
|
||||
shell: msys2 {0}
|
||||
working-directory: libretro-common/samples/file/config_file
|
||||
run: |
|
||||
set -eu
|
||||
make clean
|
||||
make check CC=gcc EXE=.exe
|
||||
make clean CC=gcc EXE=.exe
|
||||
|
||||
- name: Native streaming worker readiness and cancellation
|
||||
shell: msys2 {0}
|
||||
working-directory: samples/record/gpu_dispatch
|
||||
run: |
|
||||
set -eu
|
||||
make clean
|
||||
make stream_dispatch_test.exe CC=gcc EXE=.exe
|
||||
./stream_dispatch_test.exe
|
||||
make clean
|
||||
|
||||
- name: Native FLV source color metadata interoperability
|
||||
shell: msys2 {0}
|
||||
working-directory: libretro-common/samples/formats/flv
|
||||
run: |
|
||||
set -eu
|
||||
make clean
|
||||
make check stream-check CC=gcc EXE=.exe COLOR_METADATA_ORACLE=1
|
||||
make clean
|
||||
@@ -958,6 +958,14 @@ jobs:
|
||||
python3 samples/menu/rgui_media/run.py --driver rgui --video-driver ${{ matrix.driver }} --gpu-surface --refresh-pixels samples/menu/rgui_media/fixture.mp4
|
||||
python3 samples/menu/rgui_media/run.py --driver rgui --video-driver ${{ matrix.driver }} --gpu-surface --continuous-error samples/menu/rgui_media/fixture.mp4
|
||||
|
||||
- name: External Ozone movie settings at drive root and in a subfolder
|
||||
if: matrix.driver == 'd3d11'
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
set -eu
|
||||
ffmpeg -v error -y -f lavfi -i color=orange:size=320x240:rate=30 -t 3 -c:v libx264 -preset ultrafast -pix_fmt yuv420p samples/menu/rgui_media/settings-preview.mp4
|
||||
MEDIA_TEST_SETTINGS_ORANGE=1 python3 samples/menu/texture_media/external_settings_paths.py samples/menu/rgui_media/settings-preview.mp4 --video-driver ${{ matrix.driver }} --threaded
|
||||
|
||||
views-sdl3:
|
||||
name: Views on SDL3, end to end (Xvfb, llvmpipe)
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -56,6 +56,24 @@ jobs:
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up MSYS2
|
||||
id: msys2
|
||||
continue-on-error: true
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.sys }}
|
||||
update: true
|
||||
|
||||
# setup-msys2 has no retry of its own, and its system upgrade fails
|
||||
# the job when mirror.msys2.org stalls ("Operation too slow") on the
|
||||
# package databases. A failed attempt is run once more after a
|
||||
# minute; the second reinstalls over the first.
|
||||
- name: Wait before retrying MSYS2
|
||||
if: steps.msys2.outcome == 'failure'
|
||||
shell: bash
|
||||
run: sleep 60
|
||||
|
||||
- name: Set up MSYS2 (retry)
|
||||
if: steps.msys2.outcome == 'failure'
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.sys }}
|
||||
|
||||
@@ -17,7 +17,21 @@ on:
|
||||
- 'record/record_gpu_session_metal.*'
|
||||
- 'record/record_gpu_dispatch_metal.*'
|
||||
- 'record/record_gpu_worker_vt*'
|
||||
- 'record/record_vt_packet.*'
|
||||
- 'record/record_stream_vt.*'
|
||||
- 'record/record_stream_output_vt.*'
|
||||
- 'record/record_stream_session_vt_native.h'
|
||||
- 'samples/record/rtmp_stream/**'
|
||||
- 'libretro-common/net/net_rtmp*'
|
||||
- 'libretro-common/include/net/net_rtmp*'
|
||||
- 'libretro-common/formats/flv/**'
|
||||
- 'libretro-common/include/formats/rflv_mux.h'
|
||||
- 'libretro-common/include/formats/rav1_sequence.h'
|
||||
- 'libretro-common/include/formats/video_color.h'
|
||||
- 'record/record_audio_queue.*'
|
||||
- 'record/record_at_audio.*'
|
||||
- 'record/record_at_resample.*'
|
||||
- 'samples/record/audiotoolbox_audio/**'
|
||||
- 'record/record_avfoundation_worker*'
|
||||
- 'record/record_avfoundation_session*'
|
||||
- 'record/record_mux_avfoundation.*'
|
||||
@@ -42,7 +56,21 @@ on:
|
||||
- 'record/record_gpu_session_metal.*'
|
||||
- 'record/record_gpu_dispatch_metal.*'
|
||||
- 'record/record_gpu_worker_vt*'
|
||||
- 'record/record_vt_packet.*'
|
||||
- 'record/record_stream_vt.*'
|
||||
- 'record/record_stream_output_vt.*'
|
||||
- 'record/record_stream_session_vt_native.h'
|
||||
- 'samples/record/rtmp_stream/**'
|
||||
- 'libretro-common/net/net_rtmp*'
|
||||
- 'libretro-common/include/net/net_rtmp*'
|
||||
- 'libretro-common/formats/flv/**'
|
||||
- 'libretro-common/include/formats/rflv_mux.h'
|
||||
- 'libretro-common/include/formats/rav1_sequence.h'
|
||||
- 'libretro-common/include/formats/video_color.h'
|
||||
- 'record/record_audio_queue.*'
|
||||
- 'record/record_at_audio.*'
|
||||
- 'record/record_at_resample.*'
|
||||
- 'samples/record/audiotoolbox_audio/**'
|
||||
- 'record/record_avfoundation_worker*'
|
||||
- 'record/record_avfoundation_session*'
|
||||
- 'record/record_mux_avfoundation.*'
|
||||
@@ -52,10 +80,111 @@ on:
|
||||
- 'samples/record/metal_frontend/**'
|
||||
- 'libretro-common/include/retro_atomic.h'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
native_aac_only:
|
||||
description: 'Run native AudioToolbox AAC acceptance without GPU/frontend jobs'
|
||||
type: boolean
|
||||
default: false
|
||||
frontend_stream_only:
|
||||
description: 'Run frontend streaming acceptance and both native frontend links'
|
||||
type: boolean
|
||||
default: false
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
stream-native:
|
||||
if: ${{ !inputs.native_aac_only && !inputs.frontend_stream_only }}
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Install independent streaming receiver
|
||||
run: command -v ffmpeg >/dev/null && command -v ffprobe >/dev/null || brew install ffmpeg
|
||||
- name: Pollable producer wake and socket readiness
|
||||
run: make -C libretro-common/samples/net/wake check
|
||||
- name: Native VT and AAC over RTMP and TLS
|
||||
env:
|
||||
VT_STREAM_ARTIFACT_DIR: ${{ runner.temp }}/vt-stream-evidence
|
||||
run: python3 samples/record/rtmp_stream/native_vt_run.py
|
||||
- name: Save native streaming acceptance evidence
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: vt-stream-evidence
|
||||
path: ${{ runner.temp }}/vt-stream-evidence
|
||||
if-no-files-found: ignore
|
||||
- name: Native Metal factory RTMP and TLS with ARC
|
||||
if: ${{ !cancelled() }}
|
||||
env:
|
||||
VT_STREAM_ARTIFACT_DIR: ${{ runner.temp }}/vt-metal-stream-arc
|
||||
run: python3 samples/record/rtmp_stream/native_vt_run.py --metal --ownership arc
|
||||
- name: Native Metal factory RTMP and TLS with manual reference counting
|
||||
if: ${{ !cancelled() }}
|
||||
env:
|
||||
VT_STREAM_ARTIFACT_DIR: ${{ runner.temp }}/vt-metal-stream-mrc
|
||||
run: python3 samples/record/rtmp_stream/native_vt_run.py --metal --ownership mrc
|
||||
- name: Save native Metal streaming acceptance evidence
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: vt-metal-stream-evidence
|
||||
path: |
|
||||
${{ runner.temp }}/vt-metal-stream-arc
|
||||
${{ runner.temp }}/vt-metal-stream-mrc
|
||||
if-no-files-found: ignore
|
||||
- name: Native URL-owning Metal streaming dispatcher with ARC
|
||||
if: ${{ !cancelled() }}
|
||||
env:
|
||||
VT_STREAM_ARTIFACT_DIR: ${{ runner.temp }}/vt-metal-dispatch-arc
|
||||
run: python3 samples/record/rtmp_stream/native_vt_run.py --dispatcher --ownership arc
|
||||
- name: Native URL-owning Metal streaming dispatcher with manual reference counting
|
||||
if: ${{ !cancelled() }}
|
||||
env:
|
||||
VT_STREAM_ARTIFACT_DIR: ${{ runner.temp }}/vt-metal-dispatch-mrc
|
||||
run: python3 samples/record/rtmp_stream/native_vt_run.py --dispatcher --ownership mrc
|
||||
- name: Save native Metal dispatcher acceptance evidence
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: vt-metal-dispatch-evidence
|
||||
path: |
|
||||
${{ runner.temp }}/vt-metal-dispatch-arc
|
||||
${{ runner.temp }}/vt-metal-dispatch-mrc
|
||||
if-no-files-found: ignore
|
||||
aac-native:
|
||||
if: ${{ inputs.native_aac_only || !inputs.frontend_stream_only }}
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Install independent AAC test decoder
|
||||
run: command -v ffmpeg >/dev/null || brew install ffmpeg
|
||||
- name: AudioToolbox AAC callback ownership contracts
|
||||
run: make -C samples/record/audiotoolbox_audio check
|
||||
- name: Native AudioToolbox AAC packets and independent timing
|
||||
env:
|
||||
AUDIO_TOOLBOX_ARTIFACT_DIR: ${{ runner.temp }}/audiotoolbox-aac-evidence
|
||||
run: make -C samples/record/audiotoolbox_audio native-check
|
||||
- name: Save AudioToolbox AAC acceptance evidence
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: audiotoolbox-aac-evidence
|
||||
path: ${{ runner.temp }}/audiotoolbox-aac-evidence
|
||||
if-no-files-found: ignore
|
||||
- name: Native source-rate conversion and independent AAC timing
|
||||
env:
|
||||
AUDIO_TOOLBOX_SRC_ARTIFACT_DIR: ${{ runner.temp }}/audiotoolbox-src-evidence
|
||||
run: make -C samples/record/audiotoolbox_audio native-src-check
|
||||
- name: Save AudioToolbox SRC acceptance evidence
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: audiotoolbox-src-evidence
|
||||
path: ${{ runner.temp }}/audiotoolbox-src-evidence
|
||||
if-no-files-found: ignore
|
||||
encode:
|
||||
if: ${{ !inputs.native_aac_only && !inputs.frontend_stream_only }}
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
@@ -68,6 +197,8 @@ jobs:
|
||||
- name: Portable ownership and failure contracts
|
||||
working-directory: samples/record/videotoolbox_encode
|
||||
run: make check thread_test worker_thread_test audio_thread_test av_session_thread_test && ./thread_test && ./worker_thread_test && ./audio_thread_test && ./av_session_thread_test
|
||||
- name: VideoToolbox AAC streaming ownership and independent wire clock
|
||||
run: make -C samples/record/rtmp_stream vt-check
|
||||
- name: Native AAC property ABI and advertised rates
|
||||
run: make -C samples/record/videotoolbox_encode native-audio-check
|
||||
- name: Native hardware encoder and independent pixels
|
||||
@@ -154,6 +285,7 @@ jobs:
|
||||
if-no-files-found: warn
|
||||
|
||||
frontend-build:
|
||||
if: ${{ !inputs.native_aac_only && !inputs.frontend_stream_only }}
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 40
|
||||
steps:
|
||||
@@ -189,7 +321,58 @@ jobs:
|
||||
path: ${{ runner.temp }}/metal-frontend-recordings
|
||||
if-no-files-found: warn
|
||||
|
||||
frontend-stream-build:
|
||||
if: ${{ !inputs.native_aac_only }}
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 20
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
threads: [enable, disable]
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Configure network-enabled Metal frontend
|
||||
run: |
|
||||
set -eu
|
||||
stream_options=
|
||||
if [ "${{ matrix.threads }}" = disable ]; then
|
||||
stream_options="--enable-rtmp --enable-rflv"
|
||||
fi
|
||||
./configure --enable-metal --enable-avf --${{ matrix.threads }}-threads --enable-configfile --enable-webmplayer \
|
||||
--disable-qt --disable-ffmpeg --disable-discord --disable-cheevos \
|
||||
--enable-networking --disable-sdl2 --disable-sdl --disable-translate \
|
||||
--disable-update_cores --disable-update_assets --disable-online_updater \
|
||||
--disable-cdrom --disable-7zip --enable-ssl --enable-retrossl $stream_options
|
||||
for feature in HAVE_METAL HAVE_AVF HAVE_NETWORKING HAVE_CRYPTO HAVE_RTMP HAVE_RFLV HAVE_RETROSSL; do
|
||||
grep -Eq "^#define $feature 1" config.h
|
||||
done
|
||||
- name: Link network worker and threadless fallback
|
||||
run: |
|
||||
set -eu
|
||||
make -j"$(sysctl -n hw.ncpu)" \
|
||||
MINVERFLAGS="-mmacosx-version-min=$(sw_vers -productVersion)"
|
||||
test -x retroarch
|
||||
nm retroarch | grep '_record_gpu_dispatch_metal_new_stream'
|
||||
- name: Native frontend streaming through command start and stop
|
||||
if: ${{ matrix.threads == 'enable' }}
|
||||
run: |
|
||||
set -eu
|
||||
command -v ffmpeg >/dev/null && command -v ffprobe >/dev/null || brew install ffmpeg
|
||||
cc -dynamiclib -std=gnu89 -Ilibretro-common/include samples/record/metal_frontend/core.c -o "$RUNNER_TEMP/metal-stream-core.dylib" -lm
|
||||
python3 samples/record/metal_frontend/stream.py --retroarch ./retroarch --core "$RUNNER_TEMP/metal-stream-core.dylib" --video-buffer-frames 2 --output-dir "$RUNNER_TEMP/metal-frontend-stream/h264"
|
||||
python3 samples/record/metal_frontend/stream.py --retroarch ./retroarch --core "$RUNNER_TEMP/metal-stream-core.dylib" --codec hevc --source-rate 32040.5 --video-buffer-frames 16 --output-dir "$RUNNER_TEMP/metal-frontend-stream/fractional"
|
||||
python3 samples/record/metal_frontend/stream.py --retroarch ./retroarch --core "$RUNNER_TEMP/metal-stream-core.dylib" --channels 1 --source-rate 44100 --video-buffer-frames 8 --output-dir "$RUNNER_TEMP/metal-frontend-stream/mono"
|
||||
python3 samples/record/metal_frontend/stream.py --retroarch ./retroarch --core "$RUNNER_TEMP/metal-stream-core.dylib" --video-only --video-buffer-frames 4 --output-dir "$RUNNER_TEMP/metal-frontend-stream/video-only"
|
||||
- name: Save real frontend streaming evidence
|
||||
if: ${{ always() && matrix.threads == 'enable' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: metal-frontend-stream-evidence
|
||||
path: ${{ runner.temp }}/metal-frontend-stream
|
||||
if-no-files-found: ignore
|
||||
|
||||
frontend-contracts:
|
||||
if: ${{ !inputs.native_aac_only }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
@@ -1082,7 +1082,7 @@ check_gates "griffin: HAVE_RETROSMB + cloud sync" "$UIDEFS -DRARCH_INTERNAL -DH
|
||||
# griffin can carry. A static helper in one translation unit that
|
||||
# another one also defines (get32 in net_smb2.c and rvorbis.c) only
|
||||
# collides here, so this lane carries as much of griffin as a host can.
|
||||
GRIFFIN_FULL="-DRARCH_INTERNAL -DHAVE_GRIFFIN=1 -DHAVE_MENU -DHAVE_RGUI -DHAVE_XMB -DHAVE_OZONE -DHAVE_MATERIALUI -DHAVE_GFX_WIDGETS -DHAVE_OVERLAY -DHAVE_CONFIGFILE -DHAVE_CHEEVOS -DRC_DISABLE_LUA -DHAVE_RUNAHEAD -DHAVE_REWIND -DHAVE_PATCH -DHAVE_XDELTA -DHAVE_CHEATS -DHAVE_SCREENSHOTS -DHAVE_TRANSLATE -DHAVE_LIBRETRODB -DHAVE_DYNAMIC -DHAVE_DYLIB -DHAVE_THREADS -DHAVE_AUDIOMIXER -DHAVE_DSP_FILTER -DHAVE_VIDEO_FILTER -DHAVE_RWAV -DHAVE_RFLAC -DHAVE_RVORBIS -DHAVE_RMP3 -DHAVE_RAC3 -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DHAVE_RWEBP -DHAVE_RDDS -DHAVE_RZSTD -DHAVE_7ZIP -DHAVE_CHD -DHAVE_RCHD -DHAVE_STB_FONT -DHAVE_NETWORKING -DHAVE_IFINFO -DHAVE_NETWORK_CMD -DHAVE_NETPLAYDISCOVERY -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_ASSETS -DHAVE_UPDATE_CORES -DHAVE_UPDATE_CORE_INFO -DHAVE_CORE_INFO_CACHE -DHAVE_CLOUDSYNC -DHAVE_S3 -DHAVE_CRYPTO -DHAVE_KEYCHAIN -DHAVE_SSL -DHAVE_RETROSSL -DHAVE_SMBCLIENT -DHAVE_RETROSMB -DHAVE_NFSCLIENT -DHAVE_RETRONFS -DHAVE_LANGEXTRA -DHAVE_SHADERPIPELINE -DHAVE_GLSL -DHAVE_OPENGL -D_GNU_SOURCE"
|
||||
GRIFFIN_FULL="-DRARCH_INTERNAL -DHAVE_GRIFFIN=1 -DHAVE_MENU -DHAVE_RGUI -DHAVE_XMB -DHAVE_OZONE -DHAVE_MATERIALUI -DHAVE_GFX_WIDGETS -DHAVE_OVERLAY -DHAVE_CONFIGFILE -DHAVE_CHEEVOS -DRC_DISABLE_LUA -DHAVE_RUNAHEAD -DHAVE_REWIND -DHAVE_PATCH -DHAVE_XDELTA -DHAVE_CHEATS -DHAVE_SCREENSHOTS -DHAVE_TRANSLATE -DHAVE_LIBRETRODB -DHAVE_DYNAMIC -DHAVE_DYLIB -DHAVE_THREADS -DHAVE_AUDIOMIXER -DHAVE_DSP_FILTER -DHAVE_VIDEO_FILTER -DHAVE_RWAV -DHAVE_RFLAC -DHAVE_RVORBIS -DHAVE_RMP3 -DHAVE_RAC3 -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DHAVE_RGIF -DHAVE_RWEBP -DHAVE_RDDS -DHAVE_RZSTD -DHAVE_7ZIP -DHAVE_CHD -DHAVE_RCHD -DHAVE_STB_FONT -DHAVE_NETWORKING -DHAVE_IFINFO -DHAVE_NETWORK_CMD -DHAVE_NETPLAYDISCOVERY -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_ASSETS -DHAVE_UPDATE_CORES -DHAVE_UPDATE_CORE_INFO -DHAVE_CORE_INFO_CACHE -DHAVE_CLOUDSYNC -DHAVE_S3 -DHAVE_CRYPTO -DHAVE_KEYCHAIN -DHAVE_SSL -DHAVE_RETROSSL -DHAVE_SMBCLIENT -DHAVE_RETROSMB -DHAVE_NFSCLIENT -DHAVE_RETRONFS -DHAVE_LANGEXTRA -DHAVE_SHADERPIPELINE -DHAVE_GLSL -DHAVE_OPENGL -D_GNU_SOURCE"
|
||||
check_gates "griffin: full unity (every codec + network stack)" "$UIDEFS $GRIFFIN_FULL" griffin/griffin.c
|
||||
# The SMB show-settings row read a HAVE_MENU-only default under
|
||||
# HAVE_SMBCLIENT alone; with the built-in client on by default that
|
||||
|
||||
@@ -403,3 +403,4 @@ samples/record/ffmpeg_pipeline/record_finalize_fragment.c
|
||||
samples/record/ffmpeg_pipeline/record_start_fragment.c
|
||||
samples/input/sensor_subdevice/core_sensor_fragment.c
|
||||
samples/input/bind_capture/driver_code.inc
|
||||
samples/record/metal_frontend/profile_fragment.c
|
||||
+39
-5
@@ -1126,7 +1126,8 @@ ifeq ($(HAVE_OVERLAY), 1)
|
||||
led/drivers/led_overlay.o
|
||||
endif
|
||||
|
||||
OBJ += gfx/drivers_font_renderer/stb.o
|
||||
OBJ += gfx/drivers_font_renderer/stb.o \
|
||||
$(LIBRETRO_COMM_DIR)/gfx/font/rtt.o
|
||||
|
||||
ifeq ($(HAVE_FREETYPE), 1)
|
||||
OBJ += gfx/drivers_font_renderer/freetype.o
|
||||
@@ -1703,6 +1704,17 @@ ifeq ($(HAVE_METAL), 1)
|
||||
record/record_gpu_session_metal.o \
|
||||
record/record_gpu_dispatch_metal.o \
|
||||
$(LIBRETRO_COMM_DIR)/formats/h265/rh265_sps_crop.o
|
||||
ifeq ($(HAVE_NETWORKING), 1)
|
||||
ifeq ($(HAVE_RTMP), 1)
|
||||
ifeq ($(HAVE_RFLV), 1)
|
||||
OBJ += record/record_stream_vt.o \
|
||||
record/record_stream_output_vt.o \
|
||||
record/record_at_resample.o \
|
||||
record/record_vt_packet.o \
|
||||
$(LIBRETRO_COMM_DIR)/net/net_wake.o
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
LIBS += -framework CoreMedia -framework VideoToolbox -framework AudioToolbox
|
||||
endif
|
||||
endif
|
||||
@@ -2038,6 +2050,20 @@ ifeq ($(HAVE_D3D12), 1)
|
||||
DEFINES += -DHAVE_D3D12
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_MF_AUDIO), 1)
|
||||
ifneq ($(findstring Win32,$(OS)),)
|
||||
DEFINES += -DHAVE_MF_AUDIO
|
||||
OBJ += record/record_mf_audio.o
|
||||
ifeq ($(HAVE_RTMP), 1)
|
||||
ifeq ($(HAVE_RFLV), 1)
|
||||
ifeq ($(HAVE_D3D12), 1)
|
||||
OBJ += record/record_stream_d3d12.o
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# H.264 previews decoded on the GPU, as rh264's backend; D3D12 imports
|
||||
# its frames as well
|
||||
ifneq ($(findstring 1, $(HAVE_D3D11) $(HAVE_D3D12)),)
|
||||
@@ -2523,6 +2549,11 @@ ifeq ($(HAVE_RTGA), 1)
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/formats/tga/rtga.o
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_RGIF), 1)
|
||||
DEFINES += -DHAVE_RGIF
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/formats/gif/rgif.o
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_RDDS), 1)
|
||||
DEFINES += -DHAVE_RDDS
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/formats/dds/rdds.o
|
||||
@@ -2664,10 +2695,11 @@ endif
|
||||
# when HAVE_AVF is on.
|
||||
ifeq ($(HAVE_AVF), 1)
|
||||
DEFINES += -DHAVE_AVF
|
||||
OBJ += camera/drivers/avfoundation.o \
|
||||
OBJ += record/record_at_audio.o \
|
||||
camera/drivers/avfoundation.o \
|
||||
record/drivers/record_avfoundation.o
|
||||
LIBS += -framework AVFoundation -framework CoreVideo \
|
||||
-framework CoreMedia -framework Accelerate
|
||||
-framework CoreMedia -framework Accelerate -framework AudioToolbox
|
||||
ifeq ($(HAVE_COCOATOUCH), 1)
|
||||
LIBS += -framework UIKit
|
||||
endif
|
||||
@@ -2760,12 +2792,14 @@ ifeq ($(HAVE_NETWORKING), 1)
|
||||
$(LIBRETRO_COMM_DIR)/net/net_rtmp_receive.o \
|
||||
$(LIBRETRO_COMM_DIR)/net/net_rtmp_reply.o \
|
||||
$(LIBRETRO_COMM_DIR)/net/net_rtmp_session.o \
|
||||
$(LIBRETRO_COMM_DIR)/net/net_rtmp_socket.o
|
||||
$(LIBRETRO_COMM_DIR)/net/net_rtmp_socket.o \
|
||||
$(LIBRETRO_COMM_DIR)/net/net_rtmp_client.o
|
||||
endif
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/net/net_compat.o \
|
||||
$(LIBRETRO_COMM_DIR)/net/net_http.o \
|
||||
$(LIBRETRO_COMM_DIR)/net/net_http_parse.o \
|
||||
$(LIBRETRO_COMM_DIR)/net/net_socket.o \
|
||||
$(LIBRETRO_COMM_DIR)/net/net_resolve.o \
|
||||
core_updater_list.o \
|
||||
network/natt.o \
|
||||
network/natt_desc.o \
|
||||
@@ -3378,7 +3412,7 @@ ifeq ($(HAVE_RECORD_MEDIACODEC), 1)
|
||||
DEFINES += -DHAVE_RECORD_MEDIACODEC
|
||||
MEDIA_RECORD_OBJ := record/record_mediacodec_encoder.o \
|
||||
record/record_audio_tap.o \
|
||||
record/record_mux_mediacodec.o record/record_mediacodec_worker.o \
|
||||
record/record_mux_mediacodec.o record/record_mediacodec_worker.o record/record_aac_stream_timing.o \
|
||||
record/record_aac_probe.o \
|
||||
record/record_mp4_audio_edit.o record/record_mediacodec_file_edit.o \
|
||||
record/record_mediacodec_surface.o record/record_mediacodec_file.o \
|
||||
|
||||
+2
-1
@@ -53,7 +53,7 @@ DEFINES :=
|
||||
ifeq ($(GRIFFIN_BUILD), 1)
|
||||
OBJ += griffin/griffin.o
|
||||
DEFINES += -DHAVE_GRIFFIN=1 -DHAVE_MENU -DHAVE_CONFIGFILE -DHAVE_RGUI -DHAVE_XMB -DHAVE_LIBRETRODB -DHAVE_CC_RESAMPLER
|
||||
DEFINES += -DHAVE_7ZIP -DHAVE_RZSTD -DHAVE_RPNG -DHAVE_RWEBP -DHAVE_RDDS -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA
|
||||
DEFINES += -DHAVE_7ZIP -DHAVE_RZSTD -DHAVE_RPNG -DHAVE_RWEBP -DHAVE_RDDS -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DHAVE_RGIF
|
||||
DEFINES += -DHAVE_NETWORKING -DHAVE_IFINFO -DHAVE_CHEEVOS -DRC_DISABLE_LUA -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_CORES
|
||||
DEFINES += -DHAVE_UPDATE_CORE_INFO
|
||||
#DEFINES += -DHAVE_UPDATE_ASSETS
|
||||
@@ -73,6 +73,7 @@ else
|
||||
HAVE_CC_RESAMPLER = 1
|
||||
HAVE_MENU_COMMON = 1
|
||||
HAVE_RTGA = 1
|
||||
HAVE_RGIF = 1
|
||||
HAVE_RPNG = 1
|
||||
HAVE_RWEBP = 1
|
||||
HAVE_RDDS = 1
|
||||
|
||||
@@ -34,6 +34,7 @@ HAVE_AUDIOMIXER = 1
|
||||
HAVE_CC_RESAMPLER = 1
|
||||
HAVE_MENU_COMMON = 1
|
||||
HAVE_RTGA = 1
|
||||
HAVE_RGIF = 1
|
||||
HAVE_RPNG = 1
|
||||
HAVE_RWEBP = 1
|
||||
HAVE_RDDS = 1
|
||||
|
||||
@@ -34,6 +34,7 @@ HAVE_AUDIOMIXER = 1
|
||||
HAVE_CC_RESAMPLER = 1
|
||||
HAVE_MENU_COMMON = 1
|
||||
HAVE_RTGA = 1
|
||||
HAVE_RGIF = 1
|
||||
HAVE_RPNG = 1
|
||||
HAVE_RJPEG = 1
|
||||
HAVE_RBMP = 1
|
||||
|
||||
@@ -196,6 +196,7 @@ else ifeq ($(libogc_platform), 1)
|
||||
HAVE_RJPEG := 1
|
||||
HAVE_RBMP := 1
|
||||
HAVE_RTGA := 1
|
||||
HAVE_RGIF := 1
|
||||
HAVE_RMODTRACKER := 1
|
||||
HAVE_OVERLAY := 1
|
||||
HAVE_7ZIP := 1
|
||||
@@ -272,6 +273,7 @@ else ifeq ($(platform), psp1)
|
||||
HAVE_RJPEG := 1
|
||||
HAVE_RBMP := 1
|
||||
HAVE_RTGA := 1
|
||||
HAVE_RGIF := 1
|
||||
HAVE_KERNEL_PRX := 1
|
||||
#HAVE_LANGEXTRA := 1
|
||||
RARCH_CONSOLE = 1
|
||||
@@ -324,6 +326,7 @@ else ifeq ($(platform), vita)
|
||||
HAVE_RJPEG := 1
|
||||
HAVE_RBMP := 1
|
||||
HAVE_RTGA := 1
|
||||
HAVE_RGIF := 1
|
||||
HAVE_7ZIP := 1
|
||||
HAVE_GXM := 1
|
||||
HAVE_NETWORKING := 1
|
||||
@@ -346,6 +349,7 @@ else ifeq ($(platform), windows_msvc6_x86)
|
||||
HAVE_RJPEG := 1
|
||||
HAVE_RBMP := 1
|
||||
HAVE_RTGA := 1
|
||||
HAVE_RGIF := 1
|
||||
HAVE_7ZIP := 1
|
||||
HAVE_NETWORKING := 0
|
||||
HAVE_IFINFO := 0
|
||||
@@ -397,6 +401,7 @@ else ifeq ($(platform), windows_msvc2003_x86)
|
||||
HAVE_RJPEG := 1
|
||||
HAVE_RBMP := 1
|
||||
HAVE_RTGA := 1
|
||||
HAVE_RGIF := 1
|
||||
HAVE_7ZIP := 1
|
||||
HAVE_NETWORKING := 1
|
||||
HAVE_IFINFO := 0
|
||||
@@ -454,6 +459,7 @@ else ifeq ($(platform), windows_msvc2005_x86)
|
||||
HAVE_RJPEG := 1
|
||||
HAVE_RBMP := 1
|
||||
HAVE_RTGA := 1
|
||||
HAVE_RGIF := 1
|
||||
HAVE_7ZIP := 1
|
||||
HAVE_NETWORKING := 1
|
||||
HAVE_IFINFO := 0
|
||||
@@ -542,6 +548,7 @@ else ifneq (,$(findstring windows_msvc2010,$(platform)))
|
||||
HAVE_RJPEG := 1
|
||||
HAVE_RBMP := 1
|
||||
HAVE_RTGA := 1
|
||||
HAVE_RGIF := 1
|
||||
HAVE_7ZIP := 1
|
||||
HAVE_NETWORKING := 1
|
||||
HAVE_IFINFO := 1
|
||||
@@ -638,6 +645,7 @@ else ifneq (,$(findstring windows_msvc2012,$(platform)))
|
||||
HAVE_RJPEG := 1
|
||||
HAVE_RBMP := 1
|
||||
HAVE_RTGA := 1
|
||||
HAVE_RGIF := 1
|
||||
HAVE_7ZIP := 1
|
||||
HAVE_NETWORKING := 1
|
||||
HAVE_IFINFO := 1
|
||||
@@ -725,6 +733,7 @@ else ifneq (,$(findstring windows_msvc2013,$(platform)))
|
||||
HAVE_RJPEG := 1
|
||||
HAVE_RBMP := 1
|
||||
HAVE_RTGA := 1
|
||||
HAVE_RGIF := 1
|
||||
HAVE_7ZIP := 1
|
||||
HAVE_NETWORKING := 1
|
||||
HAVE_IFINFO := 1
|
||||
@@ -812,6 +821,7 @@ else ifneq (,$(findstring windows_msvc2015,$(platform)))
|
||||
HAVE_RJPEG := 1
|
||||
HAVE_RBMP := 1
|
||||
HAVE_RTGA := 1
|
||||
HAVE_RGIF := 1
|
||||
HAVE_7ZIP := 1
|
||||
HAVE_NETWORKING := 1
|
||||
HAVE_IFINFO := 1
|
||||
@@ -914,6 +924,7 @@ else ifeq (qnx,$(platform))
|
||||
HAVE_RJPEG := 1
|
||||
HAVE_RBMP := 1
|
||||
HAVE_RTGA := 1
|
||||
HAVE_RGIF := 1
|
||||
HAVE_7ZIP := 1
|
||||
HAVE_NETWORKING := 1
|
||||
HAVE_IFINFO := 1
|
||||
@@ -960,6 +971,7 @@ else ifneq (,$(findstring unix,$(platform)))
|
||||
HAVE_RJPEG := 1
|
||||
HAVE_RBMP := 1
|
||||
HAVE_RTGA := 1
|
||||
HAVE_RGIF := 1
|
||||
HAVE_7ZIP := 1
|
||||
HAVE_NETWORKING := 1
|
||||
HAVE_IFINFO := 1
|
||||
@@ -1077,6 +1089,9 @@ endif
|
||||
ifeq ($(HAVE_RTGA), 1)
|
||||
CFLAGS += -DHAVE_RTGA
|
||||
endif
|
||||
ifeq ($(HAVE_RGIF), 1)
|
||||
CFLAGS += -DHAVE_RGIF
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_BSV_MOVIE), 1)
|
||||
CFLAGS += -DHAVE_BSV_MOVIE
|
||||
@@ -1129,6 +1144,12 @@ ifeq ($(HAVE_RFLV), 1)
|
||||
CFLAGS += -DHAVE_RFLV
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_MF_AUDIO), 1)
|
||||
ifeq ($(system_platform), win)
|
||||
CFLAGS += -DHAVE_MF_AUDIO
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_IFINFO), 1)
|
||||
CFLAGS += -DHAVE_IFINFO
|
||||
endif
|
||||
|
||||
@@ -29,6 +29,7 @@ HAVE_AUDIOMIXER = 1
|
||||
HAVE_CC_RESAMPLER = 1
|
||||
HAVE_MENU_COMMON = 1
|
||||
HAVE_RTGA = 1
|
||||
HAVE_RGIF = 1
|
||||
HAVE_RPNG = 1
|
||||
HAVE_RWEBP = 1
|
||||
HAVE_RDDS = 1
|
||||
|
||||
@@ -54,6 +54,7 @@ HAVE_MENU_COMMON := 1
|
||||
HAVE_RJPEG := 1
|
||||
HAVE_RBMP := 1
|
||||
HAVE_RTGA := 1
|
||||
HAVE_RGIF := 1
|
||||
HAVE_7ZIP := 1
|
||||
HAVE_NETWORKING := 1
|
||||
HAVE_IFINFO := 1
|
||||
|
||||
@@ -158,6 +158,7 @@ HAVE_RDDS := 0
|
||||
HAVE_RJPEG := 1
|
||||
HAVE_RBMP := 1
|
||||
HAVE_RTGA := 1
|
||||
HAVE_RGIF := 1
|
||||
HAVE_RMODTRACKER := 0
|
||||
HAVE_OVERLAY := 1
|
||||
HAVE_7ZIP := 0
|
||||
|
||||
+2
-1
@@ -34,7 +34,7 @@ ifeq ($(GRIFFIN_BUILD), 1)
|
||||
OBJ += griffin/griffin.o
|
||||
DEFINES += -DHAVE_GRIFFIN=1
|
||||
DEFINES += -DHAVE_MENU -DHAVE_LIBRETRODB -DHAVE_CONFIGFILE
|
||||
DEFINES += -DHAVE_RPNG -DHAVE_RWEBP -DHAVE_RDDS -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DHAVE_CC_RESAMPLER
|
||||
DEFINES += -DHAVE_RPNG -DHAVE_RWEBP -DHAVE_RDDS -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DHAVE_RGIF -DHAVE_CC_RESAMPLER
|
||||
DEFINES += -DHAVE_CORE_INFO_CACHE
|
||||
ifeq ($(DEBUG), 1)
|
||||
DEFINES += -DHAVE_NETLOGGER
|
||||
@@ -50,6 +50,7 @@ else
|
||||
HAVE_RJPEG := 1
|
||||
HAVE_RBMP := 1
|
||||
HAVE_RTGA := 1
|
||||
HAVE_RGIF := 1
|
||||
HAVE_OVERLAY := 1
|
||||
HAVE_7ZIP := 1
|
||||
HAVE_RZSTD := 1
|
||||
|
||||
@@ -37,6 +37,7 @@ ifeq ($(GRIFFIN_BUILD), 1)
|
||||
-DHAVE_RJPEG \
|
||||
-DHAVE_RBMP \
|
||||
-DHAVE_RTGA \
|
||||
-DHAVE_RGIF \
|
||||
-DHAVE_CC_RESAMPLER \
|
||||
-DHAVE_CORE_INFO_CACHE
|
||||
ifeq ($(DEBUG), 1)
|
||||
@@ -58,6 +59,7 @@ else
|
||||
HAVE_RJPEG := 1
|
||||
HAVE_RBMP := 1
|
||||
HAVE_RTGA := 1
|
||||
HAVE_RGIF := 1
|
||||
HAVE_7ZIP := 1
|
||||
HAVE_RZSTD := 1
|
||||
ifeq ($(HAVE_VITAGLES), 1)
|
||||
|
||||
@@ -148,6 +148,7 @@ HAVE_RDDS := 1
|
||||
HAVE_RJPEG := 1
|
||||
HAVE_RBMP := 1
|
||||
HAVE_RTGA := 1
|
||||
HAVE_RGIF := 1
|
||||
HAVE_RMODTRACKER := 1
|
||||
HAVE_OVERLAY := 1
|
||||
HAVE_7ZIP := 1
|
||||
|
||||
+2
-1
@@ -122,7 +122,7 @@ endif
|
||||
DEFINES += -DHAVE_RWAV
|
||||
DEFINES += -DHAVE_GRIFFIN=1 -DHAVE_MENU -DHAVE_GFX_WIDGETS -DHAVE_CONFIGFILE -DHAVE_PATCH -DHAVE_CHEATS -DHAVE_RGUI -DHAVE_LIBRETRODB
|
||||
DEFINES += -DHAVE_REWIND
|
||||
DEFINES += -DHAVE_RPNG -DHAVE_RWEBP -DHAVE_RDDS -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DHAVE_CC_RESAMPLER
|
||||
DEFINES += -DHAVE_RPNG -DHAVE_RWEBP -DHAVE_RDDS -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DHAVE_RGIF -DHAVE_CC_RESAMPLER
|
||||
DEFINES += -DHAVE_RSLC -DHAVE_SLANG
|
||||
DEFINES += -DHAVE_RVORBIS -DHAVE_LANGEXTRA -DHAVE_LIBRETRODB -DHAVE_NETWORKING -DHAVE_IFINFO -DHAVE_NETPLAYDISCOVERY
|
||||
DEFINES += -DHAVE_XMB -DHAVE_MATERIALUI
|
||||
@@ -139,6 +139,7 @@ endif
|
||||
HAVE_MENU_COMMON = 1
|
||||
HAVE_GFX_WIDGETS = 1
|
||||
HAVE_RTGA = 1
|
||||
HAVE_RGIF = 1
|
||||
HAVE_RPNG = 1
|
||||
HAVE_RWEBP = 1
|
||||
HAVE_RDDS = 1
|
||||
|
||||
+4
-1
@@ -1443,7 +1443,10 @@ static int rcheevos_rvz_pump(rcheevos_rvz_t* handle, bool opening)
|
||||
|
||||
if (err != RVZ_PENDING)
|
||||
return err;
|
||||
if (filestream_seek(handle->file, (int64_t)req.offset,
|
||||
/* At the offset in one call; seek and read where there is none */
|
||||
if ((got = filestream_read_at(handle->file, req.dst,
|
||||
(int64_t)req.length, (int64_t)req.offset)) < 0
|
||||
&& filestream_seek(handle->file, (int64_t)req.offset,
|
||||
RETRO_VFS_SEEK_POSITION_START) == 0)
|
||||
got = filestream_read(handle->file, req.dst, (int64_t)req.length);
|
||||
rvz_feed(handle->rvz, got > 0 ? (size_t)got : 0);
|
||||
|
||||
@@ -3194,22 +3194,15 @@ static uint8_t *command_memory_get_pointer(
|
||||
|
||||
/* What RUN_UNTIL, a PRESS that waits after it and a STEPS list wait on:
|
||||
* the byte at @lo, or with @wide the value @hi * 256 + @lo, from two
|
||||
* bytes that need not be adjacent. With @diff, that less the value at
|
||||
* @sub_lo, or @sub_hi:@sub_lo: how far apart two things are, signed. */
|
||||
* bytes that need not be adjacent. */
|
||||
struct command_cond
|
||||
{
|
||||
unsigned hi;
|
||||
unsigned lo;
|
||||
unsigned sub_hi;
|
||||
unsigned sub_lo;
|
||||
unsigned mask; /* "& <mask>": the bits compared; 0 for all */
|
||||
int want;
|
||||
unsigned want;
|
||||
uint8_t op; /* enum cmd_until_op */
|
||||
bool wide;
|
||||
bool sub_wide;
|
||||
bool diff;
|
||||
/* a stop: fires only on a frame it holds after one it did not */
|
||||
bool edge;
|
||||
};
|
||||
|
||||
/* "<address>[:<address>]" into @c, @end after it: 0, or 1 where the
|
||||
@@ -3232,34 +3225,20 @@ static int command_cond_address(const char *s, struct command_cond *c,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The byte at @lo, or with @wide the value @hi * 256 + @lo. */
|
||||
static bool command_cond_value(unsigned hi, unsigned lo, bool wide,
|
||||
static bool command_cond_read(const struct command_cond *c,
|
||||
unsigned *out, char *why, size_t why_len)
|
||||
{
|
||||
unsigned avail = 0;
|
||||
const rarch_system_info_t *sys = &runloop_state_get_ptr()->system;
|
||||
const uint8_t *l = command_memory_get_pointer(sys, lo, &avail, 0,
|
||||
const uint8_t *lo = command_memory_get_pointer(sys, c->lo, &avail, 0,
|
||||
why, why_len);
|
||||
const uint8_t *h = NULL;
|
||||
if (!l || (wide && !(h = command_memory_get_pointer(sys, hi,
|
||||
const uint8_t *hi = NULL;
|
||||
if (!lo || (c->wide && !(hi = command_memory_get_pointer(sys, c->hi,
|
||||
&avail, 0, why, why_len))))
|
||||
return false;
|
||||
*out = h ? ((unsigned)*h << 8) | *l : *l;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool command_cond_read(const struct command_cond *c,
|
||||
int *out, char *why, size_t why_len)
|
||||
{
|
||||
unsigned a = 0;
|
||||
unsigned b = 0;
|
||||
if ( !command_cond_value(c->hi, c->lo, c->wide, &a, why, why_len)
|
||||
|| (c->diff && !command_cond_value(c->sub_hi, c->sub_lo,
|
||||
c->sub_wide, &b, why, why_len)))
|
||||
return false;
|
||||
*out = hi ? ((unsigned)*hi << 8) | *lo : *lo;
|
||||
if (c->mask)
|
||||
a &= c->mask;
|
||||
*out = (int)a - (int)b;
|
||||
*out &= c->mask;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3312,9 +3291,9 @@ static size_t command_watch_lines(char *s, size_t len)
|
||||
i++)
|
||||
{
|
||||
const struct command_watch_entry *e = &command_watches[i];
|
||||
int now = 0;
|
||||
unsigned now = 0;
|
||||
if (command_cond_read(&e->where, &now, reason, sizeof(reason)))
|
||||
snprintf(value, sizeof(value), "%d", now);
|
||||
snprintf(value, sizeof(value), "%u", now);
|
||||
else
|
||||
strlcpy(value, "none", sizeof(value));
|
||||
if (e->where.wide)
|
||||
@@ -3359,17 +3338,15 @@ static bool command_cond_number(const char *s, char **end,
|
||||
return errno != ERANGE;
|
||||
}
|
||||
|
||||
/* "<address>[:<address>] [- <address>[:<address>]] <condition>
|
||||
* <value>", @end after the value; false with what was wrong in @why. */
|
||||
/* "<address>[:<address>] <condition> <value>", @end after the value;
|
||||
* false with what was wrong in @why. */
|
||||
static bool command_cond_parse(const char *s, struct command_cond *c,
|
||||
char **end, char *why, size_t why_len)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned long num;
|
||||
unsigned long max;
|
||||
const char *sp;
|
||||
int bad;
|
||||
bool neg = false;
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
if ((bad = command_cond_address(s, c, end)))
|
||||
@@ -3382,32 +3359,6 @@ static bool command_cond_parse(const char *s, struct command_cond *c,
|
||||
}
|
||||
while (**end == ' ')
|
||||
(*end)++;
|
||||
/* "485 - 47e": the second's value taken from the first's, signed,
|
||||
* so how far an enemy is from the player is one condition */
|
||||
if (**end == '-')
|
||||
{
|
||||
struct command_cond sub;
|
||||
memset(&sub, 0, sizeof(sub));
|
||||
if (command_cond_address(*end + 1, &sub, end))
|
||||
{
|
||||
strlcpy(why, "a hexadecimal address, or two as high:low, after "
|
||||
"the \"-\"", why_len);
|
||||
return false;
|
||||
}
|
||||
c->sub_hi = sub.hi;
|
||||
c->sub_lo = sub.lo;
|
||||
c->sub_wide = sub.wide;
|
||||
c->diff = true;
|
||||
while (**end == ' ')
|
||||
(*end)++;
|
||||
}
|
||||
max = (c->wide || c->sub_wide) ? 65535UL : 255UL;
|
||||
if (**end == '&' && c->diff)
|
||||
{
|
||||
strlcpy(why, "a mask compares one address's bits, not a difference",
|
||||
why_len);
|
||||
return false;
|
||||
}
|
||||
/* "& 0x40" or "& 64": only those bits, as a game keeps its flags */
|
||||
if (**end == '&')
|
||||
{
|
||||
@@ -3446,29 +3397,17 @@ static bool command_cond_parse(const char *s, struct command_cond *c,
|
||||
}
|
||||
while (*sp == ' ')
|
||||
sp++;
|
||||
/* a difference may be below zero: "<= -16" */
|
||||
if (c->diff && *sp == '-')
|
||||
{
|
||||
neg = true;
|
||||
sp++;
|
||||
}
|
||||
/* "== 112" or "== 0x70", as a mask is given */
|
||||
if (!command_cond_number(sp, end, &num) || num > max)
|
||||
if ( !command_cond_number(sp, end, &num)
|
||||
|| num > (c->wide ? 65535UL : 255UL))
|
||||
{
|
||||
if (c->diff)
|
||||
strlcpy(why, max > 255UL
|
||||
? "a value from -65535 to 65535, which is what two values "
|
||||
"of two bytes differ by"
|
||||
: "a value from -255 to 255, which is what two bytes "
|
||||
"differ by", why_len);
|
||||
else
|
||||
strlcpy(why, c->wide
|
||||
? "a value from 0 to 65535 (0xFFFF), which is what two bytes hold"
|
||||
: "a value from 0 to 255 (0xFF), which is what a byte holds",
|
||||
why_len);
|
||||
strlcpy(why, c->wide
|
||||
? "a value from 0 to 65535 (0xFFFF), which is what two bytes hold"
|
||||
: "a value from 0 to 255 (0xFF), which is what a byte holds",
|
||||
why_len);
|
||||
return false;
|
||||
}
|
||||
c->want = neg ? -(int)num : (int)num;
|
||||
c->want = (unsigned)num;
|
||||
c->op = (uint8_t)i;
|
||||
return true;
|
||||
}
|
||||
@@ -3476,7 +3415,7 @@ static bool command_cond_parse(const char *s, struct command_cond *c,
|
||||
/* What @c's memory holds now, looked up afresh as WATCH's bytes are,
|
||||
* since a core may move its memory while the content runs; false where
|
||||
* nothing maps it, with the reason as line clients read it in @why. */
|
||||
static bool command_cond_met(const struct command_cond *c, int now)
|
||||
static bool command_cond_met(const struct command_cond *c, unsigned now)
|
||||
{
|
||||
switch (c->op)
|
||||
{
|
||||
@@ -3498,7 +3437,7 @@ static bool command_cond_mapped(command_t *cmd, const char *name,
|
||||
const struct command_cond *c)
|
||||
{
|
||||
char reason[128];
|
||||
int now = 0;
|
||||
unsigned now = 0;
|
||||
if (command_cond_read(c, &now, reason, sizeof(reason)))
|
||||
return true;
|
||||
command_reply_error(cmd, name, "%s", command_memory_why(reason));
|
||||
@@ -3566,15 +3505,12 @@ static struct
|
||||
unsigned left; /* frames left in a RUN or PRESS step */
|
||||
unsigned budget; /* frames left for the whole job */
|
||||
unsigned ran; /* frames run so far */
|
||||
int value; /* what the last condition read held */
|
||||
unsigned value; /* what the last condition read held */
|
||||
unsigned port; /* the player whose buttons are held */
|
||||
uint16_t held; /* the buttons the job let go of, by bit */
|
||||
uint8_t answer; /* enum cmd_job_answer */
|
||||
unsigned nstops;
|
||||
unsigned stopped; /* which stop held, from 1 */
|
||||
/* whether each stop held on the frame before: one that becomes
|
||||
* fires only where it did not */
|
||||
bool stop_was[COMMAND_STOPS_MAX];
|
||||
/* a frame with the buttons let go between two presses of the same
|
||||
* one, so the game sees two taps rather than one long press */
|
||||
bool gap;
|
||||
@@ -3696,7 +3632,7 @@ static void command_run_frames_end(const char *how)
|
||||
case CMD_ANSWER_UNTIL:
|
||||
snprintf(first, sizeof(first), "%s %u\n", how,
|
||||
command_run_frames_st.ran);
|
||||
snprintf(last, sizeof(last), "VALUE %d\n",
|
||||
snprintf(last, sizeof(last), "VALUE %u\n",
|
||||
command_run_frames_st.value);
|
||||
command_run_frames_answer(first, last, false);
|
||||
break;
|
||||
@@ -3841,14 +3777,8 @@ static void command_run_frames_enter(bool safe)
|
||||
}
|
||||
else
|
||||
{
|
||||
int now = 0;
|
||||
command_run_frames_st.stops[s->idx - 1] = s->cond;
|
||||
command_run_frames_st.nstops = s->idx;
|
||||
/* what it holds as it takes over, so one already true when
|
||||
* the list starts waits for it to stop holding first */
|
||||
command_run_frames_st.stop_was[s->idx - 1] =
|
||||
command_cond_read(&s->cond, &now, why, sizeof(why))
|
||||
&& command_cond_met(&s->cond, now);
|
||||
}
|
||||
command_run_frames_st.cur++;
|
||||
continue;
|
||||
@@ -3997,7 +3927,7 @@ void command_run_frames_between(void)
|
||||
void command_run_frames_tick(void)
|
||||
{
|
||||
char why[128];
|
||||
int now = 0;
|
||||
unsigned now = 0;
|
||||
unsigned i;
|
||||
struct command_step *s;
|
||||
|
||||
@@ -4018,17 +3948,10 @@ void command_run_frames_tick(void)
|
||||
}
|
||||
if (command_cond_met(&command_run_frames_st.stops[i], now))
|
||||
{
|
||||
bool was = command_run_frames_st.stop_was[i];
|
||||
command_run_frames_st.stop_was[i] = true;
|
||||
if (!command_run_frames_st.stops[i].edge || !was)
|
||||
{
|
||||
command_run_frames_st.stopped = i + 1;
|
||||
command_run_frames_end("STOPPED");
|
||||
return;
|
||||
}
|
||||
command_run_frames_st.stopped = i + 1;
|
||||
command_run_frames_end("STOPPED");
|
||||
return;
|
||||
}
|
||||
else
|
||||
command_run_frames_st.stop_was[i] = false;
|
||||
}
|
||||
s = &command_run_frames_st.steps[command_run_frames_st.cur];
|
||||
if (command_run_frames_st.gap)
|
||||
@@ -4361,14 +4284,12 @@ bool command_set_input(command_t *cmd, const char *arg)
|
||||
* With nothing, what is watched now. Each label and address watches the
|
||||
* byte there under that label, carried by RUN_FRAMES, PRESS and
|
||||
* RUN_UNTIL; a label and "off" stops watching it. Every pair is taken
|
||||
* or none is, so a refusal leaves the list as it was. The limit is on
|
||||
* the list they leave, so an off later in the request makes room.
|
||||
* or none is, so a refusal leaves the list as it was.
|
||||
*
|
||||
* Answers with the list either way, so a client sees what it has. */
|
||||
bool command_watch(command_t *cmd, const char *arg)
|
||||
{
|
||||
/* room past the limit for those an off further on takes back out */
|
||||
struct command_watch_entry next[2 * COMMAND_WATCH_MAX];
|
||||
struct command_watch_entry next[COMMAND_WATCH_MAX];
|
||||
char reply[64 + COMMAND_WATCH_MAX * COMMAND_WATCH_LINE];
|
||||
char label[sizeof(next[0].label)];
|
||||
char reason[128];
|
||||
@@ -4378,7 +4299,7 @@ bool command_watch(command_t *cmd, const char *arg)
|
||||
unsigned i;
|
||||
const char *sp;
|
||||
|
||||
memcpy(next, command_watches, sizeof(command_watches));
|
||||
memcpy(next, command_watches, sizeof(next));
|
||||
while (arg && *arg)
|
||||
{
|
||||
while (*arg == ' ')
|
||||
@@ -4425,7 +4346,7 @@ bool command_watch(command_t *cmd, const char *arg)
|
||||
else
|
||||
{
|
||||
struct command_cond where;
|
||||
int now = 0;
|
||||
unsigned now = 0;
|
||||
char *end = NULL;
|
||||
memset(&where, 0, sizeof(where));
|
||||
/* high:low, two bytes as one value, as conditions take them */
|
||||
@@ -4437,7 +4358,7 @@ bool command_watch(command_t *cmd, const char *arg)
|
||||
return false;
|
||||
}
|
||||
/* only a label that is not watched yet needs room */
|
||||
if (i == count && count >= ARRAY_SIZE(next))
|
||||
if (i == count && count >= COMMAND_WATCH_MAX)
|
||||
{
|
||||
command_reply_error(cmd, "WATCH", "at most %u bytes watched "
|
||||
"at once", (unsigned)COMMAND_WATCH_MAX);
|
||||
@@ -4457,13 +4378,7 @@ bool command_watch(command_t *cmd, const char *arg)
|
||||
strlcpy(next[i].label, label, sizeof(next[i].label));
|
||||
}
|
||||
}
|
||||
if (count > COMMAND_WATCH_MAX)
|
||||
{
|
||||
command_reply_error(cmd, "WATCH", "at most %u bytes watched "
|
||||
"at once", (unsigned)COMMAND_WATCH_MAX);
|
||||
return false;
|
||||
}
|
||||
memcpy(command_watches, next, sizeof(command_watches));
|
||||
memcpy(command_watches, next, sizeof(next));
|
||||
command_watch_count = count;
|
||||
|
||||
_len = command_watch_lines(reply, sizeof(reply));
|
||||
@@ -4473,12 +4388,11 @@ bool command_watch(command_t *cmd, const char *arg)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* RUN_UNTIL <address> [- <address>] <condition> <value> [max frames]
|
||||
/* RUN_UNTIL <address> <condition> <value> [max frames]
|
||||
*
|
||||
* Runs the content until the byte at a system address meets what was
|
||||
* asked, then answers with how many frames that took and the value it
|
||||
* found. With "- <address>" it is that byte less the other, signed:
|
||||
* how far apart two things are. Where a client would otherwise run a few frames, read the
|
||||
* found. Where a client would otherwise run a few frames, read the
|
||||
* byte, and go round again - which is where a field run spent most of
|
||||
* its calls - this is one request.
|
||||
*
|
||||
@@ -4690,9 +4604,7 @@ static void command_steps_report(command_t *cmd, long idle,
|
||||
* <player> <controls> <frames>" and "until <condition>", in order, then
|
||||
* answers with how it ended and what WATCH watches. A "stop
|
||||
* <condition>" entry ends the list after any frame where it holds, so a
|
||||
* death does not play out the rest; "stop becomes <condition>" only
|
||||
* after one where it starts to, so one already true does not end the
|
||||
* list at its first frame. "checkpoint" keeps the state
|
||||
* death does not play out the rest, and "checkpoint" keeps the state
|
||||
* STATE rollback returns to. The whole list runs no longer than a wait
|
||||
* does; past that it answers WAITING and the step it was on, and the
|
||||
* next request carries on from there.
|
||||
@@ -4750,10 +4662,9 @@ bool command_steps(command_t *cmd, const char *arg)
|
||||
for (entry = list; entry; entry = next)
|
||||
{
|
||||
struct command_step *s;
|
||||
struct command_cond *c = NULL;
|
||||
char *end = NULL;
|
||||
struct command_cond *c = NULL;
|
||||
char *end = NULL;
|
||||
size_t n;
|
||||
bool edge = false;
|
||||
if ((next = strchr(entry, ';')))
|
||||
*next++ = '\0';
|
||||
while (*entry == ' ')
|
||||
@@ -4775,13 +4686,6 @@ bool command_steps(command_t *cmd, const char *arg)
|
||||
}
|
||||
c = &stops[nstops++];
|
||||
entry += 5;
|
||||
/* "stop becomes <condition>": only once it starts to hold, so
|
||||
* one true as the list starts does not end it at once */
|
||||
if (!strncmp(entry, "becomes ", 8))
|
||||
{
|
||||
entry += 8;
|
||||
edge = true;
|
||||
}
|
||||
}
|
||||
else if (count >= COMMAND_STEPS_MAX)
|
||||
{
|
||||
@@ -4881,7 +4785,6 @@ bool command_steps(command_t *cmd, const char *arg)
|
||||
command_reply_error(cmd, "STEPS", "%s", why);
|
||||
return false;
|
||||
}
|
||||
c->edge = edge;
|
||||
while (*end == ' ')
|
||||
end++;
|
||||
if (*end)
|
||||
@@ -6188,23 +6091,11 @@ bool command_get_status(command_t *cmd, const char* arg)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* READ_CORE_MEMORY <address> <bytes> [<address> <bytes>]...
|
||||
*
|
||||
* Each range a line of its own, in the order asked, so the arrays a
|
||||
* step needs - positions, health - are one request rather than one
|
||||
* apiece. Where nothing maps one, that line alone is the answer. */
|
||||
#define COMMAND_READ_RANGES_MAX 16
|
||||
|
||||
bool command_read_memory(command_t *cmd, const char *arg)
|
||||
{
|
||||
char* reply = NULL;
|
||||
char* reply_at = NULL;
|
||||
const uint8_t* data = NULL;
|
||||
unsigned int addrs[COMMAND_READ_RANGES_MAX];
|
||||
unsigned int counts[COMMAND_READ_RANGES_MAX];
|
||||
unsigned int nranges = 0;
|
||||
unsigned int total = 0;
|
||||
unsigned int r;
|
||||
unsigned int nbytes = 0;
|
||||
unsigned int alloc_size = 0;
|
||||
unsigned int address = -1;
|
||||
@@ -6213,48 +6104,27 @@ bool command_read_memory(command_t *cmd, const char *arg)
|
||||
runloop_state_t *runloop_st = runloop_state_get_ptr();
|
||||
const rarch_system_info_t* sys_info= &runloop_st->system;
|
||||
|
||||
while (arg && *arg)
|
||||
{
|
||||
char *end = NULL;
|
||||
unsigned long num;
|
||||
if (nranges >= COMMAND_READ_RANGES_MAX)
|
||||
{
|
||||
command_reply_error(cmd, "READ_CORE_MEMORY",
|
||||
"at most %u ranges", (unsigned)COMMAND_READ_RANGES_MAX);
|
||||
return false;
|
||||
}
|
||||
if (!command_parse_address(arg, &address, &end) || *end != ' ')
|
||||
{
|
||||
command_reply_error(cmd, "READ_CORE_MEMORY",
|
||||
"a hexadecimal address, a space and a byte count");
|
||||
return false;
|
||||
}
|
||||
num = strtoul(end + 1, &end, 10);
|
||||
num = strtoul(end + 1, NULL, 10);
|
||||
nbytes = num <= COMMAND_READ_NBYTES_MAX ? (unsigned)num : 0;
|
||||
if (nbytes == 0 || total + nbytes > COMMAND_READ_NBYTES_MAX)
|
||||
if (nbytes == 0)
|
||||
{
|
||||
command_reply_error(cmd, "READ_CORE_MEMORY", nranges
|
||||
? "byte counts from 1, %u in all"
|
||||
: "a byte count from 1 to %u", COMMAND_READ_NBYTES_MAX);
|
||||
command_reply_error(cmd, "READ_CORE_MEMORY",
|
||||
"a byte count from 1 to %u", COMMAND_READ_NBYTES_MAX);
|
||||
return false;
|
||||
}
|
||||
addrs[nranges] = address;
|
||||
counts[nranges] = nbytes;
|
||||
nranges++;
|
||||
total += nbytes;
|
||||
/* another address and count, or the end of the line */
|
||||
for (arg = end; *arg && (unsigned char)*arg <= ' '; arg++)
|
||||
;
|
||||
}
|
||||
if (!nranges)
|
||||
{
|
||||
command_reply_error(cmd, "READ_CORE_MEMORY",
|
||||
"a hexadecimal address, a space and a byte count");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Ensure large enough to return all requested bytes or an error message */
|
||||
alloc_size = 96 * nranges + total * 3;
|
||||
alloc_size = 96 + nbytes * 3;
|
||||
reply = (char*)malloc(alloc_size);
|
||||
|
||||
if (!reply)
|
||||
@@ -6262,53 +6132,43 @@ bool command_read_memory(command_t *cmd, const char *arg)
|
||||
command_reply_error(cmd, "READ_CORE_MEMORY", "out of memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
reply_at = reply + snprintf(reply, alloc_size - 1, "READ_CORE_MEMORY %x", address);
|
||||
|
||||
for (r = 0; r < nranges; r++)
|
||||
if ((data = command_memory_get_pointer(
|
||||
sys_info, address, &max_bytes,
|
||||
0, reply_at, alloc_size - strlen(reply))))
|
||||
{
|
||||
char *line = reply + _len;
|
||||
address = addrs[r];
|
||||
nbytes = counts[r];
|
||||
reply_at = line + snprintf(line, alloc_size - _len - 1,
|
||||
"READ_CORE_MEMORY %x", address);
|
||||
|
||||
if ((data = command_memory_get_pointer(
|
||||
sys_info, address, &max_bytes,
|
||||
0, reply_at, alloc_size - (size_t)(reply_at - reply))))
|
||||
char why[128];
|
||||
char *end = reply_at;
|
||||
unsigned int read = 0;
|
||||
/* on into the region that follows, as a core that splits its RAM
|
||||
* maps it; where nothing maps the rest, how much was read */
|
||||
while (data)
|
||||
{
|
||||
char why[128];
|
||||
char *end = reply_at;
|
||||
unsigned int read = 0;
|
||||
/* on into the region that follows, as a core that splits its RAM
|
||||
* maps it; where nothing maps the rest, how much was read */
|
||||
while (data)
|
||||
{
|
||||
unsigned int n = nbytes - read < max_bytes
|
||||
? nbytes - read : max_bytes;
|
||||
if (!n)
|
||||
break;
|
||||
end = command_hex_bytes(end, data, n);
|
||||
read += n;
|
||||
if (read >= nbytes)
|
||||
break;
|
||||
data = command_memory_get_pointer(sys_info, address + read,
|
||||
&max_bytes, 0, why, sizeof(why));
|
||||
}
|
||||
*end++ = '\n';
|
||||
if (read < nbytes)
|
||||
end += snprintf(end, alloc_size - (size_t)(end - reply),
|
||||
"TRUNCATED %u\n", read);
|
||||
_len = (size_t)(end - reply);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* command_memory_get_pointer() has put the reason in the reply,
|
||||
* in the form line clients have always read: this range's line
|
||||
* alone */
|
||||
_len = strlen(line);
|
||||
memmove(reply, line, _len + 1);
|
||||
cmd->error = true;
|
||||
break;
|
||||
unsigned int n = nbytes - read < max_bytes
|
||||
? nbytes - read : max_bytes;
|
||||
if (!n)
|
||||
break;
|
||||
end = command_hex_bytes(end, data, n);
|
||||
read += n;
|
||||
if (read >= nbytes)
|
||||
break;
|
||||
data = command_memory_get_pointer(sys_info, address + read,
|
||||
&max_bytes, 0, why, sizeof(why));
|
||||
}
|
||||
*end++ = '\n';
|
||||
if (read < nbytes)
|
||||
end += snprintf(end, alloc_size - (size_t)(end - reply),
|
||||
"TRUNCATED %u\n", read);
|
||||
_len = (size_t)(end - reply);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* command_memory_get_pointer() has put the reason in the reply,
|
||||
* in the form line clients have always read */
|
||||
_len = strlen(reply);
|
||||
cmd->error = true;
|
||||
}
|
||||
|
||||
cmd->replier(cmd, reply, _len);
|
||||
|
||||
@@ -603,11 +603,6 @@ struct cmd_rows
|
||||
/* The reply may carry a "PREVIOUS ..." line: how a queued STEPS no
|
||||
* reply has told of ended. */
|
||||
bool previous;
|
||||
/* Set, for a record: the field a reply of several such lines - one
|
||||
* for each range READ_CORE_MEMORY was asked - gives them all in, in
|
||||
* order, each with the trailers after it. The record's own fields
|
||||
* are the first. */
|
||||
const char *more;
|
||||
};
|
||||
|
||||
/* A command with its own handler; @arg_desc names the argument, or
|
||||
@@ -881,19 +876,18 @@ static const struct cmd_param cmd_params_watch[] = {
|
||||
{ "watches", "Label and hexadecimal address pairs, as GET_MEMORY_MAP "
|
||||
"gives them: \"x 86 mode 770\"; \"x 6d:86\" reads two bytes as one "
|
||||
"value. A label watched again is replaced; off as its address stops "
|
||||
"it. 16 at most, counted once the offs are taken.",
|
||||
"it. 16 at most.",
|
||||
CMD_PARAM_STRING, false, NULL, NULL, NULL },
|
||||
{ NULL }
|
||||
};
|
||||
static const struct cmd_param cmd_params_until[] = {
|
||||
{ "address", "Hexadecimal, as GET_MEMORY_MAP gives it; high:low "
|
||||
"(6d:86) reads two bytes as one value; & 0x40 after it compares "
|
||||
"only those bits; 485 - 47e compares the first less the second, "
|
||||
"signed.", CMD_PARAM_STRING, true, NULL, NULL, NULL },
|
||||
"only those bits.", CMD_PARAM_STRING, true, NULL, NULL, NULL },
|
||||
{ "condition", "How it compares with the value.",
|
||||
CMD_PARAM_STRING, true, NULL, "==|!=|<|>|<=|>=", NULL },
|
||||
{ "value", "0 to 255, or 65535 for high:low; a difference from "
|
||||
"-255, or -65535.", CMD_PARAM_INT, true, NULL, NULL, NULL },
|
||||
{ "value", "0 to 255, or 65535 for high:low.",
|
||||
CMD_PARAM_INT, true, NULL, NULL, NULL },
|
||||
{ "frames", "Frames to wait at most; a request's nine seconds when "
|
||||
"left out.", CMD_PARAM_INT, false, NULL, NULL, NULL },
|
||||
{ NULL }
|
||||
@@ -916,8 +910,7 @@ static const struct cmd_param cmd_params_steps[] = {
|
||||
"<frames>, until <condition> as RUN_UNTIL's, checkpoint, and up to "
|
||||
"four stop <condition> that end it: \"until 86 >= 200; "
|
||||
"press 1 a 20; until 1d == 0; stop e == 11\". 32 at most. A press "
|
||||
"after a press lets go for a frame first. stop becomes <condition> "
|
||||
"ends it only once it starts to hold, not where it already does.",
|
||||
"after a press lets go for a frame first.",
|
||||
CMD_PARAM_STRING, true, NULL, NULL, NULL },
|
||||
{ "queue", "on: answer now, run after those queued, pause when all "
|
||||
"have (idle: ms since). After a queued list ends the next reply says "
|
||||
@@ -979,16 +972,6 @@ static const struct cmd_param cmd_params_read[] = {
|
||||
CMD_PARAM_INT, true, NULL, NULL, NULL },
|
||||
{ NULL }
|
||||
};
|
||||
static const struct cmd_param cmd_params_read_memory[] = {
|
||||
{ "address", "The address to read from, in hexadecimal.",
|
||||
CMD_PARAM_STRING, true, NULL, NULL, NULL },
|
||||
{ "bytes", "How many.",
|
||||
CMD_PARAM_INT, true, NULL, NULL, NULL },
|
||||
{ "more", "Further ranges in the same request, as address and byte "
|
||||
"count pairs: \"4a2 18 568 18\". Each answers a line, given as "
|
||||
"ranges.", CMD_PARAM_STRING, false, NULL, NULL, NULL },
|
||||
{ NULL }
|
||||
};
|
||||
static const struct cmd_param cmd_params_write[] = {
|
||||
{ "address", "The address to write to, in hexadecimal.",
|
||||
CMD_PARAM_STRING, true, NULL, NULL, NULL },
|
||||
@@ -1229,7 +1212,7 @@ static const struct cmd_trailer cmd_trailers_read[] = {
|
||||
{ "TRUNCATED", "truncated", "read", "Bytes read, short of those asked." },
|
||||
{ NULL }
|
||||
};
|
||||
static const struct cmd_rows cmd_rows_read = { cmd_cols_read, cmd_trailers_read, 0, 0, " ", false, "ranges" };
|
||||
static const struct cmd_rows cmd_rows_read = { cmd_cols_read, cmd_trailers_read, 0, 0, " " };
|
||||
/* "MENU Main Menu", the entries, then which is selected of how many */
|
||||
static const struct cmd_column cmd_cols_menu[] = {
|
||||
{ "index", NULL },
|
||||
@@ -1275,7 +1258,7 @@ static const struct cmd_action_map action_map[] = {
|
||||
{ "RUN_FRAMES", command_run_frames, "<count>", "Pause and advance the content some frames; it finishes paused. One request runs nine seconds of frames at most (540 at 60fps), as PRESS, RUN_UNTIL and STEPS do.", 0, cmd_params_run_frames, &cmd_rows_frames },
|
||||
{ "SET_INPUT", command_set_input, "<player> <control>[+<control>...] <value>", "Hold RetroPad buttons or stick axes for the core, over the player's own input, until set again or released. The core is given exactly what is held: opposing directions are not cleaned and the D-Pad is not turned with the picture. Under netplay the player is this machine's, and what is held is sent like a press. Answers with the player, the buttons held and the axes held, none for either where nothing is.", CMD_INFO_NO_TOOL, cmd_params_input, &cmd_rows_input },
|
||||
{ "PRESS", command_press, "<player> <control>[+<control>...] <frames> [until <condition>]", "Press buttons for some frames and let go; with until, run on until a condition holds. What INPUT holds stays held. Answers with what WATCH watches; finishes paused.", 0, cmd_params_press, &cmd_rows_press },
|
||||
{ "RUN_UNTIL", command_run_until, "<address>[:<address>] [- <address>[:<address>]] <condition> <value> [max frames]", "Run until memory meets a condition. Answers met or waiting (ask again) with the frames run, what WATCH watches and the value.", 0, cmd_params_until, &cmd_rows_until },
|
||||
{ "RUN_UNTIL", command_run_until, "<address>[:<address>] <condition> <value> [max frames]", "Run until memory meets a condition. Answers met or waiting (ask again) with the frames run, what WATCH watches and the value.", 0, cmd_params_until, &cmd_rows_until },
|
||||
{ "STEPS", command_steps, "<step>[; <step>...][|on]", "Play a stretch in one request, or queued to play on unpaused. Answers with how it ended and what WATCH watches.", 0, cmd_params_steps, &cmd_rows_steps },
|
||||
{ "WATCH", command_watch, "[<label> <address|off>]...", "Watch bytes under labels: every step answers with them, so needs no read after. With none, answers each value, in decimal. Cleared when content closes.", 0, cmd_params_watch, &cmd_rows_watch },
|
||||
{ "RELEASE_INPUT", command_release_input, "[player]", "Let go of everything SET_INPUT holds, for one player, or every player when given none. Answers as GET_INPUT does, for that player or the first.", CMD_INFO_NO_TOOL, cmd_params_input_release, &cmd_rows_input },
|
||||
@@ -1292,7 +1275,7 @@ static const struct cmd_action_map action_map[] = {
|
||||
{ "READ_CORE_RAM", command_read_ram, "<address> <number of bytes>", "Read bytes from core memory at an achievement address (needs a game with achievements).", CMD_INFO_READ_ONLY | CMD_INFO_NO_TOOL, cmd_params_read },
|
||||
{ "WRITE_CORE_RAM", command_write_ram, "<address> <byte1> <byte2> ...", "Write bytes to core memory at an achievement address (needs a game with achievements).", CMD_INFO_DESTRUCTIVE | CMD_INFO_NO_TOOL, cmd_params_write },
|
||||
#endif
|
||||
{ "READ_CORE_MEMORY", command_read_memory, "<address> <number of bytes> [<address> <number of bytes>]...", "Read bytes from core memory at a system address. Answers with the address and the bytes, in hexadecimal; a line for each range asked.", CMD_INFO_READ_ONLY, cmd_params_read_memory, &cmd_rows_read },
|
||||
{ "READ_CORE_MEMORY", command_read_memory, "<address> <number of bytes>", "Read bytes from core memory at a system address. Answers with the address and the bytes, in hexadecimal.", CMD_INFO_READ_ONLY, cmd_params_read, &cmd_rows_read },
|
||||
{ "GET_MEMORY_MAP", command_get_memory_map, "No argument", "The core's memory map: start, length, select and disconnect in hexadecimal, as READ_CORE_MEMORY takes them. A core with none lists the RAM it hands over, in space core: system RAM from 0, save RAM after.", CMD_INFO_READ_ONLY, NULL, &cmd_rows_memory },
|
||||
{ "WRITE_CORE_MEMORY",command_write_memory, "<address> <byte1> <byte2> ...", "Write bytes to core memory at a system address. Answers with the address and how many bytes were written.", CMD_INFO_DESTRUCTIVE, cmd_params_write },
|
||||
|
||||
|
||||
@@ -894,6 +894,7 @@
|
||||
#define DEFAULT_SETTINGS_SHOW_ACCESSIBILITY true
|
||||
#define DEFAULT_SETTINGS_SHOW_POWER_MANAGEMENT true
|
||||
#define DEFAULT_SETTINGS_SHOW_ACHIEVEMENTS true
|
||||
#define DEFAULT_SETTINGS_SHOW_BLUETOOTH true
|
||||
#define DEFAULT_SETTINGS_SHOW_NETWORK true
|
||||
#define DEFAULT_SETTINGS_SHOW_PLAYLISTS true
|
||||
#define DEFAULT_SETTINGS_SHOW_USER true
|
||||
|
||||
@@ -418,6 +418,12 @@
|
||||
#define SUPPORTS_RTGA false
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RGIF
|
||||
#define SUPPORTS_RGIF true
|
||||
#else
|
||||
#define SUPPORTS_RGIF false
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RWEBP
|
||||
#define SUPPORTS_RWEBP true
|
||||
#else
|
||||
|
||||
@@ -1015,6 +1015,7 @@ typedef struct settings
|
||||
bool settings_show_accessibility;
|
||||
bool settings_show_power_management;
|
||||
bool settings_show_achievements;
|
||||
bool settings_show_bluetooth;
|
||||
bool settings_show_network;
|
||||
bool settings_show_playlists;
|
||||
bool settings_show_user;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include <streams/file_stream.h>
|
||||
|
||||
#if defined(HAVE_RPNG) || defined(HAVE_RJPEG) || defined(HAVE_RTGA) || defined(HAVE_RBMP) || defined(HAVE_RWEBP) || defined(HAVE_RDDS)
|
||||
#if defined(HAVE_RPNG) || defined(HAVE_RJPEG) || defined(HAVE_RTGA) || defined(HAVE_RBMP) || defined(HAVE_RWEBP) || defined(HAVE_RDDS) || defined(HAVE_RGIF)
|
||||
#define PREFER_NON_STB_IMAGE
|
||||
#endif
|
||||
|
||||
@@ -87,6 +87,10 @@ static const char image_formats[] =
|
||||
"|tga"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RGIF
|
||||
"|gif"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RWEBP
|
||||
"|webp"
|
||||
#endif
|
||||
@@ -95,7 +99,7 @@ static const char image_formats[] =
|
||||
"|dds"
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_RJPEG) && !defined(HAVE_RPNG) && !defined(HAVE_RBMP) && !defined(HAVE_RTGA) && !defined(HAVE_RWEBP) && !defined(HAVE_RDDS)
|
||||
#if !defined(HAVE_RJPEG) && !defined(HAVE_RPNG) && !defined(HAVE_RBMP) && !defined(HAVE_RTGA) && !defined(HAVE_RWEBP) && !defined(HAVE_RDDS) && !defined(HAVE_RGIF)
|
||||
#error "can't build this core with no image formats"
|
||||
#endif
|
||||
;
|
||||
|
||||
+2
-25
@@ -143,15 +143,6 @@ goes on into the next; where nothing maps the rest it stops there and
|
||||
says so, `TRUNCATED 2` after the bytes, given as `truncated: true,
|
||||
read: 2`.
|
||||
|
||||
`READ_CORE_MEMORY 47e 18 4a2 18 568 18` reads several ranges in one
|
||||
request (`more: "4a2 18 568 18"` over MCP), up to sixteen and 16384
|
||||
bytes in all: a line for each, in the order asked, each with its own
|
||||
`TRUNCATED` after it where it was cut short. The record's fields are
|
||||
the first range's, and `ranges` gives every one, the first too, as
|
||||
`{"address", "bytes"}` with `truncated` and `read` where cut short.
|
||||
Where nothing maps one of them, its line alone is the answer, as a
|
||||
single range's is.
|
||||
|
||||
## Results that are rows
|
||||
|
||||
The replies that are lines of tab-separated fields - `OPTION`,
|
||||
@@ -455,9 +446,7 @@ its place in the list when its address changes; with nothing watched
|
||||
it answers `WATCH none`. Values are decimal, 0 to 255 - or to 65535
|
||||
for a `high:low` watch - as `RUN_UNTIL` takes them; addresses are hexadecimal. A label is up to 15 characters,
|
||||
with no tab or newline in it. `x 6d:86` watches two bytes as one value,
|
||||
high:low, as conditions read them. Sixteen at once, counted on the
|
||||
list the request leaves: `WATCH lives 4d e13h off` with sixteen watched
|
||||
adds one and drops one. Each is checked when it is
|
||||
high:low, as conditions read them. Sixteen at once. Each is checked when it is
|
||||
set - an address nothing maps is refused there -
|
||||
and read afresh on every reply, so a core that moves its memory is
|
||||
followed; one that stops mapping a watched address answers `none` for
|
||||
@@ -484,14 +473,6 @@ x 7e0086 52
|
||||
VALUE 5
|
||||
```
|
||||
|
||||
`<address> - <address>` compares the first's value less the second's,
|
||||
signed, each one byte or `high:low`: `485 - 47e <= 32` waits until an
|
||||
enemy at x `485` is no more than 32 to the right of the player at
|
||||
`47e`, walking in until it is in range. The value may be below zero, from -255 to 255, or -65535 to
|
||||
65535 where either side is `high:low`, and `VALUE` answers the
|
||||
difference, `VALUE -12`. Both addresses must be mapped, and a mask is
|
||||
refused on one.
|
||||
|
||||
Where a client would otherwise run a few frames, read the byte and go
|
||||
round again, this is one request. The address is the kind
|
||||
`GET_MEMORY_MAP` gives and `READ_CORE_MEMORY` takes, and one nothing
|
||||
@@ -512,11 +493,7 @@ told it failed.
|
||||
step is `run <frames>`, `press <player> <controls> <frames>`, `until
|
||||
<condition>` or `checkpoint`, in order; up to four `stop <condition>`
|
||||
entries anywhere in the list end it after any frame where one holds - a
|
||||
death, the level's end - so neither plays out the rest. `stop becomes
|
||||
<condition>` ends it only after a frame where the condition starts to
|
||||
hold: one already true when the list starts - `stop becomes 412 == 4`
|
||||
while the player is still reeling - waits for it to stop holding and
|
||||
hold again, rather than ending the list at its first frame. `checkpoint`
|
||||
death, the level's end - so neither plays out the rest. `checkpoint`
|
||||
keeps the state `STATE rollback` returns to, where the list has got to,
|
||||
so a stretch can mark its own retry point:
|
||||
|
||||
|
||||
@@ -3010,45 +3010,7 @@ void dxgi_set_hdr_metadata(
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <formats/rpng.h>
|
||||
|
||||
/* IEEE 754 binary16 -> binary32. Used to decode FP16 scRGB samples. */
|
||||
static INLINE float dxgi_half_to_float(uint16_t h)
|
||||
{
|
||||
uint32_t sign = (uint32_t)(h >> 15) & 0x1u;
|
||||
uint32_t exp = (uint32_t)(h >> 10) & 0x1Fu;
|
||||
uint32_t mant = (uint32_t) h & 0x3FFu;
|
||||
uint32_t f;
|
||||
union { uint32_t u; float f; } u;
|
||||
|
||||
if (exp == 0)
|
||||
{
|
||||
if (mant == 0)
|
||||
f = sign << 31; /* signed zero */
|
||||
else
|
||||
{
|
||||
/* Subnormal: normalize. */
|
||||
while (!(mant & 0x400u))
|
||||
{
|
||||
mant <<= 1;
|
||||
exp -= 1; /* exp starts at 0, goes negative */
|
||||
}
|
||||
exp += 1;
|
||||
mant &= ~0x400u;
|
||||
f = (sign << 31) | ((exp + 127 - 15) << 23) | (mant << 13);
|
||||
}
|
||||
}
|
||||
else if (exp == 0x1F)
|
||||
{
|
||||
/* Inf / NaN: propagate to float32 Inf/NaN with the same mantissa
|
||||
* low bits (clamped away later, so exact bit-pattern doesn't matter). */
|
||||
f = (sign << 31) | (0xFFu << 23) | (mant << 13);
|
||||
}
|
||||
else
|
||||
f = (sign << 31) | ((exp + 127 - 15) << 23) | (mant << 13);
|
||||
|
||||
u.u = f;
|
||||
return u.f;
|
||||
}
|
||||
#include <math/float16.h>
|
||||
|
||||
/* ST.2084 (PQ) EOTF. Input is the non-linear PQ code value in [0,1];
|
||||
* output is linear light normalized so 1.0 == 10000 nits. */
|
||||
@@ -3210,9 +3172,9 @@ bool dxgi_hdr_readback_to_bgr24(
|
||||
const uint16_t* src = (const uint16_t*)src_row + src_x * 4;
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
float r = dxgi_half_to_float(src[4 * x + 0]) * inv_scale;
|
||||
float g = dxgi_half_to_float(src[4 * x + 1]) * inv_scale;
|
||||
float b = dxgi_half_to_float(src[4 * x + 2]) * inv_scale;
|
||||
float r = retro_half_to_float(src[4 * x + 0]) * inv_scale;
|
||||
float g = retro_half_to_float(src[4 * x + 1]) * inv_scale;
|
||||
float b = retro_half_to_float(src[4 * x + 2]) * inv_scale;
|
||||
/* scRGB carries legal negative values for out-of-gamut
|
||||
* colours; clamping in LinearToSRGB handles them. */
|
||||
dst[3 * x + 0] = dxgi_float_to_unorm8(dxgi_linear_to_srgb(b));
|
||||
@@ -3309,9 +3271,9 @@ bool dxgi_hdr_readback_to_rgb16(
|
||||
* scale to absolute nits, PQ-encode into 16 bit. Extended
|
||||
* range (negatives, >10000 nits) clamps -- unavoidable for
|
||||
* a UNORM PNG. */
|
||||
float r = dxgi_half_to_float(src[x * 4 + 0]);
|
||||
float g = dxgi_half_to_float(src[x * 4 + 1]);
|
||||
float b = dxgi_half_to_float(src[x * 4 + 2]);
|
||||
float r = retro_half_to_float(src[x * 4 + 0]);
|
||||
float g = retro_half_to_float(src[x * 4 + 1]);
|
||||
float b = retro_half_to_float(src[x * 4 + 2]);
|
||||
float lvl;
|
||||
float nr = r * (80.0f / 10000.0f);
|
||||
float ng = g * (80.0f / 10000.0f);
|
||||
|
||||
@@ -482,13 +482,52 @@ static bool kms_display_server_crtc_vrr(int fd, uint32_t crtc_id)
|
||||
return vrr;
|
||||
}
|
||||
|
||||
/* Physical size comes from the connector (EDID or the panel's device
|
||||
* tree node), pixel size from the live mode. The menu's touch drag,
|
||||
* swipe and scaling need DPI; 0 mm means the sink did not say. */
|
||||
static bool kms_display_server_geometry_metric(
|
||||
enum display_metric_types type, float *value)
|
||||
{
|
||||
unsigned n;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DISPLAY_METRIC_PIXEL_WIDTH:
|
||||
n = g_drm_mode ? g_drm_mode->hdisplay : 0;
|
||||
break;
|
||||
case DISPLAY_METRIC_PIXEL_HEIGHT:
|
||||
n = g_drm_mode ? g_drm_mode->vdisplay : 0;
|
||||
break;
|
||||
case DISPLAY_METRIC_MM_WIDTH:
|
||||
n = g_drm_connector ? g_drm_connector->mmWidth : 0;
|
||||
break;
|
||||
case DISPLAY_METRIC_MM_HEIGHT:
|
||||
n = g_drm_connector ? g_drm_connector->mmHeight : 0;
|
||||
break;
|
||||
case DISPLAY_METRIC_DPI:
|
||||
if ( !g_drm_mode || !g_drm_mode->hdisplay
|
||||
|| !g_drm_connector || !g_drm_connector->mmWidth)
|
||||
return false;
|
||||
*value = (float)g_drm_mode->hdisplay * 25.4f
|
||||
/ (float)g_drm_connector->mmWidth;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if (!n)
|
||||
return false;
|
||||
*value = (float)n;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool kms_display_server_get_metrics(void *data,
|
||||
enum display_metric_types type, float *value)
|
||||
{
|
||||
bool vrr;
|
||||
|
||||
if ( type != DISPLAY_METRIC_TOTAL_LINES
|
||||
|| !kms_display_server_mode_timed())
|
||||
if (type != DISPLAY_METRIC_TOTAL_LINES)
|
||||
return kms_display_server_geometry_metric(type, value);
|
||||
if (!kms_display_server_mode_timed())
|
||||
return false;
|
||||
/* Read with the line count, outside Scanline Sync's wait */
|
||||
vrr = g_crtc_id && kms_display_server_crtc_vrr(g_drm_fd, g_crtc_id);
|
||||
|
||||
+4
-32
@@ -30,6 +30,7 @@
|
||||
#include "../common/vulkan_video_import.h"
|
||||
#include <retro_inline.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <math/float16.h>
|
||||
#include <queues/mpsc_stack.h>
|
||||
#include <queues/task_queue.h>
|
||||
#include <retro_math.h>
|
||||
@@ -17375,35 +17376,6 @@ static bool vulkan_read_viewport_bgrx(void *data, uint8_t *buffer,
|
||||
}
|
||||
|
||||
#ifdef VULKAN_HDR_SWAPCHAIN
|
||||
/* IEEE-754 half (binary16) -> float, for reading an RGBA16F scRGB backbuffer
|
||||
* on the CPU. Handles normals, subnormals, sign and inf/nan. */
|
||||
static float vulkan_half_to_float(uint16_t h)
|
||||
{
|
||||
uint32_t sign = (uint32_t)(h & 0x8000) << 16;
|
||||
uint32_t exp = (h >> 10) & 0x1F;
|
||||
uint32_t mant = h & 0x3FF;
|
||||
uint32_t f;
|
||||
float out;
|
||||
if (exp == 0)
|
||||
{
|
||||
if (mant == 0)
|
||||
f = sign;
|
||||
else
|
||||
{
|
||||
exp = 127 - 15 + 1;
|
||||
while (!(mant & 0x400)) { mant <<= 1; exp--; }
|
||||
mant &= 0x3FF;
|
||||
f = sign | (exp << 23) | (mant << 13);
|
||||
}
|
||||
}
|
||||
else if (exp == 0x1F)
|
||||
f = sign | 0x7F800000 | (mant << 13);
|
||||
else
|
||||
f = sign | ((exp - 15 + 127) << 23) | (mant << 13);
|
||||
memcpy(&out, &f, sizeof(out));
|
||||
return out;
|
||||
}
|
||||
|
||||
/* ST.2084 (PQ) inverse-EOTF: normalised linear (v = nits/10000, [0,1]) ->
|
||||
* PQ code [0,1]. Same constants as the forward HDR pipeline. */
|
||||
static float vulkan_pq_encode(float v)
|
||||
@@ -17589,9 +17561,9 @@ static bool vulkan_read_viewport_hdr(void *data, uint16_t *buffer,
|
||||
int x;
|
||||
for (x = 0; x < (int)vp_width; x++)
|
||||
{
|
||||
float r = vulkan_half_to_float(row[x * 4 + 0]);
|
||||
float g = vulkan_half_to_float(row[x * 4 + 1]);
|
||||
float b = vulkan_half_to_float(row[x * 4 + 2]);
|
||||
float r = retro_half_to_float(row[x * 4 + 0]);
|
||||
float g = retro_half_to_float(row[x * 4 + 1]);
|
||||
float b = retro_half_to_float(row[x * 4 + 2]);
|
||||
float lvl;
|
||||
buffer[x * 3 + 0] = vulkan_scrgb_channel_to_pq16(r);
|
||||
buffer[x * 3 + 1] = vulkan_scrgb_channel_to_pq16(g);
|
||||
|
||||
@@ -432,6 +432,19 @@ static bool android_gfx_ctx_destroy_surface(void *data)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
/* A context in the share group, of the window's client API: OpenGL ES */
|
||||
static bool android_gfx_ctx_shared_context_new(void *data,
|
||||
gfx_ctx_shared_context_t *out)
|
||||
{
|
||||
android_ctx_data_t *and = (android_ctx_data_t*)data;
|
||||
memset(out, 0, sizeof(*out));
|
||||
if (!and || android_api != GFX_CTX_OPENGL_ES_API)
|
||||
return false;
|
||||
return egl_shared_context_new(&and->egl, EGL_OPENGL_ES_API, out);
|
||||
}
|
||||
#endif
|
||||
|
||||
const gfx_ctx_driver_t gfx_ctx_android = {
|
||||
android_gfx_ctx_init,
|
||||
android_gfx_ctx_destroy,
|
||||
@@ -473,9 +486,15 @@ const gfx_ctx_driver_t gfx_ctx_android = {
|
||||
NULL, /* presentable */
|
||||
NULL, /* last_present_time */
|
||||
android_gfx_ctx_release_current,
|
||||
#ifdef HAVE_EGL
|
||||
android_gfx_ctx_shared_context_new,
|
||||
egl_shared_context_bind,
|
||||
egl_shared_context_free,
|
||||
#else
|
||||
NULL, /* shared_context_new */
|
||||
NULL, /* shared_context_bind */
|
||||
NULL, /* shared_context_free */
|
||||
#endif
|
||||
#ifdef HAVE_EGL
|
||||
&android_gfx_ctx_windows
|
||||
#else
|
||||
|
||||
@@ -1447,6 +1447,28 @@ static bool gfx_ctx_drm_destroy_surface(void *data)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
/* A context in the share group, of the window's client API */
|
||||
static bool gfx_ctx_drm_shared_context_new(void *data,
|
||||
gfx_ctx_shared_context_t *out)
|
||||
{
|
||||
gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data;
|
||||
memset(out, 0, sizeof(*out));
|
||||
if (!drm)
|
||||
return false;
|
||||
switch (drm_api)
|
||||
{
|
||||
case GFX_CTX_OPENGL_API:
|
||||
return egl_shared_context_new(&drm->egl, EGL_OPENGL_API, out);
|
||||
case GFX_CTX_OPENGL_ES_API:
|
||||
return egl_shared_context_new(&drm->egl, EGL_OPENGL_ES_API, out);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
const gfx_ctx_driver_t gfx_ctx_drm = {
|
||||
gfx_ctx_drm_init,
|
||||
gfx_ctx_drm_destroy,
|
||||
@@ -1484,5 +1506,17 @@ const gfx_ctx_driver_t gfx_ctx_drm = {
|
||||
NULL,
|
||||
NULL,
|
||||
gfx_ctx_drm_create_surface,
|
||||
gfx_ctx_drm_destroy_surface
|
||||
gfx_ctx_drm_destroy_surface,
|
||||
NULL, /* presentable */
|
||||
NULL, /* last_present_time */
|
||||
NULL, /* release_current */
|
||||
#ifdef HAVE_EGL
|
||||
gfx_ctx_drm_shared_context_new,
|
||||
egl_shared_context_bind,
|
||||
egl_shared_context_free
|
||||
#else
|
||||
NULL, /* shared_context_new */
|
||||
NULL, /* shared_context_bind */
|
||||
NULL /* shared_context_free */
|
||||
#endif
|
||||
};
|
||||
@@ -152,6 +152,10 @@ static uint8_t wgl_flags;
|
||||
#ifdef HAVE_EGL
|
||||
static egl_ctx_data_t win32_egl;
|
||||
#endif
|
||||
/* The attributes the window's context was made with, for contexts in its
|
||||
* share group (gfx_ctx_wgl_shared_context_new); none for a legacy one */
|
||||
static int wgl_ctx_attribs[16];
|
||||
static bool wgl_ctx_attribs_used = false;
|
||||
static unsigned win32_major = 0;
|
||||
static unsigned win32_minor = 0;
|
||||
static int win32_interval = 0;
|
||||
@@ -368,6 +372,10 @@ void create_gl_context(HWND hwnd, bool *quit)
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
wgl_ctx_attribs[i] = attribs[i];
|
||||
wgl_ctx_attribs_used = true;
|
||||
|
||||
/* Found a suitable version that is high enough, we can stop now */
|
||||
break;
|
||||
}
|
||||
@@ -819,6 +827,71 @@ static void gfx_ctx_wgl_release_current(void *data)
|
||||
}
|
||||
}
|
||||
|
||||
#if (defined(HAVE_OPENGL) || defined(HAVE_OPENGL1) || defined(HAVE_OPENGL_CORE)) && !defined(HAVE_OPENGLES)
|
||||
/* A context in the share group of the one current on this thread - the
|
||||
* core's, or the window's - with the window's attributes, for a thread
|
||||
* of its own. It is made current on the window's device context: it
|
||||
* draws into framebuffers of its own, never into the window. */
|
||||
static bool gfx_ctx_wgl_shared_context_new(void *data,
|
||||
gfx_ctx_shared_context_t *out)
|
||||
{
|
||||
typedef HGLRC (APIENTRY *wglCreateContextAttribsProc)
|
||||
(HDC, HGLRC, const int*);
|
||||
HGLRC share = wglGetCurrentContext();
|
||||
HGLRC ctx = NULL;
|
||||
|
||||
memset(out, 0, sizeof(*out));
|
||||
if (win32_api != GFX_CTX_OPENGL_API || !win32_hdc || !win32_hrc)
|
||||
return false;
|
||||
if (!share)
|
||||
share = win32_hw_hrc ? win32_hw_hrc : win32_hrc;
|
||||
|
||||
if (wgl_ctx_attribs_used)
|
||||
{
|
||||
wglCreateContextAttribsProc create = (wglCreateContextAttribsProc)
|
||||
gfx_ctx_wgl_get_proc_address("wglCreateContextAttribsARB");
|
||||
if (create)
|
||||
ctx = create(win32_hdc, share, wgl_ctx_attribs);
|
||||
}
|
||||
else if ((ctx = wglCreateContext(win32_hdc)) && !wglShareLists(share, ctx))
|
||||
{
|
||||
wglDeleteContext(ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
if (!ctx)
|
||||
{
|
||||
RARCH_ERR("[WGL] A shared context could not be made: 0x%08lx.\n",
|
||||
(unsigned long)GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
out->kind = GFX_CTX_SHARED_WGL;
|
||||
out->context = ctx;
|
||||
out->get_proc_address = gfx_ctx_wgl_get_proc_address;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gfx_ctx_wgl_shared_context_bind(gfx_ctx_shared_context_t *ctx,
|
||||
bool bind)
|
||||
{
|
||||
if (ctx->kind != GFX_CTX_SHARED_WGL)
|
||||
return false;
|
||||
if (!bind)
|
||||
return wglMakeCurrent(NULL, NULL) ? true : false;
|
||||
/* The window's, read now: a window made again has another one, of the
|
||||
* same pixel format */
|
||||
return wglMakeCurrent(win32_hdc, (HGLRC)ctx->context) ? true : false;
|
||||
}
|
||||
|
||||
static void gfx_ctx_wgl_shared_context_free(gfx_ctx_shared_context_t *ctx)
|
||||
{
|
||||
if (ctx->kind != GFX_CTX_SHARED_WGL)
|
||||
return;
|
||||
wglDeleteContext((HGLRC)ctx->context);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void gfx_ctx_wgl_bind_hw_render(void *data, bool enable)
|
||||
{
|
||||
switch (win32_api)
|
||||
@@ -1058,5 +1131,14 @@ const gfx_ctx_driver_t gfx_ctx_wgl = {
|
||||
gfx_ctx_wgl_destroy_surface,
|
||||
gfx_ctx_wgl_presentable,
|
||||
gfx_ctx_wgl_last_present_time,
|
||||
gfx_ctx_wgl_release_current
|
||||
gfx_ctx_wgl_release_current,
|
||||
#if (defined(HAVE_OPENGL) || defined(HAVE_OPENGL1) || defined(HAVE_OPENGL_CORE)) && !defined(HAVE_OPENGLES)
|
||||
gfx_ctx_wgl_shared_context_new,
|
||||
gfx_ctx_wgl_shared_context_bind,
|
||||
gfx_ctx_wgl_shared_context_free
|
||||
#else
|
||||
NULL, /* shared_context_new */
|
||||
NULL, /* shared_context_bind */
|
||||
NULL /* shared_context_free */
|
||||
#endif
|
||||
};
|
||||
+4
-1292
File diff suppressed because it is too large.
Load diff
@@ -5102,6 +5102,87 @@ bool video_driver_hw_render_interface_kept(void)
|
||||
return iface == video_hw_render_iface_held;
|
||||
}
|
||||
|
||||
/* RETRO_ENVIRONMENT_GET_HW_SHARED_CONTEXT_INTERFACE: the context driver's
|
||||
* contexts in the window context's share group, which the core's context
|
||||
* is in too, handed to the core for threads of its own. Made at most a few
|
||||
* times a session (one per thread of the core's), so each its own block. */
|
||||
struct retro_hw_shared_context
|
||||
{
|
||||
gfx_ctx_shared_context_t shared;
|
||||
};
|
||||
|
||||
static struct retro_hw_shared_context *RETRO_CALLCONV
|
||||
video_hw_shared_context_create(void)
|
||||
{
|
||||
video_driver_state_t *video_st = &video_driver_st;
|
||||
const gfx_ctx_driver_t *ctx = &video_st->current_video_context;
|
||||
struct retro_hw_shared_context *out;
|
||||
|
||||
if ( !ctx->shared_context_new
|
||||
|| !video_st->context_data
|
||||
|| !(out = (struct retro_hw_shared_context*)calloc(1, sizeof(*out))))
|
||||
return NULL;
|
||||
if (!ctx->shared_context_new((void*)video_st->context_data, &out->shared))
|
||||
{
|
||||
free(out);
|
||||
return NULL;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static bool RETRO_CALLCONV video_hw_shared_context_make_current(
|
||||
struct retro_hw_shared_context *ctx, bool current)
|
||||
{
|
||||
const gfx_ctx_driver_t *drv = &video_driver_st.current_video_context;
|
||||
if (!ctx || !drv->shared_context_bind)
|
||||
return false;
|
||||
return drv->shared_context_bind(&ctx->shared, current);
|
||||
}
|
||||
|
||||
static void RETRO_CALLCONV video_hw_shared_context_destroy(
|
||||
struct retro_hw_shared_context *ctx)
|
||||
{
|
||||
const gfx_ctx_driver_t *drv = &video_driver_st.current_video_context;
|
||||
if (!ctx)
|
||||
return;
|
||||
if (drv->shared_context_free)
|
||||
drv->shared_context_free(&ctx->shared);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static const struct retro_hw_shared_context_interface
|
||||
video_hw_shared_context_iface = {
|
||||
RETRO_HW_SHARED_CONTEXT_INTERFACE_VERSION,
|
||||
video_hw_shared_context_create,
|
||||
video_hw_shared_context_make_current,
|
||||
video_hw_shared_context_destroy
|
||||
};
|
||||
|
||||
const struct retro_hw_shared_context_interface
|
||||
*video_driver_hw_shared_context_interface(void)
|
||||
{
|
||||
video_driver_state_t *video_st = &video_driver_st;
|
||||
const gfx_ctx_driver_t *ctx = &video_st->current_video_context;
|
||||
|
||||
switch (video_st->hw_render.context_type)
|
||||
{
|
||||
case RETRO_HW_CONTEXT_OPENGL:
|
||||
case RETRO_HW_CONTEXT_OPENGL_CORE:
|
||||
case RETRO_HW_CONTEXT_OPENGLES2:
|
||||
case RETRO_HW_CONTEXT_OPENGLES3:
|
||||
case RETRO_HW_CONTEXT_OPENGLES_VERSION:
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
if ( !video_st->context_data
|
||||
|| !ctx->shared_context_new
|
||||
|| !ctx->shared_context_bind
|
||||
|| !ctx->shared_context_free)
|
||||
return NULL;
|
||||
return &video_hw_shared_context_iface;
|
||||
}
|
||||
|
||||
bool video_driver_hw_context_moved(int before, bool shared)
|
||||
{
|
||||
return before != -1 && before != (shared ? 1 : 0);
|
||||
|
||||
+15
-6
@@ -829,7 +829,8 @@ enum gfx_ctx_shared_kind
|
||||
{
|
||||
GFX_CTX_SHARED_NONE = 0,
|
||||
GFX_CTX_SHARED_EGL,
|
||||
GFX_CTX_SHARED_GLX
|
||||
GFX_CTX_SHARED_GLX,
|
||||
GFX_CTX_SHARED_WGL
|
||||
};
|
||||
|
||||
/* A second context in the window context's share group, for a thread
|
||||
@@ -841,7 +842,7 @@ typedef struct gfx_ctx_shared_context
|
||||
enum gfx_ctx_shared_kind kind;
|
||||
void *display; /* EGLDisplay, or the X Display */
|
||||
void *config; /* EGLConfig, or GLXFBConfig */
|
||||
void *context; /* EGLContext, or GLXContext */
|
||||
void *context; /* EGLContext, GLXContext or HGLRC */
|
||||
void *surface; /* EGL: its own pbuffer, NULL surfaceless */
|
||||
unsigned long drawable; /* GLX: its own pbuffer */
|
||||
unsigned visual_id; /* GLX: the config's visual */
|
||||
@@ -1011,10 +1012,12 @@ typedef struct gfx_ctx_driver
|
||||
void (*release_current)(void *data);
|
||||
|
||||
/* Optional, desktop GL: a context in the window context's share
|
||||
* group (gfx_ctx_shared_context_t). New and free run on the video
|
||||
* thread with the window's context current, and leave it so; bind
|
||||
* and unbind run on the thread that uses the context, which never
|
||||
* gets the window's surface. NULL where the driver has none. Placed
|
||||
* group (gfx_ctx_shared_context_t). New and free run on a thread
|
||||
* with a context of the group current - the video thread with the
|
||||
* window's, or a hardware core's thread with the core's
|
||||
* (RETRO_ENVIRONMENT_GET_HW_SHARED_CONTEXT_INTERFACE) - and leave it
|
||||
* so; bind and unbind run on the thread that uses the context, which
|
||||
* never gets the window's surface. NULL where the driver has none. Placed
|
||||
* last, as above. */
|
||||
bool (*shared_context_new)(void *data, gfx_ctx_shared_context_t *out);
|
||||
bool (*shared_context_bind)(gfx_ctx_shared_context_t *ctx, bool bind);
|
||||
@@ -2827,6 +2830,12 @@ void video_driver_cache_context_ack_set(void);
|
||||
* restart - and the core has to be reset after all. True for a core
|
||||
* that holds none. */
|
||||
void video_driver_hw_render_interface_note(const struct retro_hw_render_interface *iface);
|
||||
|
||||
/* RETRO_ENVIRONMENT_GET_HW_SHARED_CONTEXT_INTERFACE's answer: NULL when the
|
||||
* core's context is not OpenGL or the context driver cannot make contexts
|
||||
* in its share group. */
|
||||
const struct retro_hw_shared_context_interface
|
||||
*video_driver_hw_shared_context_interface(void);
|
||||
bool video_driver_hw_render_interface_kept(void);
|
||||
/* Which of a GL driver's contexts a hardware core renders in: its own,
|
||||
* shared with the driver's (@shared), or the driver's. Called by the
|
||||
|
||||
@@ -582,6 +582,9 @@ VIDEO IMAGE
|
||||
#ifdef HAVE_RTGA
|
||||
#include "../libretro-common/formats/tga/rtga.c"
|
||||
#endif
|
||||
#ifdef HAVE_RGIF
|
||||
#include "../libretro-common/formats/gif/rgif.c"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IMAGEVIEWER
|
||||
#include "../cores/libretro-imageviewer/image_core.c"
|
||||
@@ -776,6 +779,13 @@ VIDEO DRIVER
|
||||
#include "../gfx/drivers/d3d12.c"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MF_AUDIO
|
||||
#include "../record/record_mf_audio.c"
|
||||
#if defined(HAVE_D3D12) && defined(HAVE_RTMP) && defined(HAVE_RFLV)
|
||||
#include "../record/record_stream_d3d12.c"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_D3D10)
|
||||
#include "../gfx/drivers/d3d10.c"
|
||||
#endif
|
||||
@@ -905,6 +915,7 @@ FONTS
|
||||
|
||||
#include "../gfx/font_driver.c"
|
||||
|
||||
#include "../libretro-common/gfx/font/rtt.c"
|
||||
#include "../gfx/drivers_font_renderer/stb.c"
|
||||
|
||||
#if defined(HAVE_FREETYPE)
|
||||
@@ -1712,6 +1723,7 @@ RECORDING
|
||||
#include "../record/record_mp4_audio_edit.c"
|
||||
#include "../record/record_mediacodec_encoder.c"
|
||||
#include "../record/record_mux_mediacodec.c"
|
||||
#include "../record/record_aac_stream_timing.c"
|
||||
#include "../record/record_mediacodec_worker.c"
|
||||
#include "../record/record_mediacodec_surface.c"
|
||||
#include "../record/record_mediacodec_file.c"
|
||||
@@ -1740,6 +1752,12 @@ RECORDING
|
||||
#include "../record/record_avfoundation_worker.c"
|
||||
#include "../record/record_avfoundation_session.c"
|
||||
#include "../libretro-common/formats/h265/rh265_sps_crop.c"
|
||||
#if defined(HAVE_NETWORKING) && defined(HAVE_RTMP) && defined(HAVE_RFLV)
|
||||
#include "../record/record_stream_vt.c"
|
||||
#include "../record/record_stream_output_vt.c"
|
||||
#include "../record/record_vt_packet.c"
|
||||
#include "../libretro-common/net/net_wake.c"
|
||||
#endif
|
||||
#endif
|
||||
#ifdef HAVE_FFMPEG
|
||||
#include "../record/drivers/record_ffmpeg.c"
|
||||
@@ -1787,6 +1805,7 @@ NETPLAY
|
||||
#include "../network/netplay/netplay_room_parse.c"
|
||||
#include "../libretro-common/net/net_compat.c"
|
||||
#include "../libretro-common/net/net_socket.c"
|
||||
#include "../libretro-common/net/net_resolve.c"
|
||||
#include "../libretro-common/net/net_http.c"
|
||||
#ifdef HAVE_RTMP
|
||||
#include "../libretro-common/net/net_rtmp_chunk.c"
|
||||
@@ -1798,6 +1817,7 @@ NETPLAY
|
||||
#include "../libretro-common/net/net_rtmp_reply.c"
|
||||
#include "../libretro-common/net/net_rtmp_session.c"
|
||||
#include "../libretro-common/net/net_rtmp_socket.c"
|
||||
#include "../libretro-common/net/net_rtmp_client.c"
|
||||
#endif
|
||||
#ifdef HAVE_IFINFO
|
||||
#include "../libretro-common/net/net_ifinfo.c"
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_AVF
|
||||
#include "../record/record_at_audio.c"
|
||||
#include "../camera/drivers/avfoundation.m"
|
||||
#include "../record/drivers/record_avfoundation.m"
|
||||
#endif
|
||||
@@ -84,6 +85,9 @@
|
||||
#include "../record/record_gpu_capture_metal.m"
|
||||
#include "../record/record_mux_avfoundation.m"
|
||||
#include "../record/record_gpu_session_metal.m"
|
||||
#if defined(HAVE_NETWORKING) && defined(HAVE_RTMP) && defined(HAVE_RFLV)
|
||||
#include "../record/record_at_resample.c"
|
||||
#endif
|
||||
#include "../record/record_gpu_dispatch_metal.m"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+65
-34
@@ -514,6 +514,9 @@ typedef struct
|
||||
bool run_state_update;
|
||||
/* Touch panel properties */
|
||||
bool is_touch_device;
|
||||
/* Contacts come in MT slots; the single-touch emulation
|
||||
* (ABS_X/ABS_Y/BTN_TOUCH) repeats one of them and is ignored. */
|
||||
bool mt_slots;
|
||||
} udev_input_touch_t;
|
||||
|
||||
#endif
|
||||
@@ -715,7 +718,6 @@ static bool udev_vp_ok;
|
||||
static udev_input_mouse_t *udev_get_mouse(
|
||||
struct udev_input *udev, unsigned port)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned mouse_index = 0;
|
||||
int dev_index = -1;
|
||||
|
||||
@@ -1131,10 +1133,8 @@ static void udev_touch_ts_print(const udev_touch_ts_t *ts)
|
||||
static udev_input_device_t *udev_get_pointer_port_dev(
|
||||
struct udev_input *udev, unsigned port)
|
||||
{
|
||||
uint16_t i;
|
||||
uint16_t pointer_index = 0;
|
||||
int16_t dev_index = -1;
|
||||
udev_input_mouse_t *mouse = NULL;
|
||||
|
||||
if (port >= MAX_USERS || !video_driver_has_focus())
|
||||
return NULL;
|
||||
@@ -1506,13 +1506,19 @@ static void udev_init_touch_dev(udev_input_device_t *dev)
|
||||
{
|
||||
RARCH_WARN("[udev] Failed to get touchscreen limits.\n");
|
||||
|
||||
/* One slot, fed by the single-touch events */
|
||||
memset(&abs_info, 0, sizeof(abs_info));
|
||||
udev_touch_set_limits_from(&abs_info, &touch->info_slots);
|
||||
touch->info_slots.enabled = false;
|
||||
}
|
||||
else
|
||||
udev_touch_set_limits_from(&abs_info, &touch->info_slots);
|
||||
|
||||
touch->mt_slots = touch->info_slots.enabled
|
||||
&& touch->info_slots.range > 1;
|
||||
|
||||
/* Single-touch devices use ABS_X/Y, Multi-touch use ABS_MT_POSITION_X/Y */
|
||||
if (abs_info.maximum == 0)
|
||||
if (!touch->mt_slots)
|
||||
{
|
||||
/* TODO - Test for single-touch devices. */
|
||||
RARCH_WARN("[udev] Single-touch devices are currently untested.\n");
|
||||
@@ -1608,9 +1614,15 @@ static void udev_init_touch_dev(udev_input_device_t *dev)
|
||||
udev_destroy_touch_dev(dev);
|
||||
return;
|
||||
}
|
||||
for (iii = 0; iii < touch->info_slots.range; ++iii)
|
||||
{
|
||||
touch->staging[iii].tracking_id = UDEV_INPUT_TOUCH_TRACKING_ID_NONE;
|
||||
touch->current[iii].tracking_id = UDEV_INPUT_TOUCH_TRACKING_ID_NONE;
|
||||
}
|
||||
|
||||
/* Initialize touch device */
|
||||
touch->current_slot = UDEV_INPUT_TOUCH_SLOT_ID_NONE;
|
||||
/* Initialize touch device; the kernel starts on slot 0 and does
|
||||
* not announce it */
|
||||
touch->current_slot = 0;
|
||||
touch->is_touch_device = true;
|
||||
touch->run_state_update = false;
|
||||
udev_touch_ts_now(&touch->last_state_update);
|
||||
@@ -1711,7 +1723,7 @@ static void udev_sync_touch(udev_input_device_t *dev)
|
||||
int32_t *mt_req_values;
|
||||
uint8_t *mt_request_data;
|
||||
size_t mt_request_data_size;
|
||||
size_t slot_count;
|
||||
int slot_count;
|
||||
udev_touch_ts_t now;
|
||||
udev_input_touch_t *touch = &dev->touch;
|
||||
udev_slot_state_t *staging = dev->touch.staging;
|
||||
@@ -1754,6 +1766,11 @@ static void udev_sync_touch(udev_input_device_t *dev)
|
||||
staging[iii].tracking_id = mt_req_values[iii];
|
||||
udev_touch_ts_copy(&now, &staging[iii].td_time);
|
||||
}
|
||||
/* Contacts begun or ended unseen are counted as they are now */
|
||||
touch->staging_active = 0;
|
||||
for (iii = 0; iii < slot_count; ++iii)
|
||||
if (staging[iii].tracking_id >= 0)
|
||||
touch->staging_active++;
|
||||
|
||||
/* Request MT position on the x-axis for each slot */
|
||||
*mt_req_code = ABS_MT_POSITION_X;
|
||||
@@ -1856,8 +1873,8 @@ static bool udev_translate_touch_pos(
|
||||
* One way to fix this is to add or remove 0.5, but this needs floating
|
||||
* point operations which might not be desirable.
|
||||
*/
|
||||
int32_t ma_pos_x = (((((pointer_pos_x + src_touch->info_x_limits.min) * 0x7fff) / src_touch->info_x_limits.range) * VIDEO_SCALE_W(target_vp->full_dims)) / 0x7fff);
|
||||
int32_t ma_pos_y = (((((pointer_pos_y + src_touch->info_y_limits.min) * 0x7fff) / src_touch->info_y_limits.range) * VIDEO_SCALE_H(target_vp->full_dims)) / 0x7fff);
|
||||
int32_t ma_pos_x = (((((pointer_pos_x - src_touch->info_x_limits.min) * 0x7fff) / src_touch->info_x_limits.range) * VIDEO_SCALE_W(target_vp->full_dims)) / 0x7fff);
|
||||
int32_t ma_pos_y = (((((pointer_pos_y - src_touch->info_y_limits.min) * 0x7fff) / src_touch->info_y_limits.range) * VIDEO_SCALE_H(target_vp->full_dims)) / 0x7fff);
|
||||
|
||||
/* Calculate relative offsets. */
|
||||
VIDEO_POS_ADD(*pointer_ma_rel, ma_pos_x - VIDEO_POS_X(*pointer_ma_pos),
|
||||
@@ -2390,7 +2407,7 @@ static void udev_report_touch(udev_input_t *udev, udev_input_device_t *dev)
|
||||
/* Simulated pointer */
|
||||
/* Release the pointer only after all contacts are released */
|
||||
if (touch->pointer_enabled)
|
||||
touch->pointer_btn_pp = (touch->staging_active == 0);
|
||||
touch->pointer_btn_pp = (touch->staging_active > 0);
|
||||
|
||||
/* Mouse section */
|
||||
if (touch->mouse_enabled)
|
||||
@@ -2603,8 +2620,8 @@ static void udev_handle_touch(void *data,
|
||||
const struct input_event *event, udev_input_device_t *dev)
|
||||
{
|
||||
udev_input_t *udev = (udev_input_t*)data;
|
||||
udev_input_mouse_t *mouse = &dev->mouse;
|
||||
udev_input_touch_t *touch = &dev->touch;
|
||||
udev_slot_state_t *st0 = touch->staging;
|
||||
|
||||
/* struct input_event */
|
||||
/* { */
|
||||
@@ -2657,16 +2674,18 @@ static void udev_handle_touch(void *data,
|
||||
}
|
||||
break;
|
||||
case ABS_X:
|
||||
/* TODO - Currently using single-touch events as touch with id 0 */
|
||||
/* Single-touch contact, kept in slot 0 */
|
||||
if (touch->mt_slots)
|
||||
break;
|
||||
RARCH_DDBG("[udev] handle_touch: [0] ST_X to %d\n", event->value);
|
||||
VIDEO_POS_PUT_X(touch->staging[0].pos, event->value);
|
||||
|
||||
/* Low priority event, mark the change. */
|
||||
if (touch->staging[0].change == UDEV_TOUCH_CHANGE_NONE)
|
||||
touch->staging[0].change = UDEV_TOUCH_CHANGE_MOVE;
|
||||
VIDEO_POS_PUT_X(st0->pos, event->value);
|
||||
/* Starting tracing, remember touchdown position. */
|
||||
else if (touch->staging[0].change == UDEV_TOUCH_CHANGE_DOWN)
|
||||
VIDEO_POS_PUT_X(touch->staging[0].td_pos, event->value);
|
||||
if (st0->change == UDEV_TOUCH_CHANGE_DOWN)
|
||||
VIDEO_POS_PUT_X(st0->td_pos, event->value);
|
||||
/* Low priority event, mark the change of a held contact. */
|
||||
else if (st0->change == UDEV_TOUCH_CHANGE_NONE
|
||||
&& st0->tracking_id >= 0)
|
||||
st0->change = UDEV_TOUCH_CHANGE_MOVE;
|
||||
break;
|
||||
case ABS_MT_POSITION_X:
|
||||
RARCH_DDBG("[udev] handle_touch: [%d] MT_X to %d\n", touch->current_slot, event->value);
|
||||
@@ -2679,15 +2698,15 @@ static void udev_handle_touch(void *data,
|
||||
VIDEO_POS_PUT_X(touch->staging[touch->current_slot].td_pos, event->value);
|
||||
break;
|
||||
case ABS_Y:
|
||||
/* TODO - Currently using single-touch events as touch with id 0 */
|
||||
if (touch->mt_slots)
|
||||
break;
|
||||
RARCH_DDBG("[udev] handle_touch: [0] ST_Y to %d\n", event->value);
|
||||
VIDEO_POS_PUT_Y(touch->staging[0].pos, event->value);
|
||||
/* Low priority event, mark the change. */
|
||||
if (touch->staging[0].change == UDEV_TOUCH_CHANGE_NONE)
|
||||
touch->staging[0].change = UDEV_TOUCH_CHANGE_MOVE;
|
||||
/* Starting tracing, remember touchdown position. */
|
||||
else if (touch->staging[0].change == UDEV_TOUCH_CHANGE_DOWN)
|
||||
VIDEO_POS_PUT_Y(touch->staging[0].td_pos, event->value);
|
||||
VIDEO_POS_PUT_Y(st0->pos, event->value);
|
||||
if (st0->change == UDEV_TOUCH_CHANGE_DOWN)
|
||||
VIDEO_POS_PUT_Y(st0->td_pos, event->value);
|
||||
else if (st0->change == UDEV_TOUCH_CHANGE_NONE
|
||||
&& st0->tracking_id >= 0)
|
||||
st0->change = UDEV_TOUCH_CHANGE_MOVE;
|
||||
break;
|
||||
case ABS_MT_POSITION_Y:
|
||||
RARCH_DDBG("[udev] handle_touch: [%d] MT_Y to %d\n", touch->current_slot, event->value);
|
||||
@@ -2728,11 +2747,25 @@ static void udev_handle_touch(void *data,
|
||||
case EV_KEY:
|
||||
if (event->code == BTN_TOUCH)
|
||||
{
|
||||
RARCH_DDBG("[udev] handle_touch: [%d] TOUCH %d\n", touch->current_slot, event->value);
|
||||
/* Single-touch contact, kept in slot 0 */
|
||||
if (touch->mt_slots)
|
||||
break;
|
||||
RARCH_DDBG("[udev] handle_touch: [0] TOUCH %d\n", event->value);
|
||||
if (event->value > 0)
|
||||
touch->staging[touch->current_slot].change = UDEV_TOUCH_CHANGE_DOWN;
|
||||
else
|
||||
touch->staging[touch->current_slot].change = UDEV_TOUCH_CHANGE_UP;
|
||||
{
|
||||
if (st0->tracking_id < 0)
|
||||
{
|
||||
st0->tracking_id = 0;
|
||||
st0->change = UDEV_TOUCH_CHANGE_DOWN;
|
||||
st0->td_pos = st0->pos;
|
||||
udev_touch_event_ts_copy(event, &st0->td_time);
|
||||
}
|
||||
}
|
||||
else if (st0->tracking_id >= 0)
|
||||
{
|
||||
st0->tracking_id = UDEV_INPUT_TOUCH_TRACKING_ID_NONE;
|
||||
st0->change = UDEV_TOUCH_CHANGE_UP;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
@@ -3036,8 +3069,7 @@ static int16_t udev_input_touch_state(
|
||||
|
||||
case RETRO_DEVICE_POINTER:
|
||||
case RARCH_DEVICE_POINTER_SCREEN:
|
||||
screen = (device == RARCH_DEVICE_MOUSE_SCREEN);
|
||||
break;
|
||||
screen = (device == RARCH_DEVICE_POINTER_SCREEN);
|
||||
switch (id)
|
||||
{
|
||||
case RETRO_DEVICE_ID_POINTER_X:
|
||||
@@ -3552,7 +3584,6 @@ static void udev_input_handle_hotplug(udev_input_t *udev)
|
||||
const char *val_touchscreen = NULL;
|
||||
const char *action = NULL;
|
||||
const char *devnode = NULL;
|
||||
int check = 0;
|
||||
struct udev_device *dev = udev_monitor_receive_device(
|
||||
udev->monitor);
|
||||
|
||||
|
||||
+1
-5
@@ -2349,7 +2349,6 @@ static const struct
|
||||
char s_aa08c6d6[124];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[59];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[111];
|
||||
char s_b4816da6[77];
|
||||
@@ -9628,8 +9627,6 @@ static const struct
|
||||
"\200\321\213\320\273\320\260\320\264\320\260\321\205",
|
||||
#endif
|
||||
#endif
|
||||
"\320\237\320\276\321\210\321\203\320\272 \321\226 \320\277\320\260\320\264\320\273\321\203\321"
|
||||
"\207\321\215\320\275\320\275\320\265 bluetooth-\320\277\321\200\321\213\320\273\320\260\320\264.",
|
||||
#ifdef _3DS
|
||||
"\320\232\320\260\321\202\320\260\320\273\320\276\320\263 \321\200\321\215\321\201\321\203\321"
|
||||
"\200\321\201\320\260\321\236 \320\264\320\273\321\217 \320\275\321\226\320\266\320\275\321\217"
|
||||
@@ -16515,7 +16512,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_be_blob_check[
|
||||
(sizeof(msg_hash_be_blob) == (259250u
|
||||
(sizeof(msg_hash_be_blob) == (259191u
|
||||
#ifdef ANDROID
|
||||
+ 531u
|
||||
#endif
|
||||
@@ -19203,7 +19200,6 @@ static const msg_hash_id_t msg_hash_be_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+1
-4
@@ -2832,7 +2832,6 @@ static const struct
|
||||
char s_aa08c6d6[89];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[46];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[107];
|
||||
char s_b4816da6[57];
|
||||
@@ -7956,7 +7955,6 @@ static const struct
|
||||
"Desactiva el ERTM del senyal Bluetooth per corregir l'emparellament d'alguns dispositius",
|
||||
#endif
|
||||
#endif
|
||||
"Escaneja dispositius bluetooth i connecta-hi.",
|
||||
#ifdef _3DS
|
||||
"Indica la carpeta de recursos de la pantalla inferior. La carpeta ha de tenir un fitxer \"bottom"
|
||||
"_menu.png\".",
|
||||
@@ -10912,7 +10910,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_ca_blob_check[
|
||||
(sizeof(msg_hash_ca_blob) == (243481u
|
||||
(sizeof(msg_hash_ca_blob) == (243435u
|
||||
#ifdef ANDROID
|
||||
+ 281u
|
||||
#endif
|
||||
@@ -14285,7 +14283,6 @@ static const msg_hash_id_t msg_hash_ca_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+1
-5
@@ -2900,7 +2900,6 @@ static const struct
|
||||
char s_aa08c6d6[49];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[37];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[64];
|
||||
char s_b4816da6[45];
|
||||
@@ -9185,8 +9184,6 @@ static const struct
|
||||
"\237\220\344\272\233\350\256\276\345\244\207\347\232\204\351\205\215\345\257\271",
|
||||
#endif
|
||||
#endif
|
||||
"\346\211\253\346\217\217\350\223\235\347\211\231\350\256\276\345\244\207\345\271\266\350\277\236"
|
||||
"\346\216\245\345\256\203\344\273\254\343\200\202",
|
||||
#ifdef _3DS
|
||||
"\345\272\225\351\203\250\345\261\217\345\271\225\350\265\204\344\272\247\347\233\256\345\275\225"
|
||||
"\343\200\202\347\233\256\345\275\225\345\277\205\351\241\273\345\214\205\345\220\253 \"bow_menu."
|
||||
@@ -14974,7 +14971,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_chs_blob_check[
|
||||
(sizeof(msg_hash_chs_blob) == (182082u
|
||||
(sizeof(msg_hash_chs_blob) == (182045u
|
||||
#ifdef ANDROID
|
||||
+ 220u
|
||||
#endif
|
||||
@@ -18441,7 +18438,6 @@ static const msg_hash_id_t msg_hash_chs_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+1
-5
@@ -2310,7 +2310,6 @@ static const struct
|
||||
#ifdef HAVE_LAKKA
|
||||
char s_2bab34b2[22];
|
||||
#endif
|
||||
char s_27aef25c[31];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[102];
|
||||
char s_b4816da6[34];
|
||||
@@ -6968,8 +6967,6 @@ static const struct
|
||||
#ifdef HAVE_LAKKA
|
||||
"\351\205\215\345\260\215\350\227\215\347\211\231\350\243\235\347\275\256\343\200\202",
|
||||
#endif
|
||||
"\346\216\203\346\217\217\350\227\215\347\211\231\350\243\235\347\275\256\344\270\246\351\200\243"
|
||||
"\346\216\245\343\200\202",
|
||||
#ifdef _3DS
|
||||
"\350\250\255\345\256\232\344\270\213\350\236\242\345\271\225\347\232\204\351\201\270\345\226\256"
|
||||
"\344\270\273\351\241\214\350\263\207\346\226\231\345\244\276\344\275\215\347\275\256, \350\263"
|
||||
@@ -10477,7 +10474,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_cht_blob_check[
|
||||
(sizeof(msg_hash_cht_blob) == (120267u
|
||||
(sizeof(msg_hash_cht_blob) == (120236u
|
||||
#ifdef ANDROID
|
||||
+ 157u
|
||||
#endif
|
||||
@@ -13092,7 +13089,6 @@ static const msg_hash_id_t msg_hash_cht_ids[] =
|
||||
#ifdef HAVE_LAKKA
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ENABLE,
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+1
-4
@@ -2268,7 +2268,6 @@ static const struct
|
||||
char s_aa08c6d6[78];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[49];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[84];
|
||||
char s_b4816da6[50];
|
||||
@@ -6405,7 +6404,6 @@ static const struct
|
||||
"\275ch za\305\231\303\255zen\303\255",
|
||||
#endif
|
||||
#endif
|
||||
"Vyhledejte za\305\231\303\255zen\303\255 Bluetooth a p\305\231ipojte je.",
|
||||
#ifdef _3DS
|
||||
"Adres\303\241\305\231 aktiv na spodn\303\255 obrazovce. Adres\303\241\305\231 mus\303\255 obsaho"
|
||||
"vat \"spodn\303\255_menu.png\".",
|
||||
@@ -8810,7 +8808,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_cs_blob_check[
|
||||
(sizeof(msg_hash_cs_blob) == (161551u
|
||||
(sizeof(msg_hash_cs_blob) == (161502u
|
||||
#ifdef ANDROID
|
||||
+ 390u
|
||||
#endif
|
||||
@@ -11429,7 +11427,6 @@ static const msg_hash_id_t msg_hash_cs_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+1
-4
@@ -2828,7 +2828,6 @@ static const struct
|
||||
char s_aa08c6d6[74];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[55];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[84];
|
||||
char s_b4816da6[52];
|
||||
@@ -8046,7 +8045,6 @@ static const struct
|
||||
"Bluetooth ERTM deaktivieren, um das Koppeln einiger Ger\303\244te zu verbessern",
|
||||
#endif
|
||||
#endif
|
||||
"Nach Bluetoothger\303\244ten suchen und mit ihnen verbinden.",
|
||||
#ifdef _3DS
|
||||
"Unterer Bildschirm Asset Verzeichnis. Verzeichnis muss \"bottom_menu.png\" enthalten.",
|
||||
"Blaue Schriftfarbe auf unteren Bildschirm anpassen.",
|
||||
@@ -11189,7 +11187,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_de_blob_check[
|
||||
(sizeof(msg_hash_de_blob) == (255124u
|
||||
(sizeof(msg_hash_de_blob) == (255069u
|
||||
#ifdef ANDROID
|
||||
+ 358u
|
||||
#endif
|
||||
@@ -14578,7 +14576,6 @@ static const msg_hash_id_t msg_hash_de_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+1
-4
@@ -264,7 +264,6 @@ static const struct
|
||||
char s_3c3598a9[39];
|
||||
char s_a8d552a7[43];
|
||||
char s_6112ec7c[38];
|
||||
char s_27aef25c[45];
|
||||
#ifdef _3DS
|
||||
char s_b4816da6[39];
|
||||
char s_450ca36f[40];
|
||||
@@ -812,7 +811,6 @@ static const struct
|
||||
"Change audio synchronisation settings.",
|
||||
"Load customised configuration at start-up.",
|
||||
"Load customised controls at start-up.",
|
||||
"Scan for Bluetooth devices and connect them.",
|
||||
#ifdef _3DS
|
||||
"Adjust bottom screen font blue colour.",
|
||||
"Adjust bottom screen font green colour.",
|
||||
@@ -1141,7 +1139,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_en_blob_check[
|
||||
(sizeof(msg_hash_en_blob) == (26222u
|
||||
(sizeof(msg_hash_en_blob) == (26177u
|
||||
#ifdef HAVE_LAKKA
|
||||
+ 176u
|
||||
#endif
|
||||
@@ -1475,7 +1473,6 @@ static const msg_hash_id_t msg_hash_en_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_AUDIO_SYNCHRONIZATION_SETTINGS,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_AUTO_OVERRIDES_ENABLE,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_AUTO_REMAPS_ENABLE,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_GREEN,
|
||||
|
||||
+1
-4
@@ -2539,7 +2539,6 @@ static const struct
|
||||
char s_aa08c6d6[68];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[49];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[82];
|
||||
char s_b4816da6[58];
|
||||
@@ -6986,7 +6985,6 @@ static const struct
|
||||
"Malebligi ERTM de Bluetooth por ripari kupladon de kelkaj aparatoj.",
|
||||
#endif
|
||||
#endif
|
||||
"Ser\304\211i aparatojn kun bluetooth kaj konekti ilin.",
|
||||
#ifdef _3DS
|
||||
"Havaja dosierujo de malsupra ekrano. Dosierujo devas inkluzivi \"bottom_menu.png\".",
|
||||
"Al\304\235ustigi la bluecon de la tiparo de la malsupra ekrano.",
|
||||
@@ -9170,7 +9168,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_eo_blob_check[
|
||||
(sizeof(msg_hash_eo_blob) == (170789u
|
||||
(sizeof(msg_hash_eo_blob) == (170740u
|
||||
#ifdef ANDROID
|
||||
+ 312u
|
||||
#endif
|
||||
@@ -12139,7 +12137,6 @@ static const msg_hash_id_t msg_hash_eo_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+1
-4
@@ -2939,7 +2939,6 @@ static const struct
|
||||
char s_aa08c6d6[98];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[58];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[116];
|
||||
char s_b4816da6[59];
|
||||
@@ -8272,7 +8271,6 @@ static const struct
|
||||
"itivos.",
|
||||
#endif
|
||||
#endif
|
||||
"Busca dispositivos con Bluetooth para conectarse a ellos.",
|
||||
#ifdef _3DS
|
||||
"Indica el directorio de recursos de la pantalla inferior. El directorio debe contener el archivo"
|
||||
" \"bottom_menu.png\".",
|
||||
@@ -11520,7 +11518,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_es_blob_check[
|
||||
(sizeof(msg_hash_es_blob) == (272662u
|
||||
(sizeof(msg_hash_es_blob) == (272604u
|
||||
#ifdef ANDROID
|
||||
+ 329u
|
||||
#endif
|
||||
@@ -15013,7 +15011,6 @@ static const msg_hash_id_t msg_hash_es_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+1
-4
@@ -2206,7 +2206,6 @@ static const struct
|
||||
#ifdef HAVE_LAKKA
|
||||
char s_2bab34b2[29];
|
||||
#endif
|
||||
char s_27aef25c[41];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[85];
|
||||
char s_b4816da6[51];
|
||||
@@ -5797,7 +5796,6 @@ static const struct
|
||||
#ifdef HAVE_LAKKA
|
||||
"M\303\244\303\244rit\303\244 bluetoothin tila.",
|
||||
#endif
|
||||
"Etsi bluetooth laitteita ja yhdist\303\244 ne.",
|
||||
#ifdef _3DS
|
||||
"Alemman n\303\244yt\303\266n resurssien kansio. Kansioon on sis\303\244llytett\303\244v\303\244 "
|
||||
"\"bottom_menu.png\".",
|
||||
@@ -7580,7 +7578,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_fi_blob_check[
|
||||
(sizeof(msg_hash_fi_blob) == (123470u
|
||||
(sizeof(msg_hash_fi_blob) == (123429u
|
||||
#ifdef HAVE_LAKKA
|
||||
+ 257u
|
||||
#endif
|
||||
@@ -10111,7 +10109,6 @@ static const msg_hash_id_t msg_hash_fi_ids[] =
|
||||
#ifdef HAVE_LAKKA
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ENABLE,
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+1
-4
@@ -2801,7 +2801,6 @@ static const struct
|
||||
char s_aa08c6d6[77];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[59];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[86];
|
||||
char s_b4816da6[58];
|
||||
@@ -7941,7 +7940,6 @@ static const struct
|
||||
"D\303\251sactiver l'ERTM Bluetooth pour corriger l'appairage de certains appareils",
|
||||
#endif
|
||||
#endif
|
||||
"Rechercher des p\303\251riph\303\251riques Bluetooth et les connecter.",
|
||||
#ifdef _3DS
|
||||
"Dossier des ressources de l'\303\251cran du bas. Le dossier doit inclure \"bottom_menu.png\".",
|
||||
"Ajuster la couleur bleue de la police de l'\303\251cran du bas.",
|
||||
@@ -11027,7 +11025,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_fr_blob_check[
|
||||
(sizeof(msg_hash_fr_blob) == (257607u
|
||||
(sizeof(msg_hash_fr_blob) == (257548u
|
||||
#ifdef ANDROID
|
||||
+ 373u
|
||||
#endif
|
||||
@@ -14366,7 +14364,6 @@ static const msg_hash_id_t msg_hash_fr_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+39
-4
@@ -2546,6 +2546,10 @@ static const struct
|
||||
char s_bb929824[28];
|
||||
char s_fe2ec9bd[35];
|
||||
char s_1e3a9360[40];
|
||||
char s_5943aeda[30];
|
||||
char s_60b84450[31];
|
||||
char s_782f95e3[31];
|
||||
char s_5081d7d8[37];
|
||||
char s_5741c1d0[23];
|
||||
char s_a1a7717d[24];
|
||||
char s_e6ca3876[27];
|
||||
@@ -2975,7 +2979,6 @@ static const struct
|
||||
char s_aa08c6d6[73];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[61];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[90];
|
||||
char s_b4816da6[48];
|
||||
@@ -4221,6 +4224,10 @@ static const struct
|
||||
char s_72e21512[263];
|
||||
char s_9f6de46b[305];
|
||||
char s_26e66ece[276];
|
||||
char s_5f131848[172];
|
||||
char s_23227a3e[167];
|
||||
char s_87e08991[167];
|
||||
char s_56660806[173];
|
||||
char s_66f2b57e[54];
|
||||
char s_a776daeb[87];
|
||||
char s_88095324[87];
|
||||
@@ -4283,6 +4290,7 @@ static const struct
|
||||
char s_dc6f9d69[50];
|
||||
char s_417085f4[57];
|
||||
char s_1bcf70a7[185];
|
||||
char s_fbed99aa[217];
|
||||
char s_2e2ca41a[312];
|
||||
char s_f48b1fac[55];
|
||||
char s_f4ad1b37[100];
|
||||
@@ -7967,6 +7975,10 @@ static const struct
|
||||
"Leagan Amach Fo-phicteil\303\255n",
|
||||
"\303\232s\303\241id an Buaicphointe Taispe\303\241na",
|
||||
"D\303\255ch\303\263d\303\272 f\303\255se\303\241in tr\303\255 chrua-earra\303\255",
|
||||
"Imeall an Sc\303\241ile\303\241in Bun (%)",
|
||||
"Imill Chl\303\251 an Sc\303\241ile\303\241in (%)",
|
||||
"Imill Sc\303\241ile\303\241in ar Dheis (%)",
|
||||
"Imill an Sc\303\241ile\303\241in ag an mBarr (%)",
|
||||
"Leagan Amach F\303\255se\303\241in",
|
||||
"Uasmh\303\251id Moille Fr\303\241ma",
|
||||
"Uasta \303\215omh\303\241nna Swapchain",
|
||||
@@ -8556,7 +8568,6 @@ static const struct
|
||||
"\303\272",
|
||||
#endif
|
||||
#endif
|
||||
"Scan\303\241il le haghaidh gl\303\251asanna bluetooth agus ceangail iad.",
|
||||
#ifdef _3DS
|
||||
"Eolaire s\303\263cmhainn\303\255 bun an sc\303\241ile\303\241in. N\303\255 m\303\263r \"bottom_m"
|
||||
"enu.png\" a bheith san eolaire.",
|
||||
@@ -11099,6 +11110,18 @@ static const struct
|
||||
" Vulkan), rud a fh\303\241gann an CPU saor; m\303\241 roghna\303\255tear 'Off', d\303\251antar i"
|
||||
"ad a dh\303\255ch\303\263d\303\272 ar an CPU. Baineann s\303\251 seo le r\303\251amhamhairc a os"
|
||||
"cla\303\255tear feasta.",
|
||||
"F\303\241g sp\303\241s ag imeall \303\255ochtair an chluiche agus an roghchl\303\241ir, arna shl"
|
||||
"oinneadh mar ch\303\251atad\303\241n den fhuinneog ar iOS. M\303\241 shocra\303\255tear \303\251"
|
||||
" ar 0, n\303\255 bheidh aon imeall ann.",
|
||||
"F\303\241g sp\303\241s ag imeall cl\303\251 an chluiche agus an roghchl\303\241ir, arna shloinne"
|
||||
"adh mar ch\303\251atad\303\241n den fhuinneog ar iOS. M\303\241 shocra\303\255tear \303\251 ar 0"
|
||||
", n\303\255 bheidh aon imeall ann.",
|
||||
"F\303\241g sp\303\241s ag imeall deas an chluiche agus an roghchl\303\241ir, arna shloinneadh ma"
|
||||
"r ch\303\251atad\303\241n den fhuinneog ar iOS. M\303\241 shocra\303\255tear \303\251 ar 0, n"
|
||||
"\303\255 bheidh aon imeall ann.",
|
||||
"F\303\241g sp\303\241s ag imeall uachtarach an chluiche agus an roghchl\303\241ir, arna shloinne"
|
||||
"adh mar ch\303\251atad\303\241n den fhuinneog ar iOS. M\303\241 shocra\303\255tear \303\251 ar 0"
|
||||
", n\303\255 bheidh aon imeall ann.",
|
||||
"St\303\263r\303\241iltear Leagan Amach F\303\255se\303\241in san eolaire seo.",
|
||||
"Ins\303\255onn s\303\251 don tiom\303\241na\303\255 f\303\255se modh maol\303\241naithe sonraith"
|
||||
"e a \303\272s\303\241id go sainr\303\241ite.",
|
||||
@@ -11297,6 +11320,10 @@ static const struct
|
||||
"Coinn\303\255onn 'Ceangailte' an sc\303\241ile\303\241n seo in \303\251ineacht leis na cinn eile"
|
||||
". Cuireann 'Ar leithligh' \303\251 ar fhuinneog n\303\263 ar thaispe\303\241int d\303\241 chuid "
|
||||
"f\303\251in. F\303\241gann 'Faoi cheilt' ar l\303\241r \303\251.",
|
||||
"C\303\241 dt\303\251ann an sc\303\241ile\303\241n seo nuair a bh\303\255onn a fhuinneog f\303"
|
||||
"\251in aige? Roghna\303\255tear an dara taispe\303\241int go huathoibr\303\255och. Fanann an sc"
|
||||
"\303\241ile\303\241n ceangailte leis an taispe\303\241int a bhfuil RetroArch \303\241 thaispe"
|
||||
"\303\241int uirthi.",
|
||||
"D\303\272n an roghchl\303\241r agus bog sc\303\241ile\303\241in agus roghchl\303\241r na gcluas"
|
||||
"\303\241n leis na rialt\303\263ir\303\255: greama\303\255onn an greim, claonann an truicear, ath"
|
||||
"ra\303\255onn an bata achar agus m\303\251id, casann agus claonann bata na l\303\241imhe saora, "
|
||||
@@ -12404,7 +12431,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_ga_blob_check[
|
||||
(sizeof(msg_hash_ga_blob) == (273097u
|
||||
(sizeof(msg_hash_ga_blob) == (274061u
|
||||
#ifdef ANDROID
|
||||
+ 390u
|
||||
#endif
|
||||
@@ -15505,6 +15532,10 @@ static const msg_hash_id_t msg_hash_ga_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_HDR_SUBPIXEL_LAYOUT,
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_HDR_USE_DISPLAY_PEAK,
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_HW_DECODE,
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_IOS_MARGIN_BOTTOM,
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_IOS_MARGIN_LEFT,
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_IOS_MARGIN_RIGHT,
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_IOS_MARGIN_TOP,
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_LAYOUT_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_MAX_FRAME_LATENCY,
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES,
|
||||
@@ -15926,7 +15957,6 @@ static const msg_hash_id_t msg_hash_ga_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
@@ -17162,6 +17192,10 @@ static const msg_hash_id_t msg_hash_ga_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_HDR_SUBPIXEL_LAYOUT,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_HDR_USE_DISPLAY_PEAK,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_HW_DECODE,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_IOS_MARGIN_BOTTOM,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_IOS_MARGIN_LEFT,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_IOS_MARGIN_RIGHT,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_IOS_MARGIN_TOP,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_LAYOUT_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_MAX_FRAME_LATENCY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES,
|
||||
@@ -17224,6 +17258,7 @@ static const msg_hash_id_t msg_hash_ga_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_SCREEN_LAYOUT,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_SCREEN_SELECTED,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_SCREEN_WINDOW_MODE,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_SCREEN_WINDOW_MONITOR,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_SCREEN_XR_EDIT,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_SCREEN_XR_PITCH,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_SCREEN_XR_RESET,
|
||||
|
||||
+1
-4
@@ -2615,7 +2615,6 @@ static const struct
|
||||
char s_aa08c6d6[78];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[43];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[90];
|
||||
char s_450ca36f[50];
|
||||
@@ -7315,7 +7314,6 @@ static const struct
|
||||
"Desactiva o Bluetooth ERTM para corrixir a vinculaci\303\263n dalg\303\272ns dispositivos",
|
||||
#endif
|
||||
#endif
|
||||
"Busca dispositivos bluetooth e con\303\251ctaos.",
|
||||
#ifdef _3DS
|
||||
"Directorio de activos da pantalla inferior. O directorio debe inclu\303\255r \"bottom_menu.png\""
|
||||
".",
|
||||
@@ -9794,7 +9792,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_gl_blob_check[
|
||||
(sizeof(msg_hash_gl_blob) == (210917u
|
||||
(sizeof(msg_hash_gl_blob) == (210874u
|
||||
#ifdef ANDROID
|
||||
+ 365u
|
||||
#endif
|
||||
@@ -12849,7 +12847,6 @@ static const msg_hash_id_t msg_hash_gl_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_GREEN,
|
||||
|
||||
+1
-4
@@ -2455,7 +2455,6 @@ static const struct
|
||||
char s_aa08c6d6[83];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[53];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[104];
|
||||
char s_b4816da6[53];
|
||||
@@ -7023,7 +7022,6 @@ static const struct
|
||||
"\241ros\303\255t\303\241s\303\241n\303\241l",
|
||||
#endif
|
||||
#endif
|
||||
"Bluetooth eszk\303\266z\303\266k keres\303\251se \303\251s csatlakoztat\303\241sa.",
|
||||
#ifdef _3DS
|
||||
"Az als\303\263 k\303\251perny\305\221 be\303\251p\303\255tett m\303\251diaf\303\241jljainak k"
|
||||
"\303\266nyvt\303\241ra. A \"bottom_menu.png\" meg kell legyen itt.",
|
||||
@@ -9816,7 +9814,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_hu_blob_check[
|
||||
(sizeof(msg_hash_hu_blob) == (187189u
|
||||
(sizeof(msg_hash_hu_blob) == (187136u
|
||||
#ifdef ANDROID
|
||||
+ 316u
|
||||
#endif
|
||||
@@ -12699,7 +12697,6 @@ static const msg_hash_id_t msg_hash_hu_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+1
-4
@@ -2429,7 +2429,6 @@ static const struct
|
||||
char s_aa08c6d6[81];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[52];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[88];
|
||||
char s_b4816da6[55];
|
||||
@@ -6713,7 +6712,6 @@ static const struct
|
||||
"Disabilita l'ERTM Bluetooth per correggere l'accoppiamento di alcuni dispositivi",
|
||||
#endif
|
||||
#endif
|
||||
"Scansione per i dispositivi bluetooth e collegarli.",
|
||||
#ifdef _3DS
|
||||
"Directory asset nello schermo inferiore. La directory deve includere \"bottom_menu.png\".",
|
||||
"Regola il colore blu del font dello schermo inferiore.",
|
||||
@@ -8840,7 +8838,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_it_blob_check[
|
||||
(sizeof(msg_hash_it_blob) == (182312u
|
||||
(sizeof(msg_hash_it_blob) == (182260u
|
||||
#ifdef ANDROID
|
||||
+ 376u
|
||||
#endif
|
||||
@@ -11700,7 +11698,6 @@ static const msg_hash_id_t msg_hash_it_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+1
-6
@@ -2250,7 +2250,6 @@ static const struct
|
||||
char s_aa08c6d6[82];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[62];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[133];
|
||||
char s_b4816da6[55];
|
||||
@@ -8157,9 +8156,6 @@ static const struct
|
||||
"\263\343\202\260\343\202\222\344\277\256\346\255\243\343\201\227\343\201\276\343\201\231",
|
||||
#endif
|
||||
#endif
|
||||
"Bluetooth \343\203\207\343\203\220\343\202\244\343\202\271\343\202\222\343\202\271\343\202\255"
|
||||
"\343\203\243\343\203\263\343\201\227\343\201\246\346\216\245\347\266\232\343\201\227\343\201\276"
|
||||
"\343\201\231\343\200\202",
|
||||
#ifdef _3DS
|
||||
"\344\270\213\347\224\273\351\235\242\343\202\242\343\202\273\343\203\203\343\203\210\343\201\256"
|
||||
"\343\203\207\343\202\243\343\203\254\343\202\257\343\203\210\343\203\252\343\201\247\343\201\231"
|
||||
@@ -13932,7 +13928,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_ja_blob_check[
|
||||
(sizeof(msg_hash_ja_blob) == (199282u
|
||||
(sizeof(msg_hash_ja_blob) == (199220u
|
||||
#ifdef ANDROID
|
||||
+ 484u
|
||||
#endif
|
||||
@@ -16508,7 +16504,6 @@ static const msg_hash_id_t msg_hash_ja_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+1
-6
@@ -2808,7 +2808,6 @@ static const struct
|
||||
char s_aa08c6d6[121];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[53];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[122];
|
||||
char s_b4816da6[54];
|
||||
@@ -9660,9 +9659,6 @@ static const struct
|
||||
"\210\230 \354\236\210\354\212\265\353\213\210\353\213\244",
|
||||
#endif
|
||||
#endif
|
||||
"\353\270\224\353\243\250\355\210\254\354\212\244 \354\236\245\353\271\204\353\245\274 \352\262"
|
||||
"\200\354\203\211\355\225\230\352\263\240 \354\227\260\352\262\260\355\225\251\353\213\210\353"
|
||||
"\213\244.",
|
||||
#ifdef _3DS
|
||||
"\354\225\204\353\236\230 \355\231\224\353\251\264 \354\225\240\354\205\213 \353\224\224\353\240"
|
||||
"\211\355\206\240\353\246\254\354\236\205\353\213\210\353\213\244. \353\224\224\353\240\211\355"
|
||||
@@ -16223,7 +16219,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_ko_blob_check[
|
||||
(sizeof(msg_hash_ko_blob) == (228977u
|
||||
(sizeof(msg_hash_ko_blob) == (228924u
|
||||
#ifdef ANDROID
|
||||
+ 436u
|
||||
#endif
|
||||
@@ -19492,7 +19488,6 @@ static const msg_hash_id_t msg_hash_ko_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+1
-4
@@ -2381,7 +2381,6 @@ static const struct
|
||||
char s_aa08c6d6[78];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[45];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[76];
|
||||
char s_b4816da6[64];
|
||||
@@ -6581,7 +6580,6 @@ static const struct
|
||||
"Schakel Bluetooth ERTM uit om de koppeling van sommige apparaten te repareren",
|
||||
#endif
|
||||
#endif
|
||||
"Scan naar bluetooth apparaten en verbind ze.",
|
||||
#ifdef _3DS
|
||||
"De map met assets voor het onderste scherm moet \"bottom_menu.png\" bevatten.",
|
||||
"Pas de blauwe kleur van het lettertype onderaan het scherm aan.",
|
||||
@@ -8652,7 +8650,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_nl_blob_check[
|
||||
(sizeof(msg_hash_nl_blob) == (172428u
|
||||
(sizeof(msg_hash_nl_blob) == (172383u
|
||||
#ifdef ANDROID
|
||||
+ 375u
|
||||
#endif
|
||||
@@ -11466,7 +11464,6 @@ static const msg_hash_id_t msg_hash_nl_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+1
-4
@@ -924,7 +924,6 @@ static const struct
|
||||
char s_8a24406f[28];
|
||||
char s_5977d6d8[44];
|
||||
char s_f6adf4ee[39];
|
||||
char s_27aef25c[53];
|
||||
#ifdef _3DS
|
||||
char s_f441f728[37];
|
||||
#endif
|
||||
@@ -2208,7 +2207,6 @@ static const struct
|
||||
"Demp all lyd i stillemodus.",
|
||||
"Endre innstillinger for lyd inngang/utgang.",
|
||||
"Vis n\303\245v\303\246rende batteriniv\303\245 i menyen.",
|
||||
"Skann etter bluetooth-enheter og opprett tilkobling.",
|
||||
#ifdef _3DS
|
||||
"Juster skriftskalaen for bunnskjerm.",
|
||||
#endif
|
||||
@@ -2631,7 +2629,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_no_blob_check[
|
||||
(sizeof(msg_hash_no_blob) == (29330u
|
||||
(sizeof(msg_hash_no_blob) == (29277u
|
||||
#ifdef HAVE_LAKKA
|
||||
+ 178u
|
||||
#endif
|
||||
@@ -3685,7 +3683,6 @@ static const msg_hash_id_t msg_hash_no_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_AUDIO_RESPECT_SILENT_MODE,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_AUDIO_SETTINGS,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BATTERY_LEVEL_ENABLE,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_SCALE,
|
||||
#endif
|
||||
|
||||
+1
-4
@@ -2695,7 +2695,6 @@ static const struct
|
||||
char s_aa08c6d6[71];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[59];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[75];
|
||||
char s_b4816da6[53];
|
||||
@@ -7522,7 +7521,6 @@ static const struct
|
||||
"ze\305\204",
|
||||
#endif
|
||||
#endif
|
||||
"Skanuj w poszukiwaniu urz\304\205dze\305\204 bluetooth i pod\305\202\304\205cz je.",
|
||||
#ifdef _3DS
|
||||
"Katalog zasob\303\263w dolnego ekranu. Katalog musi zawiera\304\207 \"bottom_menu.png\".",
|
||||
"Dostosuj niebieski kolor czcionki na dolnym ekranie.",
|
||||
@@ -10225,7 +10223,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_pl_blob_check[
|
||||
(sizeof(msg_hash_pl_blob) == (199715u
|
||||
(sizeof(msg_hash_pl_blob) == (199656u
|
||||
#ifdef ANDROID
|
||||
+ 385u
|
||||
#endif
|
||||
@@ -13418,7 +13416,6 @@ static const msg_hash_id_t msg_hash_pl_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
@@ -2566,7 +2566,6 @@ static const struct
|
||||
char s_aa08c6d6[79];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[49];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[89];
|
||||
char s_b4816da6[45];
|
||||
@@ -7121,7 +7120,6 @@ static const struct
|
||||
"Desativa o ERTM do Bluetooth para corrigir o pareamento de alguns dispositivos",
|
||||
#endif
|
||||
#endif
|
||||
"Procura por dispositivos bluetooth e os conecta.",
|
||||
#ifdef _3DS
|
||||
"Diret\303\263rio dos recursos da tela inferior. O diret\303\263rio precisa ter um \"bottom_menu."
|
||||
"png\".",
|
||||
@@ -9528,7 +9526,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_pt_br_blob_check[
|
||||
(sizeof(msg_hash_pt_br_blob) == (193642u
|
||||
(sizeof(msg_hash_pt_br_blob) == (193593u
|
||||
#ifdef ANDROID
|
||||
+ 352u
|
||||
#endif
|
||||
@@ -12552,7 +12550,6 @@ static const msg_hash_id_t msg_hash_pt_br_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+1
-6
@@ -2576,7 +2576,6 @@ static const struct
|
||||
char s_aa08c6d6[133];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[67];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[119];
|
||||
char s_b4816da6[83];
|
||||
@@ -10865,9 +10864,6 @@ static const struct
|
||||
"\203\321\201\321\202\321\200\320\276\320\271\321\201\321\202\320\262\320\260\321\205.",
|
||||
#endif
|
||||
#endif
|
||||
"\320\237\320\276\320\270\321\201\320\272 \320\270 \320\277\320\276\320\264\320\272\320\273\321"
|
||||
"\216\321\207\320\265\320\275\320\270\320\265 bluetooth-\321\203\321\201\321\202\321\200\320\276"
|
||||
"\320\271\321\201\321\202\320\262.",
|
||||
#ifdef _3DS
|
||||
"\320\232\320\260\321\202\320\260\320\273\320\276\320\263 \321\200\320\265\321\201\321\203\321"
|
||||
"\200\321\201\320\276\320\262 \320\264\320\273\321\217 \320\275\320\270\320\266\320\275\320\265"
|
||||
@@ -19291,7 +19287,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_ru_blob_check[
|
||||
(sizeof(msg_hash_ru_blob) == (308352u
|
||||
(sizeof(msg_hash_ru_blob) == (308285u
|
||||
#ifdef ANDROID
|
||||
+ 547u
|
||||
#endif
|
||||
@@ -22293,7 +22289,6 @@ static const msg_hash_id_t msg_hash_ru_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+492
-4
File diff suppressed because it is too large.
Load diff
+39
-4
@@ -2423,6 +2423,10 @@ static const struct
|
||||
char s_bb929824[16];
|
||||
char s_fe2ec9bd[33];
|
||||
char s_1e3a9360[29];
|
||||
char s_5943aeda[32];
|
||||
char s_60b84450[35];
|
||||
char s_782f95e3[33];
|
||||
char s_5081d7d8[32];
|
||||
char s_5741c1d0[14];
|
||||
char s_a1a7717d[19];
|
||||
char s_e6ca3876[32];
|
||||
@@ -2828,7 +2832,6 @@ static const struct
|
||||
char s_aa08c6d6[69];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[45];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[88];
|
||||
char s_b4816da6[62];
|
||||
@@ -4067,6 +4070,10 @@ static const struct
|
||||
char s_72e21512[180];
|
||||
char s_9f6de46b[288];
|
||||
char s_26e66ece[211];
|
||||
char s_5f131848[122];
|
||||
char s_23227a3e[125];
|
||||
char s_87e08991[123];
|
||||
char s_56660806[122];
|
||||
char s_66f2b57e[38];
|
||||
char s_a776daeb[88];
|
||||
char s_88095324[88];
|
||||
@@ -4129,6 +4136,7 @@ static const struct
|
||||
char s_dc6f9d69[55];
|
||||
char s_417085f4[44];
|
||||
char s_1bcf70a7[142];
|
||||
char s_fbed99aa[170];
|
||||
char s_2e2ca41a[296];
|
||||
char s_f48b1fac[55];
|
||||
char s_f4ad1b37[84];
|
||||
@@ -4500,6 +4508,7 @@ static const struct
|
||||
char s_e9eb2822[45];
|
||||
char s_ed159cd6[16];
|
||||
char s_fa458d88[36];
|
||||
char s_f2f8ca3f[212];
|
||||
char s_7ccec78e[41];
|
||||
char s_308c47e4[40];
|
||||
char s_525bf430[20];
|
||||
@@ -7562,6 +7571,10 @@ static const struct
|
||||
"Subpixel-layout",
|
||||
"Anv\303\244nd bildsk\303\244rmens toppv\303\244rde",
|
||||
"Maskinvaruavkodning av video",
|
||||
"Undermarginal f\303\266r sk\303\244rmen (%)",
|
||||
"V\303\244nstermarginal f\303\266r sk\303\244rmen (%)",
|
||||
"H\303\266germarginal f\303\266r sk\303\244rmen (%)",
|
||||
"\303\226vermarginal f\303\266r sk\303\244rmen (%)",
|
||||
"Videolayouter",
|
||||
"Max bildrutelatens",
|
||||
"Maximalt antal swapchain-bilder",
|
||||
@@ -8094,7 +8107,6 @@ static const struct
|
||||
"Inaktivera Bluetooth ERTM f\303\266r att fixa parkoppling av vissa enheter",
|
||||
#endif
|
||||
#endif
|
||||
"S\303\266k efter bluetooth-enheter och anslut dem.",
|
||||
#ifdef _3DS
|
||||
"Nedre sk\303\244rmens katalog f\303\266r tillg\303\245ngar. Katalogen m\303\245ste inkludera \"b"
|
||||
"ottom_menu.png\".",
|
||||
@@ -10223,6 +10235,14 @@ static const struct
|
||||
"Avkoda videof\303\266rhandsvisningar p\303\245 GPU:n n\303\244r grafikdrivrutinen kan g\303\266r"
|
||||
"a det (H.264 med Vulkan), s\303\245 att CPU:n avlastas. \342\200\235Av\342\200\235 avkodar dem p"
|
||||
"\303\245 CPU:n. G\303\244ller f\303\266rhandsvisningar som \303\266ppnas fr\303\245n och med nu.",
|
||||
"L\303\244mna utrymme vid nederkanten av spelet och menyn, i procent av f\303\266nstret, p\303"
|
||||
"\245 iOS. 0 l\303\244gger inte till n\303\245gon marginal.",
|
||||
"L\303\244mna utrymme vid v\303\244nsterkanten av spelet och menyn, i procent av f\303\266nstret,"
|
||||
" p\303\245 iOS. 0 l\303\244gger inte till n\303\245gon marginal.",
|
||||
"L\303\244mna utrymme vid h\303\266gerkanten av spelet och menyn, i procent av f\303\266nstret, p"
|
||||
"\303\245 iOS. 0 l\303\244gger inte till n\303\245gon marginal.",
|
||||
"L\303\244mna utrymme vid \303\266verkanten av spelet och menyn, i procent av f\303\266nstret, p"
|
||||
"\303\245 iOS. 0 l\303\244gger inte till n\303\245gon marginal.",
|
||||
"Videolayouter lagras i denna katalog.",
|
||||
"S\303\244ger till videodrivrutinen att uttryckligen anv\303\244nda ett specificerat buffringsl"
|
||||
"\303\244ge.",
|
||||
@@ -10370,6 +10390,9 @@ static const struct
|
||||
"V\303\244lj den flytande sk\303\244rm som ska justeras.",
|
||||
"Kopplad beh\303\245ller sk\303\244rmen tillsammans med de andra. Separat visar den i ett eget f"
|
||||
"\303\266nster eller p\303\245 en egen bildsk\303\244rm. Dold utel\303\244mnar den.",
|
||||
"Var den h\303\244r sk\303\244rmen visas n\303\244r den har ett eget f\303\266nster. Auto v\303"
|
||||
"\244ljer en annan bildsk\303\244rm. P\303\245 den bildsk\303\244rm d\303\244r RetroArch k\303"
|
||||
"\266rs beh\303\245lls sk\303\244rmen i samma f\303\266nster.",
|
||||
"St\303\244ng menyn och flytta VR-headsetets sk\303\244rmar och meny med handkontrollerna: greppk"
|
||||
"nappen tar tag, avtryckaren vinklar, styrspaken \303\244ndrar avst\303\245nd och storlek, den fr"
|
||||
"ia handens styrspak vrider och vinklar, huvudknappen \303\245terst\303\244ller och V\303\244lj n"
|
||||
@@ -10910,6 +10933,9 @@ static const struct
|
||||
"Filen finns redan. Sparar till reservbuffert",
|
||||
"Filen hittas ej",
|
||||
"En eller flera firmwarefiler saknas",
|
||||
"Vissa av RetroArchs nedladdningsbara filer (menyresurser, handkontrollprofiler, k\303\244rninfor"
|
||||
"mation, databaser) saknas.H\303\244mta dem nu? Det kr\303\244ver en internetanslutning.De kan up"
|
||||
"pdateras senare med N\303\244tuppdateraren.",
|
||||
"Mappspecifika k\303\244rnalternativ hittades i",
|
||||
"Hittade automatiskt sparat tillst\303\245nd i",
|
||||
"Hittade skivetikett",
|
||||
@@ -11357,7 +11383,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_sv_blob_check[
|
||||
(sizeof(msg_hash_sv_blob) == (234595u
|
||||
(sizeof(msg_hash_sv_blob) == (235556u
|
||||
#ifdef ANDROID
|
||||
+ 361u
|
||||
#endif
|
||||
@@ -14344,6 +14370,10 @@ static const msg_hash_id_t msg_hash_sv_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_HDR_SUBPIXEL_LAYOUT,
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_HDR_USE_DISPLAY_PEAK,
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_HW_DECODE,
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_IOS_MARGIN_BOTTOM,
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_IOS_MARGIN_LEFT,
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_IOS_MARGIN_RIGHT,
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_IOS_MARGIN_TOP,
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_LAYOUT_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_MAX_FRAME_LATENCY,
|
||||
(msg_hash_id_t)MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES,
|
||||
@@ -14742,7 +14772,6 @@ static const msg_hash_id_t msg_hash_sv_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
@@ -15979,6 +16008,10 @@ static const msg_hash_id_t msg_hash_sv_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_HDR_SUBPIXEL_LAYOUT,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_HDR_USE_DISPLAY_PEAK,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_HW_DECODE,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_IOS_MARGIN_BOTTOM,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_IOS_MARGIN_LEFT,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_IOS_MARGIN_RIGHT,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_IOS_MARGIN_TOP,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_LAYOUT_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_MAX_FRAME_LATENCY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES,
|
||||
@@ -16041,6 +16074,7 @@ static const msg_hash_id_t msg_hash_sv_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_SCREEN_LAYOUT,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_SCREEN_SELECTED,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_SCREEN_WINDOW_MODE,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_SCREEN_WINDOW_MONITOR,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_SCREEN_XR_EDIT,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_SCREEN_XR_PITCH,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_VIDEO_SCREEN_XR_RESET,
|
||||
@@ -16407,6 +16441,7 @@ static const msg_hash_id_t msg_hash_sv_ids[] =
|
||||
(msg_hash_id_t)MSG_FILE_ALREADY_EXISTS_SAVING_TO_BACKUP_BUFFER,
|
||||
(msg_hash_id_t)MSG_FILE_NOT_FOUND,
|
||||
(msg_hash_id_t)MSG_FIRMWARE,
|
||||
(msg_hash_id_t)MSG_FIRST_RUN_DOWNLOAD_PROMPT,
|
||||
(msg_hash_id_t)MSG_FOLDER_SPECIFIC_CORE_OPTIONS_FOUND_AT,
|
||||
(msg_hash_id_t)MSG_FOUND_AUTO_SAVESTATE_IN,
|
||||
(msg_hash_id_t)MSG_FOUND_DISK_LABEL,
|
||||
|
||||
+1
-7
@@ -2605,7 +2605,6 @@ static const struct
|
||||
char s_aa08c6d6[164];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[94];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[209];
|
||||
char s_b4816da6[124];
|
||||
@@ -13115,10 +13114,6 @@ static const struct
|
||||
"\243\340\270\223\340\271\214",
|
||||
#endif
|
||||
#endif
|
||||
"\340\270\252\340\271\201\340\270\201\340\270\231\340\270\253\340\270\262\340\270\255\340\270\270"
|
||||
"\340\270\233\340\270\201\340\270\243\340\270\223\340\271\214\340\270\232\340\270\245\340\270\271"
|
||||
"\340\270\227\340\270\271\340\270\230\340\271\201\340\270\245\340\270\260\340\271\200\340\270\212"
|
||||
"\340\270\267\340\271\210\340\270\255\340\270\241\340\270\225\340\271\210\340\270\255",
|
||||
#ifdef _3DS
|
||||
"\340\271\204\340\270\224\340\271\200\340\270\243\340\270\201\340\270\227\340\270\255\340\270\243"
|
||||
"\340\270\265\340\270\227\340\270\243\340\270\261\340\270\236\340\270\242\340\270\262\340\270\201"
|
||||
@@ -26516,7 +26511,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_th_blob_check[
|
||||
(sizeof(msg_hash_th_blob) == (453709u
|
||||
(sizeof(msg_hash_th_blob) == (453615u
|
||||
#ifdef ANDROID
|
||||
+ 757u
|
||||
#endif
|
||||
@@ -29616,7 +29611,6 @@ static const msg_hash_id_t msg_hash_th_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+1
-4
@@ -2369,7 +2369,6 @@ static const struct
|
||||
char s_aa08c6d6[76];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[56];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[64];
|
||||
char s_b4816da6[46];
|
||||
@@ -6690,7 +6689,6 @@ static const struct
|
||||
"\237\304\261 b\304\261rak\304\261n",
|
||||
#endif
|
||||
#endif
|
||||
"Bluetooth cihazlar\304\261n\304\261 tarar ve ba\304\237lant\304\261 olu\305\237turur.",
|
||||
#ifdef _3DS
|
||||
"Alt ekran i\303\247erik dizini. Dizin 'bottom_menu.png' i\303\247ermelidir.",
|
||||
"Alt ekran yaz\304\261 tipi mavi rengini ayarlay\304\261n.",
|
||||
@@ -9195,7 +9193,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_tr_blob_check[
|
||||
(sizeof(msg_hash_tr_blob) == (169322u
|
||||
(sizeof(msg_hash_tr_blob) == (169266u
|
||||
#ifdef ANDROID
|
||||
+ 340u
|
||||
#endif
|
||||
@@ -11924,7 +11922,6 @@ static const msg_hash_id_t msg_hash_tr_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+1
-7
@@ -2755,7 +2755,6 @@ static const struct
|
||||
char s_aa08c6d6[103];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[86];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[127];
|
||||
char s_b4816da6[79];
|
||||
@@ -11993,10 +11992,6 @@ static const struct
|
||||
"\321\200\320\270\321\201\321\202\321\200\320\276\321\227\320\262",
|
||||
#endif
|
||||
#endif
|
||||
"\320\241\320\272\320\260\320\275\321\203\320\262\320\260\321\202\320\270 \320\264\320\273\321"
|
||||
"\217 Bluetooth \320\277\321\200\320\270\321\201\321\202\321\200\320\276\321\227\320\262 \321\202"
|
||||
"\320\260 \320\277\321\226\320\264'\321\224\320\264\320\275\320\260\321\202\320\270 \321\227\321"
|
||||
"\205.",
|
||||
#ifdef _3DS
|
||||
"\320\235\320\270\320\266\320\275\321\226\320\271 \320\265\320\272\321\200\320\260\320\275\320"
|
||||
"\275\320\270\320\271 \320\272\320\260\321\202\320\260\320\273\320\276\320\263 \320\260\320\272"
|
||||
@@ -21397,7 +21392,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_uk_blob_check[
|
||||
(sizeof(msg_hash_uk_blob) == (349435u
|
||||
(sizeof(msg_hash_uk_blob) == (349349u
|
||||
#ifdef ANDROID
|
||||
+ 610u
|
||||
#endif
|
||||
@@ -24567,7 +24562,6 @@ static const msg_hash_id_t msg_hash_uk_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+1
-5
@@ -3007,7 +3007,6 @@ static const struct
|
||||
char s_aa08c6d6[90];
|
||||
#endif
|
||||
#endif
|
||||
char s_27aef25c[51];
|
||||
#ifdef _3DS
|
||||
char s_2873cef1[91];
|
||||
char s_b4816da6[73];
|
||||
@@ -9570,8 +9569,6 @@ static const struct
|
||||
" b\341\273\213",
|
||||
#endif
|
||||
#endif
|
||||
"Qu\303\251t c\303\241c thi\341\272\277t b\341\273\213 Bluetooth v\303\240 k\341\272\277t n\341"
|
||||
"\273\221i.",
|
||||
#ifdef _3DS
|
||||
"Th\306\260 m\341\273\245c t\303\240i nguy\303\252n m\303\240n h\303\254nh d\306\260\341\273\233i"
|
||||
". Th\306\260 m\341\273\245c ph\341\272\243i bao g\341\273\223m \"bottom_menu.png\".",
|
||||
@@ -15672,7 +15669,7 @@ static const struct
|
||||
* compiler that pads this struct fails here instead of
|
||||
* misindexing at runtime. */
|
||||
typedef char msg_hash_vn_blob_check[
|
||||
(sizeof(msg_hash_vn_blob) == (312852u
|
||||
(sizeof(msg_hash_vn_blob) == (312801u
|
||||
#ifdef ANDROID
|
||||
+ 373u
|
||||
#endif
|
||||
@@ -19228,7 +19225,6 @@ static const msg_hash_id_t msg_hash_vn_ids[] =
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_ERTM_DISABLE,
|
||||
#endif
|
||||
#endif
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BLUETOOTH_SETTINGS,
|
||||
#ifdef _3DS
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_ASSETS_DIRECTORY,
|
||||
(msg_hash_id_t)MENU_ENUM_SUBLABEL_BOTTOM_FONT_COLOR_BLUE,
|
||||
|
||||
+2
-2
@@ -127,7 +127,7 @@
|
||||
#define LANGUAGE_PROGRESS_RUSSIAN_APPROVED 5
|
||||
|
||||
/* Slovak */
|
||||
#define LANGUAGE_PROGRESS_SLOVAK_TRANSLATED 95
|
||||
#define LANGUAGE_PROGRESS_SLOVAK_TRANSLATED 99
|
||||
#define LANGUAGE_PROGRESS_SLOVAK_APPROVED 0
|
||||
|
||||
/* Serbian (Latin) */
|
||||
@@ -159,7 +159,7 @@
|
||||
#define LANGUAGE_PROGRESS_VALENCIAN_APPROVED 0
|
||||
|
||||
/* Vietnamese */
|
||||
#define LANGUAGE_PROGRESS_VIETNAMESE_TRANSLATED 100
|
||||
#define LANGUAGE_PROGRESS_VIETNAMESE_TRANSLATED 99
|
||||
#define LANGUAGE_PROGRESS_VIETNAMESE_APPROVED 0
|
||||
|
||||
/* Chinese Simplified */
|
||||
|
||||
@@ -387,47 +387,11 @@ static INLINE float audio_mixer_bits_float(int i)
|
||||
#ifdef AUDIO_MIXER_HAS_STREAM
|
||||
/* ---- folding a multichannel stream to the stereo a voice mixes ------
|
||||
*
|
||||
* Vorbis and Opus both decode more than two channels now, and so do
|
||||
* WAV and FLAC - but they do not agree on what order the channels
|
||||
* arrive in, so there are two tables and the caller says which.
|
||||
*
|
||||
* Vorbis's order (spec 4.3.9), which Opus mapping family 1 adopts:
|
||||
*
|
||||
* 3 L C R 4 L R RL RR 5 L C R RL RR
|
||||
* 6 L C R RL RR LFE 7 L C R RL RR BC LFE
|
||||
* 8 L C R RL RR SL SR LFE
|
||||
*
|
||||
* Microsoft's, which WAV carries and FLAC's spec matches:
|
||||
*
|
||||
* 3 FL FR FC 4 FL FR BL BR 5 FL FR FC BL BR
|
||||
* 6 FL FR FC LFE BL BR 7 FL FR FC LFE BC SL SR
|
||||
* 8 FL FR FC LFE BL BR SL SR
|
||||
*
|
||||
* Folding one with the other's table is not a subtle error: on 5.1 it
|
||||
* sends front-right to both sides, front-centre to the right alone,
|
||||
* LFE into the mix and back-right nowhere.
|
||||
*
|
||||
* A stream voice mixes stereo, so anything wider is folded here - the
|
||||
* arms deliberately do no channel conversion, leaving it to the
|
||||
* mixer. Coefficients are the usual ITU-R BS.775 ones: centre and
|
||||
* surrounds enter both sides at -3 dB, a lone back centre at -6 dB
|
||||
* into each, and LFE is dropped, which is what it is for.
|
||||
*
|
||||
* Not normalised. Scaling by the coefficient sum would put 5.1
|
||||
* content 7.7 dB below the same material in a stereo file, which is a
|
||||
* surprising thing for a file's channel count to do to its volume;
|
||||
* the sum only reaches full scale when the channels are correlated,
|
||||
* and the mixer already clamps at its s16 and float boundaries. The
|
||||
* trade is level for the possibility of clipping on correlated
|
||||
* material, and it is the trade most players make.
|
||||
*
|
||||
* Q15 in int32 - unity is 32768, which does not fit the int16 the
|
||||
* coefficients would otherwise want, and wrapping it would invert a
|
||||
* channel rather than pass it. The s16 fold stays clear of float. */
|
||||
#define AMIX_DM_UNITY 32768
|
||||
#define AMIX_DM_M3DB 23170
|
||||
#define AMIX_DM_M6DB 16384
|
||||
|
||||
* A voice mixes stereo, so anything wider is folded here - the arms
|
||||
* deliberately do no channel conversion. The fold for each arm's
|
||||
* channel order is audio_transfer's (audio_transfer_fold_q15): Vorbis
|
||||
* and Opus in Vorbis order, the rest in WAVE order, WMA by its speaker
|
||||
* mask. Q15 in int32; the s16 fold stays clear of float. */
|
||||
static int16_t audio_mixer_sat_s16_64(int64_t v)
|
||||
{
|
||||
if (v > 32767)
|
||||
@@ -437,59 +401,6 @@ static int16_t audio_mixer_sat_s16_64(int64_t v)
|
||||
return (int16_t)v;
|
||||
}
|
||||
|
||||
/* [channels][input channel][0 = left, 1 = right] */
|
||||
static const int32_t audio_mixer_downmix_vorbis_q15[9][8][2] = {
|
||||
{ {0,0} }, /* unused */
|
||||
{ {0,0} }, /* mono */
|
||||
{ {0,0} }, /* stereo */
|
||||
/* 3: L C R */
|
||||
{ {AMIX_DM_UNITY,0}, {AMIX_DM_M3DB,AMIX_DM_M3DB}, {0,AMIX_DM_UNITY} },
|
||||
/* 4: L R RL RR */
|
||||
{ {AMIX_DM_UNITY,0}, {0,AMIX_DM_UNITY},
|
||||
{AMIX_DM_M3DB,0}, {0,AMIX_DM_M3DB} },
|
||||
/* 5: L C R RL RR */
|
||||
{ {AMIX_DM_UNITY,0}, {AMIX_DM_M3DB,AMIX_DM_M3DB}, {0,AMIX_DM_UNITY},
|
||||
{AMIX_DM_M3DB,0}, {0,AMIX_DM_M3DB} },
|
||||
/* 6: L C R RL RR LFE */
|
||||
{ {AMIX_DM_UNITY,0}, {AMIX_DM_M3DB,AMIX_DM_M3DB}, {0,AMIX_DM_UNITY},
|
||||
{AMIX_DM_M3DB,0}, {0,AMIX_DM_M3DB}, {0,0} },
|
||||
/* 7: L C R RL RR BC LFE */
|
||||
{ {AMIX_DM_UNITY,0}, {AMIX_DM_M3DB,AMIX_DM_M3DB}, {0,AMIX_DM_UNITY},
|
||||
{AMIX_DM_M3DB,0}, {0,AMIX_DM_M3DB},
|
||||
{AMIX_DM_M6DB,AMIX_DM_M6DB}, {0,0} },
|
||||
/* 8: L C R RL RR SL SR LFE */
|
||||
{ {AMIX_DM_UNITY,0}, {AMIX_DM_M3DB,AMIX_DM_M3DB}, {0,AMIX_DM_UNITY},
|
||||
{AMIX_DM_M3DB,0}, {0,AMIX_DM_M3DB},
|
||||
{AMIX_DM_M3DB,0}, {0,AMIX_DM_M3DB}, {0,0} }
|
||||
};
|
||||
|
||||
|
||||
/* Microsoft/FLAC order. */
|
||||
static const int32_t audio_mixer_downmix_wav_q15[9][8][2] = {
|
||||
{ {0,0} }, /* unused */
|
||||
{ {0,0} }, /* mono */
|
||||
{ {0,0} }, /* stereo */
|
||||
/* 3: FL FR FC */
|
||||
{ {AMIX_DM_UNITY,0}, {0,AMIX_DM_UNITY}, {AMIX_DM_M3DB,AMIX_DM_M3DB} },
|
||||
/* 4: FL FR BL BR */
|
||||
{ {AMIX_DM_UNITY,0}, {0,AMIX_DM_UNITY},
|
||||
{AMIX_DM_M3DB,0}, {0,AMIX_DM_M3DB} },
|
||||
/* 5: FL FR FC BL BR */
|
||||
{ {AMIX_DM_UNITY,0}, {0,AMIX_DM_UNITY}, {AMIX_DM_M3DB,AMIX_DM_M3DB},
|
||||
{AMIX_DM_M3DB,0}, {0,AMIX_DM_M3DB} },
|
||||
/* 6: FL FR FC LFE BL BR */
|
||||
{ {AMIX_DM_UNITY,0}, {0,AMIX_DM_UNITY}, {AMIX_DM_M3DB,AMIX_DM_M3DB},
|
||||
{0,0}, {AMIX_DM_M3DB,0}, {0,AMIX_DM_M3DB} },
|
||||
/* 7: FL FR FC LFE BC SL SR */
|
||||
{ {AMIX_DM_UNITY,0}, {0,AMIX_DM_UNITY}, {AMIX_DM_M3DB,AMIX_DM_M3DB},
|
||||
{0,0}, {AMIX_DM_M6DB,AMIX_DM_M6DB},
|
||||
{AMIX_DM_M3DB,0}, {0,AMIX_DM_M3DB} },
|
||||
/* 8: FL FR FC LFE BL BR SL SR */
|
||||
{ {AMIX_DM_UNITY,0}, {0,AMIX_DM_UNITY}, {AMIX_DM_M3DB,AMIX_DM_M3DB},
|
||||
{0,0}, {AMIX_DM_M3DB,0}, {0,AMIX_DM_M3DB},
|
||||
{AMIX_DM_M3DB,0}, {0,AMIX_DM_M3DB} }
|
||||
};
|
||||
|
||||
/* Which order an arm hands its channels over in. */
|
||||
static const int32_t (*audio_mixer_downmix_table(
|
||||
enum audio_type_enum type, unsigned ch, const audio_mixer_voice_t *voice))[2]
|
||||
@@ -498,15 +409,7 @@ static const int32_t (*audio_mixer_downmix_table(
|
||||
#ifdef HAVE_RWMA
|
||||
if (type == AUDIO_TYPE_WMA) return voice->types.stream.wma_matrix;
|
||||
#endif
|
||||
switch (type)
|
||||
{
|
||||
case AUDIO_TYPE_VORBIS:
|
||||
case AUDIO_TYPE_OPUS:
|
||||
return audio_mixer_downmix_vorbis_q15[ch];
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return audio_mixer_downmix_wav_q15[ch];
|
||||
return audio_transfer_fold_q15(type, ch);
|
||||
}
|
||||
|
||||
/* Frames a temp buffer of 'samples' holds at 'ch' channels: what a
|
||||
@@ -596,7 +499,7 @@ static float wav_sample_unit(const rwav_t *wav, const uint8_t *src,
|
||||
static void wav_fold_to_stereo(const rwav_t *wav, const uint8_t *src,
|
||||
float *dst, size_t frames)
|
||||
{
|
||||
const int32_t (*co)[2] = audio_mixer_downmix_wav_q15[wav->numchannels];
|
||||
const int32_t (*co)[2] = audio_transfer_fold_q15(AUDIO_TYPE_WAV, wav->numchannels);
|
||||
size_t i;
|
||||
for (i = 0; i < frames; i++)
|
||||
{
|
||||
@@ -674,7 +577,7 @@ static bool wav_to_float(const rwav_t* wav, const uint8_t* src,
|
||||
got = rwav_decode_s16(&h, src, 0, wav->numsamples, tmp);
|
||||
{
|
||||
const int32_t (*co)[2] =
|
||||
audio_mixer_downmix_wav_q15[wav->numchannels];
|
||||
audio_transfer_fold_q15(AUDIO_TYPE_WAV, wav->numchannels);
|
||||
unsigned c;
|
||||
for (i = 0; i < got; i++)
|
||||
{
|
||||
@@ -1017,7 +920,7 @@ static bool wav_to_s16(const rwav_t* wav, const uint8_t* src,
|
||||
got = rwav_decode_s16(&h, src, 0, wav->numsamples, tmp);
|
||||
{
|
||||
const int32_t (*co)[2] =
|
||||
audio_mixer_downmix_wav_q15[wav->numchannels];
|
||||
audio_transfer_fold_q15(AUDIO_TYPE_WAV, wav->numchannels);
|
||||
unsigned c;
|
||||
for (i = 0; i < got; i++)
|
||||
{
|
||||
@@ -1046,7 +949,7 @@ static bool wav_to_s16(const rwav_t* wav, const uint8_t* src,
|
||||
size_t i2;
|
||||
unsigned c;
|
||||
const int32_t (*co)[2] =
|
||||
audio_mixer_downmix_wav_q15[wav->numchannels];
|
||||
audio_transfer_fold_q15(AUDIO_TYPE_WAV, wav->numchannels);
|
||||
for (i2 = 0; i2 < wav->numsamples; i2++)
|
||||
{
|
||||
int64_t l = 0, r = 0;
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/* Copyright (C) 2010-2026 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (float_to_ulaw.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* G.711 mu-law: see audio/conversion/float_to_ulaw.h. */
|
||||
|
||||
#include <audio/conversion/float_to_ulaw.h>
|
||||
|
||||
/* The level code @i (0..127, magnitude) decodes to, 16-bit scale */
|
||||
static int ulaw_level(int i)
|
||||
{
|
||||
return ((((i & 15) << 3) + 0x84) << (i >> 4)) - 0x84;
|
||||
}
|
||||
|
||||
/* The code for magnitude @j (1..8192, 14-bit scale): the first whose
|
||||
* decision level - halfway to the next code's level, rounded - is above
|
||||
* it, or 127 past the last; seven steps of a binary search */
|
||||
static int ulaw_code(int j)
|
||||
{
|
||||
int lo = 0, hi = 127;
|
||||
while (lo < hi)
|
||||
{
|
||||
int mid = (lo + hi) >> 1;
|
||||
if (j < ((ulaw_level(mid) + ulaw_level(mid + 1) + 4) >> 3))
|
||||
hi = mid;
|
||||
else
|
||||
lo = mid + 1;
|
||||
}
|
||||
return lo;
|
||||
}
|
||||
|
||||
static uint8_t ulaw_from_s16(int s)
|
||||
{
|
||||
int idx = (s + 32768) >> 2; /* 0..16383, 8192 at zero */
|
||||
if (idx > 8192)
|
||||
return (uint8_t)(ulaw_code(idx - 8192) ^ 0xFF);
|
||||
if (idx == 8192)
|
||||
return 0xFF;
|
||||
return (uint8_t)(ulaw_code(8192 - idx) ^ 0x7F);
|
||||
}
|
||||
|
||||
void convert_s16_to_ulaw(uint8_t *out, const int16_t *in, size_t samples)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < samples; i++)
|
||||
out[i] = ulaw_from_s16(in[i]);
|
||||
}
|
||||
|
||||
void convert_float_to_ulaw(uint8_t *out, const float *in, size_t samples)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < samples; i++)
|
||||
{
|
||||
float f = in[i] * 32768.0f;
|
||||
int s;
|
||||
/* clipped, then rounded half away from zero */
|
||||
if (f >= 32767.0f)
|
||||
s = 32767;
|
||||
else if (f <= -32768.0f)
|
||||
s = -32768;
|
||||
else
|
||||
s = (int)(f < 0 ? f - 0.5f : f + 0.5f);
|
||||
out[i] = ulaw_from_s16(s);
|
||||
}
|
||||
}
|
||||
@@ -574,6 +574,117 @@ static void aes_x86_cbc_decrypt(const struct aes_ctx *ctx, uint8_t *iv,
|
||||
_mm_storeu_si128((__m128i*)iv, prev);
|
||||
}
|
||||
|
||||
/* XTS (IEEE 1619): the tweak is multiplied by alpha from one block to
|
||||
* the next. As a little-endian 128-bit number it is a shift left by
|
||||
* one, the bit out of the low half carried into the high one and the
|
||||
* one out of the top folded back in as 0x87. */
|
||||
AES_TARGET_X86
|
||||
static __m128i aes_x86_xts_next(__m128i t)
|
||||
{
|
||||
/* lane 0: the top bit, lane 1: the low half's top bit; times 0x87
|
||||
* and 1, which the carries being 0 or 1 make a multiply */
|
||||
const __m128i poly = _mm_set_epi32(0, 1, 0, 0x87);
|
||||
const __m128i carry = _mm_shuffle_epi32(_mm_srli_epi64(t, 63), 0x4e);
|
||||
return _mm_xor_si128(_mm_slli_epi64(t, 1), _mm_mul_epu32(carry, poly));
|
||||
}
|
||||
|
||||
/* XTS over whole blocks, eight in flight, from the encrypted tweak
|
||||
* @tweak; the round keys made once per call (through InvMixColumns to
|
||||
* decrypt). Each block's input is held in a register before its output
|
||||
* is stored, so @in and @out may alias. The tweak comes as bytes: a
|
||||
* vector argument would be loaded by the caller, which is built
|
||||
* without SSE on i686. */
|
||||
AES_TARGET_X86
|
||||
static void aes_x86_xts(const struct aes_ctx *ctx, const uint8_t *tweak,
|
||||
const uint8_t *in, uint8_t *out, size_t len, int decrypt)
|
||||
{
|
||||
__m128i k[15];
|
||||
__m128i t = _mm_loadu_si128((const __m128i*)tweak);
|
||||
unsigned r, nr = ctx->rounds;
|
||||
|
||||
if (decrypt)
|
||||
{
|
||||
k[0] = aes_x86_bswap32(_mm_loadu_si128((const __m128i*)(ctx->rk + 4 * nr)));
|
||||
k[nr] = aes_x86_bswap32(_mm_loadu_si128((const __m128i*)ctx->rk));
|
||||
for (r = 1; r < nr; r++)
|
||||
k[r] = _mm_aesimc_si128(aes_x86_bswap32(
|
||||
_mm_loadu_si128((const __m128i*)(ctx->rk + 4 * (nr - r)))));
|
||||
}
|
||||
else
|
||||
for (r = 0; r <= nr; r++)
|
||||
k[r] = aes_x86_bswap32(_mm_loadu_si128((const __m128i*)(ctx->rk + 4 * r)));
|
||||
|
||||
#define AES_X86_XTS_ROUNDS(op, oplast) \
|
||||
for (r = 1; r < nr; r++) \
|
||||
{ \
|
||||
const __m128i kr = k[r]; \
|
||||
b0 = op(b0, kr); b1 = op(b1, kr); b2 = op(b2, kr); b3 = op(b3, kr); \
|
||||
b4 = op(b4, kr); b5 = op(b5, kr); b6 = op(b6, kr); b7 = op(b7, kr); \
|
||||
} \
|
||||
b0 = oplast(b0, k[nr]); b1 = oplast(b1, k[nr]); \
|
||||
b2 = oplast(b2, k[nr]); b3 = oplast(b3, k[nr]); \
|
||||
b4 = oplast(b4, k[nr]); b5 = oplast(b5, k[nr]); \
|
||||
b6 = oplast(b6, k[nr]); b7 = oplast(b7, k[nr]);
|
||||
while (len >= 128)
|
||||
{
|
||||
const __m128i t0 = t;
|
||||
const __m128i t1 = aes_x86_xts_next(t0);
|
||||
const __m128i t2 = aes_x86_xts_next(t1);
|
||||
const __m128i t3 = aes_x86_xts_next(t2);
|
||||
const __m128i t4 = aes_x86_xts_next(t3);
|
||||
const __m128i t5 = aes_x86_xts_next(t4);
|
||||
const __m128i t6 = aes_x86_xts_next(t5);
|
||||
const __m128i t7 = aes_x86_xts_next(t6);
|
||||
__m128i b0 = _mm_xor_si128(_mm_xor_si128(_mm_loadu_si128((const __m128i*)(in)), t0), k[0]);
|
||||
__m128i b1 = _mm_xor_si128(_mm_xor_si128(_mm_loadu_si128((const __m128i*)(in + 16)), t1), k[0]);
|
||||
__m128i b2 = _mm_xor_si128(_mm_xor_si128(_mm_loadu_si128((const __m128i*)(in + 32)), t2), k[0]);
|
||||
__m128i b3 = _mm_xor_si128(_mm_xor_si128(_mm_loadu_si128((const __m128i*)(in + 48)), t3), k[0]);
|
||||
__m128i b4 = _mm_xor_si128(_mm_xor_si128(_mm_loadu_si128((const __m128i*)(in + 64)), t4), k[0]);
|
||||
__m128i b5 = _mm_xor_si128(_mm_xor_si128(_mm_loadu_si128((const __m128i*)(in + 80)), t5), k[0]);
|
||||
__m128i b6 = _mm_xor_si128(_mm_xor_si128(_mm_loadu_si128((const __m128i*)(in + 96)), t6), k[0]);
|
||||
__m128i b7 = _mm_xor_si128(_mm_xor_si128(_mm_loadu_si128((const __m128i*)(in + 112)), t7), k[0]);
|
||||
if (decrypt)
|
||||
{
|
||||
AES_X86_XTS_ROUNDS(_mm_aesdec_si128, _mm_aesdeclast_si128)
|
||||
}
|
||||
else
|
||||
{
|
||||
AES_X86_XTS_ROUNDS(_mm_aesenc_si128, _mm_aesenclast_si128)
|
||||
}
|
||||
_mm_storeu_si128((__m128i*)(out), _mm_xor_si128(b0, t0));
|
||||
_mm_storeu_si128((__m128i*)(out + 16), _mm_xor_si128(b1, t1));
|
||||
_mm_storeu_si128((__m128i*)(out + 32), _mm_xor_si128(b2, t2));
|
||||
_mm_storeu_si128((__m128i*)(out + 48), _mm_xor_si128(b3, t3));
|
||||
_mm_storeu_si128((__m128i*)(out + 64), _mm_xor_si128(b4, t4));
|
||||
_mm_storeu_si128((__m128i*)(out + 80), _mm_xor_si128(b5, t5));
|
||||
_mm_storeu_si128((__m128i*)(out + 96), _mm_xor_si128(b6, t6));
|
||||
_mm_storeu_si128((__m128i*)(out + 112), _mm_xor_si128(b7, t7));
|
||||
t = aes_x86_xts_next(t7);
|
||||
in += 128;
|
||||
out += 128;
|
||||
len -= 128;
|
||||
}
|
||||
#undef AES_X86_XTS_ROUNDS
|
||||
for (; len >= 16; in += 16, out += 16, len -= 16)
|
||||
{
|
||||
__m128i b = _mm_xor_si128(_mm_xor_si128(_mm_loadu_si128((const __m128i*)in), t), k[0]);
|
||||
if (decrypt)
|
||||
{
|
||||
for (r = 1; r < nr; r++)
|
||||
b = _mm_aesdec_si128(b, k[r]);
|
||||
b = _mm_aesdeclast_si128(b, k[nr]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (r = 1; r < nr; r++)
|
||||
b = _mm_aesenc_si128(b, k[r]);
|
||||
b = _mm_aesenclast_si128(b, k[nr]);
|
||||
}
|
||||
_mm_storeu_si128((__m128i*)out, _mm_xor_si128(b, t));
|
||||
t = aes_x86_xts_next(t);
|
||||
}
|
||||
}
|
||||
|
||||
/* CTR with eight blocks in flight so the AES unit's latency is hidden,
|
||||
* the round keys loaded and byte-swapped once per call rather than once
|
||||
* per round. The counter block is kept byte-reversed, where its 32-bit
|
||||
@@ -967,6 +1078,73 @@ static void aes_arm_cbc_decrypt(const struct aes_ctx *ctx, uint8_t *iv,
|
||||
vst1q_u8(iv, prev);
|
||||
}
|
||||
|
||||
/* XTS's tweak times alpha, as the x86 form above: each half shifted
|
||||
* left, the carries exchanged and the top one folded in as 0x87. */
|
||||
AES_TARGET_ARM
|
||||
static uint8x16_t aes_arm_xts_next(uint8x16_t t)
|
||||
{
|
||||
static const uint64_t poly_v[2] = { 0x87, 1 };
|
||||
const uint64x2_t v = vreinterpretq_u64_u8(t);
|
||||
const uint64x2_t top = vshrq_n_u64(v, 63);
|
||||
const uint64x2_t carry = vextq_u64(top, top, 1);
|
||||
const uint64x2_t mask = vsubq_u64(vdupq_n_u64(0), carry);
|
||||
return vreinterpretq_u8_u64(veorq_u64(vshlq_n_u64(v, 1),
|
||||
vandq_u64(mask, vld1q_u64(poly_v))));
|
||||
}
|
||||
|
||||
/* XTS over whole blocks, eight in flight, the round keys loaded once.
|
||||
* Decrypting is the CBC decryption's AESD chain, encrypting the CTR's
|
||||
* AESE chain; the tweak goes in before the first round key and out
|
||||
* after the last. */
|
||||
AES_TARGET_ARM
|
||||
static void aes_arm_xts(const struct aes_ctx *ctx, uint8x16_t t,
|
||||
const uint8_t *in, uint8_t *out, size_t len, int decrypt)
|
||||
{
|
||||
uint8x16_t k[15];
|
||||
unsigned r, nr = ctx->rounds;
|
||||
|
||||
for (r = 0; r <= nr; r++)
|
||||
k[r] = aes_arm_rk(ctx, r);
|
||||
if (decrypt)
|
||||
for (r = 1; r < nr; r++)
|
||||
k[r] = vaesimcq_u8(k[r]);
|
||||
|
||||
while (len >= 16)
|
||||
{
|
||||
uint8x16_t tw[8], b[8];
|
||||
unsigned i, n = len >= 128 ? 8 : 1;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
tw[i] = t;
|
||||
b[i] = veorq_u8(vld1q_u8(in + 16 * i), t);
|
||||
t = aes_arm_xts_next(t);
|
||||
}
|
||||
if (decrypt)
|
||||
{
|
||||
for (i = 0; i < n; i++)
|
||||
b[i] = vaesdq_u8(b[i], k[nr]);
|
||||
for (r = nr - 1; r > 0; r--)
|
||||
for (i = 0; i < n; i++)
|
||||
b[i] = vaesdq_u8(vaesimcq_u8(b[i]), k[r]);
|
||||
for (i = 0; i < n; i++)
|
||||
b[i] = veorq_u8(b[i], k[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (r = 0; r + 1 < nr; r++)
|
||||
for (i = 0; i < n; i++)
|
||||
b[i] = vaesmcq_u8(vaeseq_u8(b[i], k[r]));
|
||||
for (i = 0; i < n; i++)
|
||||
b[i] = veorq_u8(vaeseq_u8(b[i], k[nr - 1]), k[nr]);
|
||||
}
|
||||
for (i = 0; i < n; i++)
|
||||
vst1q_u8(out + 16 * i, veorq_u8(b[i], tw[i]));
|
||||
in += 16 * n;
|
||||
out += 16 * n;
|
||||
len -= 16 * n;
|
||||
}
|
||||
}
|
||||
|
||||
/* CTR with eight blocks in flight, the round keys loaded once per
|
||||
* call. The counter block is kept byte-reversed within each 32-bit
|
||||
* lane, where its big-endian counter is lane 3 as a native word: one
|
||||
@@ -1441,6 +1619,42 @@ void aes_ctr_crypt(const struct aes_ctx *ctx, uint8_t *counter,
|
||||
crypto_memzero(ks, sizeof(ks));
|
||||
}
|
||||
|
||||
/* The register holds ciphertext: encrypting it gives the next
|
||||
* keystream block, and each ciphertext octet goes back into it. */
|
||||
void aes_cfb128_encrypt(const struct aes_ctx *ctx, uint8_t *iv,
|
||||
unsigned *num, const uint8_t *in, uint8_t *out, size_t len)
|
||||
{
|
||||
unsigned n = *num & 15;
|
||||
while (len)
|
||||
{
|
||||
if (!n)
|
||||
aes_encrypt_block(ctx, iv, iv);
|
||||
iv[n] ^= *in++;
|
||||
*out++ = iv[n];
|
||||
n = (n + 1) & 15;
|
||||
len--;
|
||||
}
|
||||
*num = n;
|
||||
}
|
||||
|
||||
void aes_cfb128_decrypt(const struct aes_ctx *ctx, uint8_t *iv,
|
||||
unsigned *num, const uint8_t *in, uint8_t *out, size_t len)
|
||||
{
|
||||
unsigned n = *num & 15;
|
||||
while (len)
|
||||
{
|
||||
uint8_t c;
|
||||
if (!n)
|
||||
aes_encrypt_block(ctx, iv, iv);
|
||||
c = *in++;
|
||||
*out++ = (uint8_t)(iv[n] ^ c);
|
||||
iv[n] = c;
|
||||
n = (n + 1) & 15;
|
||||
len--;
|
||||
}
|
||||
*num = n;
|
||||
}
|
||||
|
||||
void aes_cbc_encrypt(const struct aes_ctx *ctx, uint8_t *iv,
|
||||
const uint8_t *in, uint8_t *out, size_t len)
|
||||
{
|
||||
@@ -1515,6 +1729,70 @@ void aes_cbc_decrypt(const struct aes_ctx *ctx, uint8_t *iv,
|
||||
memcpy(iv, prev, 16);
|
||||
}
|
||||
|
||||
/* The tweak times alpha in GF(2^128), as a little-endian number: a
|
||||
* shift left, the bit out of the top folded back in as 0x87. */
|
||||
static void aes_xts_next(uint8_t *t)
|
||||
{
|
||||
unsigned i;
|
||||
uint8_t carry = 0;
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
uint8_t next = t[i] >> 7;
|
||||
t[i] = (uint8_t)((t[i] << 1) | carry);
|
||||
carry = next;
|
||||
}
|
||||
t[0] ^= (uint8_t)(0x87 & (0 - carry));
|
||||
}
|
||||
|
||||
static void aes_xts(const struct aes_ctx *data_key,
|
||||
const struct aes_ctx *tweak_key, const uint8_t *tweak,
|
||||
const uint8_t *in, uint8_t *out, size_t len, int decrypt)
|
||||
{
|
||||
uint8_t t[16], b[16], o[16];
|
||||
unsigned i;
|
||||
|
||||
aes_encrypt_block(tweak_key, tweak, t);
|
||||
#if defined(AES_HAVE_X86_PATH)
|
||||
if (aes_x86_available())
|
||||
{
|
||||
aes_x86_xts(data_key, t, in, out, len, decrypt);
|
||||
return;
|
||||
}
|
||||
#elif defined(AES_HAVE_ARM_PATH)
|
||||
if (aes_arm_available())
|
||||
{
|
||||
aes_arm_xts(data_key, vld1q_u8(t), in, out, len, decrypt);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
for (; len >= 16; in += 16, out += 16, len -= 16)
|
||||
{
|
||||
for (i = 0; i < 16; i++)
|
||||
b[i] = in[i] ^ t[i];
|
||||
if (decrypt)
|
||||
aes_decrypt_block_c(data_key, b, o);
|
||||
else
|
||||
aes_encrypt_block_c(data_key, b, o);
|
||||
for (i = 0; i < 16; i++)
|
||||
out[i] = o[i] ^ t[i];
|
||||
aes_xts_next(t);
|
||||
}
|
||||
}
|
||||
|
||||
void aes_xts_encrypt(const struct aes_ctx *data_key,
|
||||
const struct aes_ctx *tweak_key, const uint8_t *tweak,
|
||||
const uint8_t *in, uint8_t *out, size_t len)
|
||||
{
|
||||
aes_xts(data_key, tweak_key, tweak, in, out, len, 0);
|
||||
}
|
||||
|
||||
void aes_xts_decrypt(const struct aes_ctx *data_key,
|
||||
const struct aes_ctx *tweak_key, const uint8_t *tweak,
|
||||
const uint8_t *in, uint8_t *out, size_t len)
|
||||
{
|
||||
aes_xts(data_key, tweak_key, tweak, in, out, len, 1);
|
||||
}
|
||||
|
||||
/* Double in GF(2^128) with the CMAC polynomial. */
|
||||
static void aes_cmac_dbl(uint8_t *b)
|
||||
{
|
||||
|
||||
@@ -407,6 +407,11 @@ static uint32_t rd_adler32_update(uint32_t adler,
|
||||
return rd_adler32_on(adler, buf, len, 16);
|
||||
}
|
||||
|
||||
uint32_t encoding_adler32(uint32_t adler, const uint8_t *buf, size_t len)
|
||||
{
|
||||
return rd_adler32_update(adler, buf, len);
|
||||
}
|
||||
|
||||
/* Test entry point for tools/encodings/adler32_test.c: the kernel above is
|
||||
* static, and driving it only through rinflate/rdeflate would exercise
|
||||
* whatever lengths and alignments a stream happens to produce rather than
|
||||
@@ -2220,6 +2225,7 @@ struct rdeflate
|
||||
uint32_t crc; /* gzip: running crc32 of the input */
|
||||
uint32_t total_in; /* gzip: mod 2^32, for ISIZE */
|
||||
int final_in; /* caller signalled end of input */
|
||||
int flush_req; /* sync flush asked for: 1 pending, 2 marker out */
|
||||
int done;
|
||||
int error;
|
||||
|
||||
@@ -2944,6 +2950,14 @@ void rdeflate_finish(void *data)
|
||||
s->final_in = 1;
|
||||
}
|
||||
|
||||
/* write out everything taken so far, ending on a byte boundary */
|
||||
void rdeflate_flush(void *data)
|
||||
{
|
||||
struct rdeflate *s = (struct rdeflate*)data;
|
||||
if (!s->flush_req)
|
||||
s->flush_req = 1;
|
||||
}
|
||||
|
||||
/* ------- the parser: consume win[block_start..win_len) into symbols ------- */
|
||||
/* Fills the symbol buffer using greedy/lazy matching. Leaves s->pos at the
|
||||
* first unprocessed byte. Stops early if the symbol buffer is near full.
|
||||
@@ -3141,8 +3155,10 @@ static void rd_parse(struct rdeflate *s)
|
||||
s->prev_lit = prev_lit;
|
||||
}
|
||||
|
||||
/* flush a deferred match/literal at true end of input */
|
||||
if (s->final_in && s->pos >= end && s->have_prev
|
||||
/* flush a deferred match/literal at true end of input, or at a sync
|
||||
* flush once all the input given so far is in */
|
||||
if ((s->final_in || (s->flush_req && s->in_pos >= s->in_size))
|
||||
&& s->pos >= end && s->have_prev
|
||||
&& s->nsyms < RD_BLOCK_SYMS - 2)
|
||||
{
|
||||
s->have_prev = 0;
|
||||
@@ -3886,6 +3902,33 @@ int rdeflate_process(void *data, size_t *read, size_t *wrote)
|
||||
block_ready = 1;
|
||||
is_final = 1;
|
||||
}
|
||||
/* sync flush: once all the input given is parsed, the pending
|
||||
* symbols go out as a block, then an empty stored block ends
|
||||
* the output on a byte boundary (zlib's Z_SYNC_FLUSH). The
|
||||
* window is kept, so matches still reach across it. */
|
||||
if (!block_ready && s->flush_req && !s->final_in
|
||||
&& s->in_pos >= s->in_size && s->pos >= s->win_len
|
||||
&& !s->have_prev)
|
||||
{
|
||||
if (s->nsyms)
|
||||
block_ready = 1;
|
||||
else
|
||||
{
|
||||
if (s->flush_req == 1)
|
||||
{
|
||||
rd_putbits(s, 0, 3); /* BFINAL=0, BTYPE=00 */
|
||||
if (s->bitcnt & 7)
|
||||
rd_putbits(s, 0, 8 - (s->bitcnt & 7));
|
||||
rd_putbits(s, 0x0000, 16);
|
||||
rd_putbits(s, 0xffff, 16);
|
||||
s->flush_req = 2;
|
||||
}
|
||||
if (!rd_flush_bytes(s))
|
||||
goto suspend;
|
||||
s->flush_req = 0;
|
||||
goto suspend;
|
||||
}
|
||||
}
|
||||
if (!block_ready) /* need more input */
|
||||
goto suspend;
|
||||
s->block_final = is_final;
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
/* Copyright (C) 2010-2026 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (encoding_shiftjis.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <encodings/shiftjis.h>
|
||||
|
||||
#include "encoding_shiftjis_tables.h"
|
||||
|
||||
/* The row of sjis_decode for lead octet @b, or -1 */
|
||||
static int sjis_row(unsigned b)
|
||||
{
|
||||
if (b >= 0x81 && b <= 0x9F)
|
||||
return (int)(b - 0x81);
|
||||
if (b >= 0xE0 && b <= 0xEF)
|
||||
return (int)(b - 0xE0 + 31);
|
||||
if (b >= 0xFA && b <= 0xFC)
|
||||
return (int)(b - 0xFA + 47);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Puts @cp at @out + *pos as UTF-8 if it fits in @cap octets */
|
||||
static int sjis_put_utf8(char *out, size_t cap, size_t *pos, uint32_t cp)
|
||||
{
|
||||
size_t n = cp < 0x80 ? 1 : cp < 0x800 ? 2 : 3;
|
||||
char *p = out + *pos;
|
||||
if (cap - *pos < n)
|
||||
return 0;
|
||||
if (n == 1)
|
||||
p[0] = (char)cp;
|
||||
else if (n == 2)
|
||||
{
|
||||
p[0] = (char)(0xC0 | (cp >> 6));
|
||||
p[1] = (char)(0x80 | (cp & 0x3F));
|
||||
}
|
||||
else
|
||||
{
|
||||
p[0] = (char)(0xE0 | (cp >> 12));
|
||||
p[1] = (char)(0x80 | ((cp >> 6) & 0x3F));
|
||||
p[2] = (char)(0x80 | (cp & 0x3F));
|
||||
}
|
||||
*pos += n;
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t sjis_to_utf8(char *out, size_t out_size, const char *in, size_t in_len)
|
||||
{
|
||||
const unsigned char *s = (const unsigned char*)in;
|
||||
size_t i = 0, pos = 0;
|
||||
|
||||
if (!out_size)
|
||||
return 0;
|
||||
while (i < in_len)
|
||||
{
|
||||
unsigned b = s[i];
|
||||
uint32_t cp;
|
||||
int row;
|
||||
if (b < 0x80)
|
||||
{
|
||||
cp = b;
|
||||
i++;
|
||||
}
|
||||
else if (b >= 0xA1 && b <= 0xDF)
|
||||
{
|
||||
/* half-width katakana */
|
||||
cp = 0xFF61 + (b - 0xA1);
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned t;
|
||||
if ((row = sjis_row(b)) < 0 || i + 1 >= in_len)
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
t = s[i + 1];
|
||||
if (t < 0x40 || t > 0xFC || !(cp = sjis_decode[row][t - 0x40]))
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
if (!sjis_put_utf8(out, out_size - 1, &pos, cp))
|
||||
break;
|
||||
}
|
||||
out[pos] = '\0';
|
||||
return pos;
|
||||
}
|
||||
|
||||
/* The two-octet code for @cp, or 0 */
|
||||
static unsigned sjis_lookup(uint32_t cp)
|
||||
{
|
||||
size_t lo = 0, hi = SJIS_ENCODE_COUNT;
|
||||
while (lo < hi)
|
||||
{
|
||||
size_t mid = lo + (hi - lo) / 2;
|
||||
if (sjis_encode[mid][0] < cp)
|
||||
lo = mid + 1;
|
||||
else
|
||||
hi = mid;
|
||||
}
|
||||
return lo < SJIS_ENCODE_COUNT && sjis_encode[lo][0] == cp ? sjis_encode[lo][1] : 0;
|
||||
}
|
||||
|
||||
/* The code point UTF-8 starts at @s (@len octets left), its length at
|
||||
* @n; 0 at @n where the octet starts no valid character */
|
||||
static uint32_t sjis_utf8_next(const unsigned char *s, size_t len, size_t *n)
|
||||
{
|
||||
unsigned b = s[0];
|
||||
uint32_t cp, min;
|
||||
size_t k, more;
|
||||
|
||||
*n = 0;
|
||||
if (b < 0x80)
|
||||
{
|
||||
*n = 1;
|
||||
return b;
|
||||
}
|
||||
if (b >= 0xC2 && b <= 0xDF)
|
||||
{
|
||||
more = 1;
|
||||
cp = b & 0x1F;
|
||||
min = 0x80;
|
||||
}
|
||||
else if (b >= 0xE0 && b <= 0xEF)
|
||||
{
|
||||
more = 2;
|
||||
cp = b & 0x0F;
|
||||
min = 0x800;
|
||||
}
|
||||
else if (b >= 0xF0 && b <= 0xF4)
|
||||
{
|
||||
more = 3;
|
||||
cp = b & 0x07;
|
||||
min = 0x10000;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
if (len <= more)
|
||||
return 0;
|
||||
for (k = 1; k <= more; k++)
|
||||
{
|
||||
if ((s[k] & 0xC0) != 0x80)
|
||||
return 0;
|
||||
cp = (cp << 6) | (s[k] & 0x3F);
|
||||
}
|
||||
if (cp < min || cp > 0x10FFFF || (cp >= 0xD800 && cp <= 0xDFFF))
|
||||
return 0;
|
||||
*n = more + 1;
|
||||
return cp;
|
||||
}
|
||||
|
||||
size_t utf8_to_sjis(char *out, size_t out_size, const char *in, size_t in_len)
|
||||
{
|
||||
const unsigned char *s = (const unsigned char*)in;
|
||||
size_t i = 0, pos = 0;
|
||||
|
||||
if (!out_size)
|
||||
return 0;
|
||||
while (i < in_len)
|
||||
{
|
||||
size_t n;
|
||||
uint32_t cp = sjis_utf8_next(s + i, in_len - i, &n);
|
||||
unsigned code;
|
||||
if (!n)
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
i += n;
|
||||
if (cp < 0x80)
|
||||
code = cp;
|
||||
else if (cp >= 0xFF61 && cp <= 0xFF9F)
|
||||
code = 0xA1 + (cp - 0xFF61);
|
||||
else if (!(code = sjis_lookup(cp)))
|
||||
continue;
|
||||
if (code > 0xFF)
|
||||
{
|
||||
if (out_size - 1 - pos < 2)
|
||||
break;
|
||||
out[pos++] = (char)(code >> 8);
|
||||
out[pos++] = (char)(code & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (out_size - 1 - pos < 1)
|
||||
break;
|
||||
out[pos++] = (char)code;
|
||||
}
|
||||
}
|
||||
out[pos] = '\0';
|
||||
return pos;
|
||||
}
|
||||
|
||||
/* Code page 1252's 0x80-0x9F; 0 where it has nothing */
|
||||
static const uint16_t cp1252_high[32] = {
|
||||
0x20AC, 0, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
|
||||
0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0, 0x017D, 0,
|
||||
0, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
|
||||
0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0, 0x017E, 0x0178
|
||||
};
|
||||
|
||||
size_t cp1252_to_utf8(char *out, size_t out_size, const char *in, size_t in_len)
|
||||
{
|
||||
const unsigned char *s = (const unsigned char*)in;
|
||||
size_t i, pos = 0;
|
||||
|
||||
if (!out_size)
|
||||
return 0;
|
||||
for (i = 0; i < in_len; i++)
|
||||
{
|
||||
uint32_t cp = s[i];
|
||||
if (cp >= 0x80 && cp <= 0x9F && !(cp = cp1252_high[cp - 0x80]))
|
||||
continue;
|
||||
if (!sjis_put_utf8(out, out_size - 1, &pos, cp))
|
||||
break;
|
||||
}
|
||||
out[pos] = '\0';
|
||||
return pos;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,185 @@
|
||||
/* Copyright (C) 2010-2026 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (encoding_xxh32.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#if defined(_MSC_VER)
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include <retro_inline.h>
|
||||
#include <retro_endianness.h>
|
||||
#include <encodings/xxh32.h>
|
||||
|
||||
#define XXH32_P1 0x9E3779B1U
|
||||
#define XXH32_P2 0x85EBCA77U
|
||||
#define XXH32_P3 0xC2B2AE3DU
|
||||
#define XXH32_P4 0x27D4EB2FU
|
||||
#define XXH32_P5 0x165667B1U
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define XXH32_ROTL(x, r) _rotl((x), (r))
|
||||
#else
|
||||
#define XXH32_ROTL(x, r) (((x) << (r)) | ((x) >> (32 - (r))))
|
||||
#endif
|
||||
|
||||
#define XXH32_ROUND(acc, in) \
|
||||
((acc) += (in) * XXH32_P2, (acc) = XXH32_ROTL((acc), 13), \
|
||||
(acc) *= XXH32_P1)
|
||||
|
||||
static INLINE uint32_t xxh32_rd32(const uint8_t *p)
|
||||
{
|
||||
uint32_t v;
|
||||
memcpy(&v, p, 4);
|
||||
return swap_if_big32(v);
|
||||
}
|
||||
|
||||
/* The whole stripes of @p up to @end, at least one, through the lanes
|
||||
* @v; returns where the stripes stop. */
|
||||
static INLINE const uint8_t *xxh32_stripes(uint32_t *v, const uint8_t *p,
|
||||
const uint8_t *end)
|
||||
{
|
||||
uint32_t v1 = v[0];
|
||||
uint32_t v2 = v[1];
|
||||
uint32_t v3 = v[2];
|
||||
uint32_t v4 = v[3];
|
||||
const uint8_t *stop = p + ((size_t)(end - p) & ~(size_t)15);
|
||||
|
||||
do
|
||||
{
|
||||
XXH32_ROUND(v1, xxh32_rd32(p));
|
||||
XXH32_ROUND(v2, xxh32_rd32(p + 4));
|
||||
XXH32_ROUND(v3, xxh32_rd32(p + 8));
|
||||
XXH32_ROUND(v4, xxh32_rd32(p + 12));
|
||||
p += 16;
|
||||
} while (p != stop);
|
||||
v[0] = v1;
|
||||
v[1] = v2;
|
||||
v[2] = v3;
|
||||
v[3] = v4;
|
||||
return p;
|
||||
}
|
||||
|
||||
static INLINE uint32_t xxh32_converge(const uint32_t *v)
|
||||
{
|
||||
return XXH32_ROTL(v[0], 1) + XXH32_ROTL(v[1], 7)
|
||||
+ XXH32_ROTL(v[2], 12) + XXH32_ROTL(v[3], 18);
|
||||
}
|
||||
|
||||
/* The last @len (under 16) octets at @p, and the avalanche: fours, then
|
||||
* single octets */
|
||||
static INLINE uint32_t xxh32_finish(uint32_t h, const uint8_t *p, size_t len)
|
||||
{
|
||||
for (; len >= 4; len -= 4, p += 4)
|
||||
{
|
||||
h += xxh32_rd32(p) * XXH32_P3;
|
||||
h = XXH32_ROTL(h, 17) * XXH32_P4;
|
||||
}
|
||||
for (; len; len--)
|
||||
{
|
||||
h += (uint32_t)*p++ * XXH32_P5;
|
||||
h = XXH32_ROTL(h, 11) * XXH32_P1;
|
||||
}
|
||||
h ^= h >> 15;
|
||||
h *= XXH32_P2;
|
||||
h ^= h >> 13;
|
||||
h *= XXH32_P3;
|
||||
h ^= h >> 16;
|
||||
return h;
|
||||
}
|
||||
|
||||
static void xxh32_lanes(uint32_t *v, uint32_t seed)
|
||||
{
|
||||
v[0] = seed + XXH32_P1 + XXH32_P2;
|
||||
v[1] = seed + XXH32_P2;
|
||||
v[2] = seed;
|
||||
v[3] = seed - XXH32_P1;
|
||||
}
|
||||
|
||||
uint32_t xxh32(const void *data, size_t len, uint32_t seed)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t*)data;
|
||||
uint32_t h;
|
||||
|
||||
if (len >= 16)
|
||||
{
|
||||
uint32_t v[4];
|
||||
xxh32_lanes(v, seed);
|
||||
p = xxh32_stripes(v, p, p + len);
|
||||
h = xxh32_converge(v);
|
||||
}
|
||||
else
|
||||
h = seed + XXH32_P5;
|
||||
return xxh32_finish(h + (uint32_t)len, p, len & 15);
|
||||
}
|
||||
|
||||
void xxh32_reset(xxh32_state_t *s, uint32_t seed)
|
||||
{
|
||||
xxh32_lanes(s->v, seed);
|
||||
s->total = 0;
|
||||
s->large = 0;
|
||||
s->memsize = 0;
|
||||
}
|
||||
|
||||
void xxh32_update(xxh32_state_t *s, const void *data, size_t len)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t*)data;
|
||||
const uint8_t *end = p + len;
|
||||
|
||||
if (!len)
|
||||
return;
|
||||
s->total += (uint32_t)len;
|
||||
s->large |= (len >= 16) | (s->total >= 16);
|
||||
|
||||
/* not yet a stripe */
|
||||
if (s->memsize + len < 16)
|
||||
{
|
||||
memcpy(s->mem + s->memsize, p, len);
|
||||
s->memsize += (uint32_t)len;
|
||||
return;
|
||||
}
|
||||
|
||||
/* the stripe begun before, made whole */
|
||||
if (s->memsize)
|
||||
{
|
||||
size_t fill = 16 - s->memsize;
|
||||
memcpy(s->mem + s->memsize, p, fill);
|
||||
xxh32_stripes(s->v, s->mem, s->mem + 16);
|
||||
p += fill;
|
||||
s->memsize = 0;
|
||||
}
|
||||
|
||||
if (end - p >= 16)
|
||||
p = xxh32_stripes(s->v, p, end);
|
||||
if (p != end)
|
||||
{
|
||||
memcpy(s->mem, p, (size_t)(end - p));
|
||||
s->memsize = (uint32_t)(end - p);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t xxh32_digest(const xxh32_state_t *s)
|
||||
{
|
||||
uint32_t h = s->large
|
||||
? xxh32_converge(s->v)
|
||||
: s->v[2] + XXH32_P5;
|
||||
return xxh32_finish(h + s->total, s->mem, s->memsize);
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
# python3 gen_sjis_tables.py > encoding_shiftjis_tables.h
|
||||
#
|
||||
# Writes encoding_shiftjis_tables.h: Shift-JIS as Windows code page 932
|
||||
# has it (JIS X 0208 with the NEC and IBM extensions), from Python's
|
||||
# cp932 codec. The user-defined area F040-F9FC and the single octets
|
||||
# 0x80, 0xA0 and 0xFD-0xFF, which code page 932 sends to the Private Use
|
||||
# Area, are left out.
|
||||
import sys
|
||||
|
||||
def lead_ok(l):
|
||||
return 0x81 <= l <= 0x9F or 0xE0 <= l <= 0xEF or 0xFA <= l <= 0xFC
|
||||
|
||||
leads = [l for l in range(0x81, 0xFD) if lead_ok(l)]
|
||||
decode = []
|
||||
pairs = {}
|
||||
for l in leads:
|
||||
row = []
|
||||
for t in range(0x40, 0xFD):
|
||||
u = 0
|
||||
try:
|
||||
s = bytes([l, t]).decode('cp932')
|
||||
if len(s) == 1 and not (0xE000 <= ord(s) <= 0xF8FF):
|
||||
u = ord(s)
|
||||
except UnicodeDecodeError:
|
||||
pass
|
||||
row.append(u)
|
||||
decode.append(row)
|
||||
|
||||
for cp in range(0x80, 0x10000):
|
||||
if 0xD800 <= cp < 0xE000 or 0xE000 <= cp <= 0xF8FF:
|
||||
continue
|
||||
try:
|
||||
e = chr(cp).encode('cp932')
|
||||
except UnicodeEncodeError:
|
||||
continue
|
||||
if len(e) == 2 and lead_ok(e[0]):
|
||||
pairs[cp] = (e[0] << 8) | e[1]
|
||||
|
||||
out = sys.stdout
|
||||
out.write('/* Generated by gen_sjis_tables.py from code page 932, as Python\'s\n'
|
||||
' * cp932 codec has it; do not edit. */\n'
|
||||
'#ifndef LIBRETRO_ENCODING_SHIFTJIS_TABLES_H\n'
|
||||
'#define LIBRETRO_ENCODING_SHIFTJIS_TABLES_H\n\n'
|
||||
'#include <stdint.h>\n\n')
|
||||
out.write('/* Unicode for lead octet L (rows: 0x81-0x9F, 0xE0-0xEF, 0xFA-0xFC)\n'
|
||||
' * and trail octet 0x40-0xFC; 0 where nothing is mapped. */\n')
|
||||
out.write('static const uint16_t sjis_decode[%d][189] = {\n' % len(leads))
|
||||
for l, row in zip(leads, decode):
|
||||
out.write(' /* 0x%02X */ {\n' % l)
|
||||
for i in range(0, len(row), 10):
|
||||
out.write(' ' + ','.join('0x%04X' % v for v in row[i:i+10]) + ',\n')
|
||||
out.write(' },\n')
|
||||
out.write('};\n\n')
|
||||
keys = sorted(pairs)
|
||||
out.write('/* Unicode code points with their two-octet Shift-JIS codes, sorted\n'
|
||||
' * by code point for a binary search. */\n')
|
||||
out.write('#define SJIS_ENCODE_COUNT %d\n' % len(keys))
|
||||
out.write('static const uint16_t sjis_encode[SJIS_ENCODE_COUNT][2] = {\n')
|
||||
for i in range(0, len(keys), 6):
|
||||
out.write(' ' + ','.join('{0x%04X,0x%04X}' % (k, pairs[k]) for k in keys[i:i+6]) + ',\n')
|
||||
out.write('};\n\n#endif\n')
|
||||
@@ -599,52 +599,14 @@ struct string_list *file_archive_get_file_list(const char *path,
|
||||
|
||||
|
||||
/* Copies a complete temporary file over a target it could not be
|
||||
* renamed onto, and removes it. Only for filesystems that refuse the
|
||||
* rename; an atomic replacement is no longer possible there, which is
|
||||
* what writing the member in place always meant. */
|
||||
* renamed onto, with the platform's copy primitive where there is one.
|
||||
* Only for filesystems that refuse the rename; an atomic replacement
|
||||
* is no longer possible there, which is what writing the member in
|
||||
* place always meant. */
|
||||
static bool file_archive_pending_copy_in_place(const char *temp_path,
|
||||
const char *path)
|
||||
{
|
||||
bool ok = true;
|
||||
uint8_t *buf;
|
||||
RFILE *in;
|
||||
RFILE *out;
|
||||
|
||||
if (!(buf = (uint8_t*)malloc(65536)))
|
||||
return false;
|
||||
if (!(in = filestream_open(temp_path, RETRO_VFS_FILE_ACCESS_READ,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_NONE)))
|
||||
{
|
||||
free(buf);
|
||||
return false;
|
||||
}
|
||||
if (!(out = filestream_open(path, RETRO_VFS_FILE_ACCESS_WRITE,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_NONE)))
|
||||
{
|
||||
filestream_close(in);
|
||||
free(buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int64_t rd = filestream_read(in, buf, 65536);
|
||||
if (rd < 0)
|
||||
ok = false;
|
||||
if (rd <= 0)
|
||||
break;
|
||||
if (filestream_write(out, buf, rd) != rd)
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
filestream_close(in);
|
||||
if (filestream_close(out) != 0)
|
||||
ok = false;
|
||||
free(buf);
|
||||
return ok;
|
||||
return filestream_copy(temp_path, path) == 0;
|
||||
}
|
||||
|
||||
/* Puts a completed member in place. Written beside the file and
|
||||
|
||||
@@ -390,7 +390,8 @@ static int64_t bz2_file_read(const char *path, const char *needle,
|
||||
if (optional_outfile)
|
||||
{
|
||||
RFILE *out = filestream_open(optional_outfile,
|
||||
RETRO_VFS_FILE_ACCESS_WRITE, RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||
RETRO_VFS_FILE_ACCESS_WRITE,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_SEQUENTIAL_BULK);
|
||||
ok = out && bz2_pass(&src, file, filestream_get_size(file),
|
||||
bz2_write, out);
|
||||
if (out)
|
||||
|
||||
@@ -185,6 +185,18 @@ static INLINE uint64_t read_le64(const uint8_t *data)
|
||||
return (uint64_t)read_le(data, 4) | ((uint64_t)read_le(data + 4, 4) << 32);
|
||||
}
|
||||
|
||||
/* @len octets at @off: one read at the offset, or a seek and a read
|
||||
* where the file has none */
|
||||
static int64_t zip_read_at(RFILE *f, void *buf, int64_t len, int64_t off)
|
||||
{
|
||||
int64_t got = filestream_read_at(f, buf, len, off);
|
||||
if (got >= 0)
|
||||
return got;
|
||||
if (filestream_seek(f, off, RETRO_VFS_SEEK_POSITION_START) < 0)
|
||||
return -1;
|
||||
return filestream_read(f, buf, len);
|
||||
}
|
||||
|
||||
static void zip_context_free_stream(
|
||||
zip_context_t *zip_context, bool keep_decompressed)
|
||||
{
|
||||
@@ -274,17 +286,16 @@ static bool zip_bzip2_fill(struct file_archive_transfer *state,
|
||||
uint64_t to = taken + cap;
|
||||
if (to > zip_context->csize)
|
||||
to = zip_context->csize;
|
||||
filestream_seek(state->archive_file,
|
||||
(int64_t)(zip_context->fdoffset + zip_context->boffset),
|
||||
RETRO_VFS_SEEK_POSITION_START);
|
||||
while (zip_context->boffset < to)
|
||||
{
|
||||
size_t at = (size_t)(zip_context->boffset % cap);
|
||||
size_t n = cap - at;
|
||||
if (n > to - zip_context->boffset)
|
||||
n = (size_t)(to - zip_context->boffset);
|
||||
if (filestream_read(state->archive_file, zip_context->tmpbuf + at,
|
||||
(int64_t)n) != (int64_t)n)
|
||||
if (zip_read_at(state->archive_file, zip_context->tmpbuf + at,
|
||||
(int64_t)n,
|
||||
(int64_t)(zip_context->fdoffset + zip_context->boffset))
|
||||
!= (int64_t)n)
|
||||
return false;
|
||||
zip_context->boffset += n;
|
||||
}
|
||||
@@ -352,8 +363,8 @@ static const uint8_t *zip_member_whole(struct file_archive_transfer *state,
|
||||
*buf = p;
|
||||
*cap = (size_t)csize;
|
||||
}
|
||||
filestream_seek(state->archive_file, off, RETRO_VFS_SEEK_POSITION_START);
|
||||
if (filestream_read(state->archive_file, *buf, csize) != (int64_t)csize)
|
||||
if (zip_read_at(state->archive_file, *buf, (int64_t)csize, off)
|
||||
!= (int64_t)csize)
|
||||
return NULL;
|
||||
return *buf;
|
||||
}
|
||||
@@ -444,8 +455,8 @@ static bool zlib_stream_decompress_data_to_file_init(
|
||||
else
|
||||
#endif
|
||||
{
|
||||
filestream_seek(state->archive_file, (int64_t)local + 26, RETRO_VFS_SEEK_POSITION_START);
|
||||
if (filestream_read(state->archive_file, local_header_buf, 4) != 4)
|
||||
if (zip_read_at(state->archive_file, local_header_buf, 4,
|
||||
(int64_t)local + 26) != 4)
|
||||
return false;
|
||||
local_header = local_header_buf;
|
||||
}
|
||||
@@ -518,11 +529,9 @@ static bool zlib_stream_decompress_data_to_file_init(
|
||||
else
|
||||
#endif
|
||||
{
|
||||
filestream_seek(state->archive_file, offsetData,
|
||||
RETRO_VFS_SEEK_POSITION_START);
|
||||
if ( csize < sizeof(hdr)
|
||||
|| filestream_read(state->archive_file, hdr, sizeof(hdr))
|
||||
!= (int64_t)sizeof(hdr))
|
||||
|| zip_read_at(state->archive_file, hdr, sizeof(hdr),
|
||||
offsetData) != (int64_t)sizeof(hdr))
|
||||
return false;
|
||||
}
|
||||
if ( csize < sizeof(hdr)
|
||||
@@ -708,10 +717,10 @@ static int zlib_stream_decompress_data_to_file_iterate(
|
||||
#endif
|
||||
{
|
||||
/* Read the entire file to memory */
|
||||
filestream_seek(state->archive_file, zip_context->fdoffset, RETRO_VFS_SEEK_POSITION_START);
|
||||
if (filestream_read(state->archive_file,
|
||||
zip_context->decompressed_data,
|
||||
zip_context->usize) != (int64_t)zip_context->usize)
|
||||
if (zip_read_at(state->archive_file,
|
||||
zip_context->decompressed_data,
|
||||
(int64_t)zip_context->usize, zip_context->fdoffset)
|
||||
!= (int64_t)zip_context->usize)
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -897,11 +906,9 @@ static int zlib_stream_decompress_data_to_file_iterate(
|
||||
size_t k = left < room ? (size_t)left : room;
|
||||
if (k)
|
||||
{
|
||||
filestream_seek(state->archive_file,
|
||||
(int64_t)(zip_context->fdoffset + zip_context->boffset),
|
||||
RETRO_VFS_SEEK_POSITION_START);
|
||||
if (filestream_read(state->archive_file,
|
||||
zip_context->tmpbuf + zip_context->in_have, (int64_t)k)
|
||||
if (zip_read_at(state->archive_file,
|
||||
zip_context->tmpbuf + zip_context->in_have, (int64_t)k,
|
||||
(int64_t)(zip_context->fdoffset + zip_context->boffset))
|
||||
!= (int64_t)k)
|
||||
return -1;
|
||||
zip_context->boffset += k;
|
||||
@@ -971,11 +978,9 @@ static int zlib_stream_decompress_data_to_file_iterate(
|
||||
size_t k = left < room ? (size_t)left : room;
|
||||
if (k)
|
||||
{
|
||||
filestream_seek(state->archive_file,
|
||||
(int64_t)(zip_context->fdoffset + zip_context->boffset),
|
||||
RETRO_VFS_SEEK_POSITION_START);
|
||||
if (filestream_read(state->archive_file,
|
||||
zip_context->tmpbuf + zip_context->in_have, (int64_t)k)
|
||||
if (zip_read_at(state->archive_file,
|
||||
zip_context->tmpbuf + zip_context->in_have, (int64_t)k,
|
||||
(int64_t)(zip_context->fdoffset + zip_context->boffset))
|
||||
!= (int64_t)k)
|
||||
return -1;
|
||||
zip_context->boffset += k;
|
||||
@@ -1068,12 +1073,11 @@ static int zlib_stream_decompress_data_to_file_iterate(
|
||||
? RZSTD_PROCESS_END : RZSTD_PROCESS_ERROR;
|
||||
else
|
||||
{
|
||||
filestream_seek(state->archive_file,
|
||||
(int64_t)(zip_context->fdoffset + zip_context->boffset),
|
||||
RETRO_VFS_SEEK_POSITION_START);
|
||||
if ( want > zip_context->csize - zip_context->boffset
|
||||
|| filestream_read(state->archive_file, zip_context->tmpbuf,
|
||||
(int64_t)want) != (int64_t)want
|
||||
|| zip_read_at(state->archive_file, zip_context->tmpbuf,
|
||||
(int64_t)want,
|
||||
(int64_t)(zip_context->fdoffset + zip_context->boffset))
|
||||
!= (int64_t)want
|
||||
|| rzstd_blocks_give((rzstd_blocks_t*)zip_context->zs,
|
||||
zip_context->tmpbuf, want, &blk, &len)
|
||||
!= RZSTD_PROCESS_NEXT)
|
||||
@@ -1445,9 +1449,8 @@ static int zip_parse_file_init(file_archive_transfer_t *state,
|
||||
else
|
||||
read_pos = MAX(read_pos - read_block + 21, 0);
|
||||
|
||||
/* Seek to read_pos and read read_block bytes. */
|
||||
filestream_seek(state->archive_file, read_pos, RETRO_VFS_SEEK_POSITION_START);
|
||||
if (filestream_read(state->archive_file, footer_buf, read_block) != read_block)
|
||||
if (zip_read_at(state->archive_file, footer_buf, read_block,
|
||||
read_pos) != read_block)
|
||||
return -1;
|
||||
|
||||
footer = footer_buf + read_block - 22;
|
||||
@@ -1489,9 +1492,7 @@ static int zip_parse_file_init(file_archive_transfer_t *state,
|
||||
loc = map + (size_t)(at - 20);
|
||||
else
|
||||
{
|
||||
filestream_seek(state->archive_file, at - 20,
|
||||
RETRO_VFS_SEEK_POSITION_START);
|
||||
if (filestream_read(state->archive_file, loc_buf, 20) != 20)
|
||||
if (zip_read_at(state->archive_file, loc_buf, 20, at - 20) != 20)
|
||||
return -1;
|
||||
}
|
||||
if (read_le(loc, 4) != ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE)
|
||||
@@ -1503,9 +1504,8 @@ static int zip_parse_file_init(file_archive_transfer_t *state,
|
||||
rec = map + (size_t)rec_off;
|
||||
else
|
||||
{
|
||||
filestream_seek(state->archive_file, (int64_t)rec_off,
|
||||
RETRO_VFS_SEEK_POSITION_START);
|
||||
if (filestream_read(state->archive_file, rec_buf, 56) != 56)
|
||||
if (zip_read_at(state->archive_file, rec_buf, 56, (int64_t)rec_off)
|
||||
!= 56)
|
||||
return -1;
|
||||
}
|
||||
if (read_le(rec, 4) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE)
|
||||
@@ -1576,8 +1576,8 @@ static int zip_parse_file_init(file_archive_transfer_t *state,
|
||||
|
||||
if (!map)
|
||||
{
|
||||
filestream_seek(state->archive_file, directory_offset, RETRO_VFS_SEEK_POSITION_START);
|
||||
if (filestream_read(state->archive_file, zip_context->directory, directory_size) != directory_size)
|
||||
if (zip_read_at(state->archive_file, zip_context->directory,
|
||||
directory_size, directory_offset) != directory_size)
|
||||
{
|
||||
free(zip_context);
|
||||
return -1;
|
||||
@@ -1837,9 +1837,8 @@ static int file_archive_entry_source_capture(
|
||||
else
|
||||
#endif
|
||||
{
|
||||
filestream_seek(state->archive_file, (int64_t)local + 26,
|
||||
RETRO_VFS_SEEK_POSITION_START);
|
||||
if (filestream_read(state->archive_file, local_header_buf, 4) != 4)
|
||||
if (zip_read_at(state->archive_file, local_header_buf, 4,
|
||||
(int64_t)local + 26) != 4)
|
||||
return -1;
|
||||
local_header = local_header_buf;
|
||||
}
|
||||
@@ -1964,10 +1963,8 @@ int64_t file_archive_entry_source_read(file_archive_entry_source_t *s,
|
||||
else
|
||||
#endif
|
||||
{
|
||||
filestream_seek(s->state.archive_file,
|
||||
(int64_t)(s->fdoffset + s->out_off),
|
||||
RETRO_VFS_SEEK_POSITION_START);
|
||||
if (filestream_read(s->state.archive_file, dst, n) != n)
|
||||
if (zip_read_at(s->state.archive_file, dst, n,
|
||||
(int64_t)(s->fdoffset + s->out_off)) != n)
|
||||
return -1;
|
||||
}
|
||||
s->out_off += (uint64_t)n;
|
||||
|
||||
@@ -832,7 +832,7 @@ static void config_file_get_realpath(char *s, size_t len,
|
||||
}
|
||||
}
|
||||
|
||||
static void config_file_add_sub_conf(config_file_t *conf, char *path,
|
||||
static bool config_file_add_sub_conf(config_file_t *conf, char *path,
|
||||
char *s, size_t len, config_file_cb_t *cb)
|
||||
{
|
||||
struct config_include_list *node = (struct config_include_list*)
|
||||
@@ -841,12 +841,7 @@ static void config_file_add_sub_conf(config_file_t *conf, char *path,
|
||||
if (node)
|
||||
{
|
||||
node->next = NULL;
|
||||
/* Add include list */
|
||||
if (!(node->path = strdup(path)))
|
||||
{
|
||||
free(node);
|
||||
goto realpath;
|
||||
}
|
||||
node->path = path;
|
||||
|
||||
/* Order is user-visible - config_file_dump() writes the
|
||||
* '#include' lines back in list order - so this appends rather
|
||||
@@ -859,9 +854,9 @@ static void config_file_add_sub_conf(config_file_t *conf, char *path,
|
||||
conf->includes_tail = node;
|
||||
}
|
||||
|
||||
realpath:
|
||||
config_file_get_realpath(s, len, path,
|
||||
conf->path);
|
||||
return node != NULL;
|
||||
}
|
||||
|
||||
size_t config_file_add_reference(config_file_t *conf, char *path)
|
||||
@@ -1128,7 +1123,7 @@ static bool config_file_parse_line(config_file_t *conf,
|
||||
if (include_found)
|
||||
{
|
||||
config_file_t sub_conf;
|
||||
char real_path[PATH_MAX_LENGTH];
|
||||
char *real_path;
|
||||
char *include_line = comment + (sizeof("include ")-1);
|
||||
if (*include_line == '\0')
|
||||
return false;
|
||||
@@ -1140,8 +1135,14 @@ static bool config_file_parse_line(config_file_t *conf,
|
||||
free(path);
|
||||
return false;
|
||||
}
|
||||
config_file_add_sub_conf(conf, path,
|
||||
real_path, sizeof(real_path), cb);
|
||||
if (!(real_path = (char*)malloc(PATH_MAX_LENGTH)))
|
||||
{
|
||||
free(path);
|
||||
return false;
|
||||
}
|
||||
if (config_file_add_sub_conf(conf, path,
|
||||
real_path, PATH_MAX_LENGTH, cb))
|
||||
path = NULL; /* The include list owns the parsed path. */
|
||||
config_file_initialize(&sub_conf);
|
||||
/* Includes are fetched the same way their parent was. */
|
||||
sub_conf.io = conf->io;
|
||||
@@ -1169,6 +1170,7 @@ static bool config_file_parse_line(config_file_t *conf,
|
||||
* NULL/transferred, so the call is equally correct
|
||||
* there. */
|
||||
config_file_deinitialize(&sub_conf);
|
||||
free(real_path);
|
||||
}
|
||||
/* Starting a line with an 'reference' directive
|
||||
* sets the reference path */
|
||||
|
||||
@@ -254,6 +254,174 @@ bool path_rmdir(const char *dir)
|
||||
return retro_vfs_rmdir_impl(dir) == 0;
|
||||
}
|
||||
|
||||
static bool path_is_dot_entry(const char *name)
|
||||
{
|
||||
return name[0] == '.'
|
||||
&& (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
|
||||
}
|
||||
|
||||
/* Appends the separator and @name to the @len characters of @path,
|
||||
* a PATH_MAX_LENGTH buffer. Returns the new length, or 0 if it
|
||||
* does not fit. */
|
||||
static size_t path_tree_append(char *path, size_t len, const char *name)
|
||||
{
|
||||
size_t name_len = strlen(name);
|
||||
if (len + 1 + name_len >= PATH_MAX_LENGTH)
|
||||
return 0;
|
||||
path[len] = PATH_DEFAULT_SLASH_C();
|
||||
memcpy(path + len + 1, name, name_len + 1);
|
||||
return len + 1 + name_len;
|
||||
}
|
||||
|
||||
/* Drops trailing separators, keeping a root's. Returns the length. */
|
||||
static size_t path_tree_trim(char *path)
|
||||
{
|
||||
size_t len = strlen(path);
|
||||
while (len > 1 && (path[len - 1] == '/' || path[len - 1] == '\\')
|
||||
&& path[len - 2] != ':')
|
||||
path[--len] = '\0';
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Empties and removes the directory in the first @len characters of
|
||||
* @path, which grows in place with each entry's name. */
|
||||
static bool path_remove_tree_dir(char *path, size_t len)
|
||||
{
|
||||
bool ok = true;
|
||||
libretro_vfs_implementation_dir *dir =
|
||||
retro_vfs_opendir_impl(path, true);
|
||||
|
||||
if (!dir)
|
||||
return false;
|
||||
|
||||
while (retro_vfs_readdir_impl(dir))
|
||||
{
|
||||
size_t entry_len;
|
||||
const char *name = retro_vfs_dirent_get_name_impl(dir);
|
||||
|
||||
if (!name || path_is_dot_entry(name))
|
||||
continue;
|
||||
if (!(entry_len = path_tree_append(path, len, name)))
|
||||
{
|
||||
ok = false;
|
||||
continue;
|
||||
}
|
||||
if (retro_vfs_dirent_is_dir_impl(dir))
|
||||
{
|
||||
/* An empty directory goes at once, and so does a link to
|
||||
* one (rmdir on Windows, unlink elsewhere): only a real
|
||||
* directory with something in it is walked. */
|
||||
if ( retro_vfs_rmdir_impl(path) != 0
|
||||
&& retro_vfs_file_remove_impl(path) != 0
|
||||
&& !path_remove_tree_dir(path, entry_len))
|
||||
ok = false;
|
||||
}
|
||||
else if (retro_vfs_file_remove_impl(path) != 0)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
retro_vfs_closedir_impl(dir);
|
||||
path[len] = '\0';
|
||||
return retro_vfs_rmdir_impl(path) == 0 && ok;
|
||||
}
|
||||
|
||||
bool path_remove_tree(const char *path)
|
||||
{
|
||||
bool ok;
|
||||
size_t len;
|
||||
char *buf;
|
||||
|
||||
if (!path || !*path)
|
||||
return false;
|
||||
/* A file, a link or an empty directory: no walk */
|
||||
if ( retro_vfs_rmdir_impl(path) == 0
|
||||
|| retro_vfs_file_remove_impl(path) == 0
|
||||
|| !path_is_valid(path))
|
||||
return true;
|
||||
if (!path_is_directory(path))
|
||||
return false;
|
||||
if (!(buf = (char*)malloc(PATH_MAX_LENGTH)))
|
||||
return false;
|
||||
strlcpy(buf, path, PATH_MAX_LENGTH);
|
||||
len = path_tree_trim(buf);
|
||||
ok = path_remove_tree_dir(buf, len);
|
||||
free(buf);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static bool path_copy_tree_file(const char *src, const char *dst)
|
||||
{
|
||||
struct retro_vfs_copy_handle *copy =
|
||||
retro_vfs_copy_begin_impl(src, dst, RETRO_VFS_COPY_OVERWRITE);
|
||||
|
||||
if (!copy)
|
||||
return false;
|
||||
/* The whole file in one step: the platform's copy primitive at
|
||||
* full speed, no buffer of ours */
|
||||
while (retro_vfs_copy_step_impl(copy, (int64_t)1 << 62, NULL, NULL)
|
||||
== RETRO_VFS_COPY_RUNNING) { }
|
||||
return retro_vfs_copy_close_impl(copy) == 0;
|
||||
}
|
||||
|
||||
/* Copies the directory in the first @src_len characters of @src into
|
||||
* the one in the first @dst_len of @dst; both grow in place. */
|
||||
static bool path_copy_tree_dir(char *src, size_t src_len,
|
||||
char *dst, size_t dst_len)
|
||||
{
|
||||
bool ok = true;
|
||||
libretro_vfs_implementation_dir *dir;
|
||||
|
||||
if (!path_is_directory(dst) && !path_mkdir(dst))
|
||||
return false;
|
||||
if (!(dir = retro_vfs_opendir_impl(src, true)))
|
||||
return false;
|
||||
|
||||
while (retro_vfs_readdir_impl(dir))
|
||||
{
|
||||
size_t src_entry, dst_entry;
|
||||
const char *name = retro_vfs_dirent_get_name_impl(dir);
|
||||
|
||||
if (!name || path_is_dot_entry(name))
|
||||
continue;
|
||||
if ( !(src_entry = path_tree_append(src, src_len, name))
|
||||
|| !(dst_entry = path_tree_append(dst, dst_len, name)))
|
||||
ok = false;
|
||||
else if (retro_vfs_dirent_is_dir_impl(dir))
|
||||
{
|
||||
if (!path_copy_tree_dir(src, src_entry, dst, dst_entry))
|
||||
ok = false;
|
||||
}
|
||||
else if (!path_copy_tree_file(src, dst))
|
||||
ok = false;
|
||||
src[src_len] = '\0';
|
||||
dst[dst_len] = '\0';
|
||||
}
|
||||
|
||||
retro_vfs_closedir_impl(dir);
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool path_copy_tree(const char *src, const char *dst)
|
||||
{
|
||||
bool ok;
|
||||
char *src_buf;
|
||||
char *dst_buf;
|
||||
|
||||
if (!src || !*src || !dst || !*dst)
|
||||
return false;
|
||||
if (!path_is_directory(src))
|
||||
return path_copy_tree_file(src, dst);
|
||||
if (!(src_buf = (char*)malloc(2 * PATH_MAX_LENGTH)))
|
||||
return false;
|
||||
dst_buf = src_buf + PATH_MAX_LENGTH;
|
||||
strlcpy(src_buf, src, PATH_MAX_LENGTH);
|
||||
strlcpy(dst_buf, dst, PATH_MAX_LENGTH);
|
||||
ok = path_copy_tree_dir(src_buf, path_tree_trim(src_buf),
|
||||
dst_buf, path_tree_trim(dst_buf));
|
||||
free(src_buf);
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* path_mkdir:
|
||||
* @dir : directory
|
||||
|
||||
@@ -396,12 +396,13 @@ struct r7z_archive
|
||||
|
||||
/* What a reader on another thread may look at while one thread calls
|
||||
* r7z_archive_decode_step(): the buffer the folder is being decoded
|
||||
* into in order, and how much of it is final. prog_state is 0 when
|
||||
* there is nothing to look at, 1 while it is being decoded, 2 when
|
||||
* the folder is decoded and held; the buffer and the folder are
|
||||
* written before the state says they are there. */
|
||||
const uint8_t *prog_buf;
|
||||
uint32_t prog_folder;
|
||||
* into in order, and how much of it is final. prog_state's low two
|
||||
* bits are 0 when there is nothing to look at, 1 while it is being
|
||||
* decoded, 2 when the folder is decoded and held; the rest count the
|
||||
* changes, so that a reader that finds it the same after reading the
|
||||
* others read them all from one (see r7z_progress_state()). */
|
||||
retro_atomic_size_t prog_buf;
|
||||
retro_atomic_size_t prog_folder;
|
||||
retro_atomic_int_t prog_state;
|
||||
retro_atomic_size_t prog_pos;
|
||||
|
||||
@@ -2332,6 +2333,26 @@ static int decode_encoded_header(r7z_archive_t *a, rd_t *r,
|
||||
return res;
|
||||
}
|
||||
|
||||
/* A new state, the count of changes moved on. Only the decoding thread
|
||||
* writes it. */
|
||||
static void r7z_progress_state(r7z_archive_t *a, int state)
|
||||
{
|
||||
unsigned n = (unsigned)retro_atomic_load_relaxed_int(&a->prog_state) >> 2;
|
||||
retro_atomic_store_release_int(&a->prog_state,
|
||||
(int)((((n + 1u) & 0x1FFFFFFFu) << 2) | (unsigned)state));
|
||||
}
|
||||
|
||||
/* What a reader is to see from now on: nothing while it is written */
|
||||
static void r7z_progress_set(r7z_archive_t *a, const uint8_t *buf,
|
||||
uint32_t folder, size_t pos, int state)
|
||||
{
|
||||
r7z_progress_state(a, 0);
|
||||
retro_atomic_store_release_size(&a->prog_buf, (size_t)(uintptr_t)buf);
|
||||
retro_atomic_store_release_size(&a->prog_folder, folder);
|
||||
retro_atomic_store_release_size(&a->prog_pos, pos);
|
||||
r7z_progress_state(a, state);
|
||||
}
|
||||
|
||||
/* The archive in memory (@data), or read through @read_cb. */
|
||||
static int r7z_open(r7z_archive_t **out, const uint8_t *data, size_t len,
|
||||
r7z_read_t read_cb, void *ud)
|
||||
@@ -2386,6 +2407,8 @@ static int r7z_open(r7z_archive_t **out, const uint8_t *data, size_t len,
|
||||
a->len = len;
|
||||
a->read_cb = read_cb;
|
||||
a->read_ud = ud;
|
||||
retro_atomic_size_init(&a->prog_buf, 0);
|
||||
retro_atomic_size_init(&a->prog_folder, 0);
|
||||
retro_atomic_int_init(&a->prog_state, 0);
|
||||
retro_atomic_size_init(&a->prog_pos, 0);
|
||||
a->cached_folder = 0xFFFFFFFFu;
|
||||
@@ -2471,7 +2494,7 @@ void r7z_archive_close(r7z_archive_t *a)
|
||||
if (!a)
|
||||
return;
|
||||
decode_pending_reset(a);
|
||||
retro_atomic_store_release_int(&a->prog_state, 0);
|
||||
r7z_progress_state(a, 0);
|
||||
if (!a->cached_borrowed)
|
||||
free(a->cached_data);
|
||||
#ifdef HAVE_RBZIP2
|
||||
@@ -2555,8 +2578,8 @@ static void decode_pending_reset(r7z_archive_t *a)
|
||||
if (!a)
|
||||
return;
|
||||
/* (a folder decoded and held stays to be looked at: 2) */
|
||||
if (retro_atomic_load_acquire_int(&a->prog_state) == 1)
|
||||
retro_atomic_store_release_int(&a->prog_state, 0);
|
||||
if ((retro_atomic_load_relaxed_int(&a->prog_state) & 3) == 1)
|
||||
r7z_progress_state(a, 0);
|
||||
if (!a->pend_in_borrowed)
|
||||
free(a->pend_in);
|
||||
if (!a->pend_pass)
|
||||
@@ -2614,10 +2637,7 @@ static int coder_is_resumable(const coder_t *c)
|
||||
/* The cached folder, decoded whole and checked, is there to be read. */
|
||||
static void r7z_progress_held(r7z_archive_t *a)
|
||||
{
|
||||
a->prog_buf = a->cached_data;
|
||||
a->prog_folder = a->cached_folder;
|
||||
retro_atomic_store_release_size(&a->prog_pos, a->cached_len);
|
||||
retro_atomic_store_release_int(&a->prog_state, 2);
|
||||
r7z_progress_set(a, a->cached_data, a->cached_folder, a->cached_len, 2);
|
||||
}
|
||||
|
||||
/* The stage that is being decoded writes its output in order, and is the
|
||||
@@ -2625,7 +2645,7 @@ static void r7z_progress_held(r7z_archive_t *a)
|
||||
* to be read (r7z_archive_decode_peek()). */
|
||||
static void r7z_progress_at(r7z_archive_t *a, size_t pos)
|
||||
{
|
||||
if (retro_atomic_load_acquire_int(&a->prog_state) == 1)
|
||||
if ((retro_atomic_load_relaxed_int(&a->prog_state) & 3) == 1)
|
||||
retro_atomic_store_release_size(&a->prog_pos, pos);
|
||||
}
|
||||
|
||||
@@ -2829,10 +2849,7 @@ static int decode_stage_begin(r7z_archive_t *a, const folder_t *f)
|
||||
* folder will be held in: its progress can be watched. */
|
||||
if (a->pend_coder + 1 == f->num_coders)
|
||||
{
|
||||
a->prog_buf = a->pend_out;
|
||||
a->prog_folder = a->pend_folder;
|
||||
retro_atomic_store_release_size(&a->prog_pos, 0);
|
||||
retro_atomic_store_release_int(&a->prog_state, 1);
|
||||
r7z_progress_set(a, a->pend_out, a->pend_folder, 0, 1);
|
||||
}
|
||||
|
||||
/* Stand up a decoder that survives between slices. */
|
||||
@@ -3238,7 +3255,7 @@ static int decode_folder_bcj2_slice(r7z_archive_t *a, uint32_t fi,
|
||||
return R7Z_ERROR_CRC;
|
||||
}
|
||||
|
||||
retro_atomic_store_release_int(&a->prog_state, 0);
|
||||
r7z_progress_state(a, 0);
|
||||
r7z_cache_hold(a, a->pend_b2dst, a->pend_b2dstlen, fi, 0);
|
||||
a->pend_b2dst = NULL;
|
||||
|
||||
@@ -3405,7 +3422,7 @@ static int decode_folder_slice(r7z_archive_t *a, uint32_t fi, int *done)
|
||||
|
||||
/* a folder no coder touched is held where it lies, when the
|
||||
* archive is in memory */
|
||||
retro_atomic_store_release_int(&a->prog_state, 0);
|
||||
r7z_progress_state(a, 0);
|
||||
r7z_cache_hold(a, a->pend_in, a->pend_in_len, fi, a->pend_in_borrowed);
|
||||
r7z_progress_held(a);
|
||||
|
||||
@@ -3502,7 +3519,7 @@ int r7z_archive_extract_slice(r7z_archive_t *a, uint32_t index,
|
||||
if ((res = decode_folder(a, e->folder, &folder_data, &folder_borrowed)) != R7Z_OK)
|
||||
return res;
|
||||
|
||||
retro_atomic_store_release_int(&a->prog_state, 0);
|
||||
r7z_progress_state(a, 0);
|
||||
r7z_cache_hold(a, folder_data,
|
||||
(size_t)a->folders[e->folder].unpack_size, e->folder,
|
||||
folder_borrowed);
|
||||
@@ -3563,7 +3580,7 @@ int r7z_archive_extract(r7z_archive_t *a, uint32_t index,
|
||||
if (res != R7Z_OK)
|
||||
return res;
|
||||
|
||||
retro_atomic_store_release_int(&a->prog_state, 0);
|
||||
r7z_progress_state(a, 0);
|
||||
r7z_cache_hold(a, folder_data,
|
||||
(size_t)a->folders[e->folder].unpack_size, e->folder,
|
||||
folder_borrowed);
|
||||
@@ -3634,7 +3651,7 @@ int r7z_archive_extract_detach(r7z_archive_t *a, uint32_t index,
|
||||
else
|
||||
{
|
||||
int borrowed = 0;
|
||||
retro_atomic_store_release_int(&a->prog_state, 0);
|
||||
r7z_progress_state(a, 0);
|
||||
r7z_cache_hold(a, NULL, 0, 0xFFFFFFFFu, 0);
|
||||
if ((res = decode_folder(a, e->folder, &buf, &borrowed)) != R7Z_OK)
|
||||
return res;
|
||||
@@ -3647,7 +3664,7 @@ int r7z_archive_extract_detach(r7z_archive_t *a, uint32_t index,
|
||||
|
||||
/* The folder's output is the member: hand the buffer over rather
|
||||
* than keep it cached and copy it. */
|
||||
retro_atomic_store_release_int(&a->prog_state, 0);
|
||||
r7z_progress_state(a, 0);
|
||||
a->cached_data = NULL;
|
||||
a->cached_len = 0;
|
||||
a->cached_folder = 0xFFFFFFFFu;
|
||||
@@ -3694,7 +3711,7 @@ int r7z_archive_entry_borrow(r7z_archive_t *a, uint32_t index,
|
||||
{
|
||||
if ((res = decode_folder(a, e->folder, &folder_data, &folder_borrowed)) != R7Z_OK)
|
||||
return res;
|
||||
retro_atomic_store_release_int(&a->prog_state, 0);
|
||||
r7z_progress_state(a, 0);
|
||||
r7z_cache_hold(a, folder_data,
|
||||
(size_t)a->folders[e->folder].unpack_size, e->folder,
|
||||
folder_borrowed);
|
||||
@@ -3736,7 +3753,7 @@ int r7z_archive_decode_step(r7z_archive_t *a, uint32_t index)
|
||||
|
||||
if (a->cached_folder == e->folder && a->cached_data)
|
||||
{
|
||||
if (retro_atomic_load_acquire_int(&a->prog_state) != 2)
|
||||
if ((retro_atomic_load_relaxed_int(&a->prog_state) & 3) != 2)
|
||||
r7z_progress_held(a);
|
||||
return R7Z_OK;
|
||||
}
|
||||
@@ -3750,7 +3767,7 @@ int r7z_archive_decode_step(r7z_archive_t *a, uint32_t index)
|
||||
|
||||
if ((res = decode_folder(a, e->folder, &folder_data, &folder_borrowed)) != R7Z_OK)
|
||||
return res;
|
||||
retro_atomic_store_release_int(&a->prog_state, 0);
|
||||
r7z_progress_state(a, 0);
|
||||
r7z_cache_hold(a, folder_data,
|
||||
(size_t)a->folders[e->folder].unpack_size, e->folder,
|
||||
folder_borrowed);
|
||||
@@ -3762,7 +3779,7 @@ int r7z_archive_decode_step(r7z_archive_t *a, uint32_t index)
|
||||
if (!done)
|
||||
return R7Z_PENDING;
|
||||
/* (a folder that went through the BCJ2 slicer says so only now) */
|
||||
if (retro_atomic_load_acquire_int(&a->prog_state) != 2)
|
||||
if ((retro_atomic_load_relaxed_int(&a->prog_state) & 3) != 2)
|
||||
r7z_progress_held(a);
|
||||
return R7Z_OK;
|
||||
}
|
||||
@@ -4805,7 +4822,7 @@ int r7z_archive_decode_peek(const r7z_archive_t *a, uint32_t index,
|
||||
const uint8_t **data, size_t *avail)
|
||||
{
|
||||
const r7z_entry_t *e;
|
||||
size_t pos;
|
||||
size_t pos, buf, folder;
|
||||
int state;
|
||||
|
||||
if (!a || !data || !avail || index >= a->num_entries)
|
||||
@@ -4816,14 +4833,20 @@ int r7z_archive_decode_peek(const r7z_archive_t *a, uint32_t index,
|
||||
if (e->is_dir)
|
||||
return R7Z_ERROR_PARAM;
|
||||
|
||||
/* the state, and then what it says is there */
|
||||
state = retro_atomic_load_acquire_int((retro_atomic_int_t*)&a->prog_state);
|
||||
if (!state || a->prog_folder != e->folder)
|
||||
/* the state, what it says is there, and the state again: changed,
|
||||
* and what was read may be from before and after */
|
||||
state = retro_atomic_load_acquire_int((retro_atomic_int_t*)&a->prog_state);
|
||||
if (!(state & 3))
|
||||
return R7Z_OK;
|
||||
folder = retro_atomic_load_acquire_size((retro_atomic_size_t*)&a->prog_folder);
|
||||
buf = retro_atomic_load_acquire_size((retro_atomic_size_t*)&a->prog_buf);
|
||||
pos = retro_atomic_load_acquire_size((retro_atomic_size_t*)&a->prog_pos);
|
||||
if (retro_atomic_load_acquire_int((retro_atomic_int_t*)&a->prog_state) != state
|
||||
|| folder != e->folder)
|
||||
return R7Z_OK;
|
||||
pos = retro_atomic_load_acquire_size((retro_atomic_size_t*)&a->prog_pos);
|
||||
if (e->offset_in_folder > (uint64_t)((size_t)-1))
|
||||
return R7Z_ERROR_DATA;
|
||||
*data = a->prog_buf + (size_t)e->offset_in_folder;
|
||||
*data = (const uint8_t*)(uintptr_t)buf + (size_t)e->offset_in_folder;
|
||||
if (pos > (size_t)e->offset_in_folder)
|
||||
{
|
||||
size_t have = pos - (size_t)e->offset_in_folder;
|
||||
|
||||
@@ -216,384 +216,8 @@ static INLINE raac_v raac_v_set4(float a, float b, float c, float e)
|
||||
#define RAAC_CB_INTENSITY 15
|
||||
#define RAAC_CB_NOISE 13
|
||||
|
||||
static const uint16_t raac_hcb1_code[81] = {
|
||||
0x07f8, 0x01f1, 0x07fd, 0x03f5, 0x0068, 0x03f0, 0x07f7, 0x01ec,
|
||||
0x07f5, 0x03f1, 0x0072, 0x03f4, 0x0074, 0x0011, 0x0076, 0x01eb,
|
||||
0x006c, 0x03f6, 0x07fc, 0x01e1, 0x07f1, 0x01f0, 0x0061, 0x01f6,
|
||||
0x07f2, 0x01ea, 0x07fb, 0x01f2, 0x0069, 0x01ed, 0x0077, 0x0017,
|
||||
0x006f, 0x01e6, 0x0064, 0x01e5, 0x0067, 0x0015, 0x0062, 0x0012,
|
||||
0x0000, 0x0014, 0x0065, 0x0016, 0x006d, 0x01e9, 0x0063, 0x01e4,
|
||||
0x006b, 0x0013, 0x0071, 0x01e3, 0x0070, 0x01f3, 0x07fe, 0x01e7,
|
||||
0x07f3, 0x01ef, 0x0060, 0x01ee, 0x07f0, 0x01e2, 0x07fa, 0x03f3,
|
||||
0x006a, 0x01e8, 0x0075, 0x0010, 0x0073, 0x01f4, 0x006e, 0x03f7,
|
||||
0x07f6, 0x01e0, 0x07f9, 0x03f2, 0x0066, 0x01f5, 0x07ff, 0x01f7,
|
||||
0x07f4
|
||||
};
|
||||
static const uint8_t raac_hcb1_bits[81] = {
|
||||
11, 9, 11, 10, 7, 10, 11, 9, 11, 10, 7, 10, 7, 5, 7, 9,
|
||||
7, 10, 11, 9, 11, 9, 7, 9, 11, 9, 11, 9, 7, 9, 7, 5,
|
||||
7, 9, 7, 9, 7, 5, 7, 5, 1, 5, 7, 5, 7, 9, 7, 9,
|
||||
7, 5, 7, 9, 7, 9, 11, 9, 11, 9, 7, 9, 11, 9, 11, 10,
|
||||
7, 9, 7, 5, 7, 9, 7, 10, 11, 9, 11, 10, 7, 9, 11, 9,
|
||||
11
|
||||
};
|
||||
static const uint16_t raac_hcb2_code[81] = {
|
||||
0x01f3, 0x006f, 0x01fd, 0x00eb, 0x0023, 0x00ea, 0x01f7, 0x00e8,
|
||||
0x01fa, 0x00f2, 0x002d, 0x0070, 0x0020, 0x0006, 0x002b, 0x006e,
|
||||
0x0028, 0x00e9, 0x01f9, 0x0066, 0x00f8, 0x00e7, 0x001b, 0x00f1,
|
||||
0x01f4, 0x006b, 0x01f5, 0x00ec, 0x002a, 0x006c, 0x002c, 0x000a,
|
||||
0x0027, 0x0067, 0x001a, 0x00f5, 0x0024, 0x0008, 0x001f, 0x0009,
|
||||
0x0000, 0x0007, 0x001d, 0x000b, 0x0030, 0x00ef, 0x001c, 0x0064,
|
||||
0x001e, 0x000c, 0x0029, 0x00f3, 0x002f, 0x00f0, 0x01fc, 0x0071,
|
||||
0x01f2, 0x00f4, 0x0021, 0x00e6, 0x00f7, 0x0068, 0x01f8, 0x00ee,
|
||||
0x0022, 0x0065, 0x0031, 0x0002, 0x0026, 0x00ed, 0x0025, 0x006a,
|
||||
0x01fb, 0x0072, 0x01fe, 0x0069, 0x002e, 0x00f6, 0x01ff, 0x006d,
|
||||
0x01f6
|
||||
};
|
||||
static const uint8_t raac_hcb2_bits[81] = {
|
||||
9, 7, 9, 8, 6, 8, 9, 8, 9, 8, 6, 7, 6, 5, 6, 7,
|
||||
6, 8, 9, 7, 8, 8, 6, 8, 9, 7, 9, 8, 6, 7, 6, 5,
|
||||
6, 7, 6, 8, 6, 5, 6, 5, 3, 5, 6, 5, 6, 8, 6, 7,
|
||||
6, 5, 6, 8, 6, 8, 9, 7, 9, 8, 6, 8, 8, 7, 9, 8,
|
||||
6, 7, 6, 4, 6, 8, 6, 7, 9, 7, 9, 7, 6, 8, 9, 7,
|
||||
9
|
||||
};
|
||||
static const uint16_t raac_hcb3_code[81] = {
|
||||
0x0000, 0x0009, 0x00ef, 0x000b, 0x0019, 0x00f0, 0x01eb, 0x01e6,
|
||||
0x03f2, 0x000a, 0x0035, 0x01ef, 0x0034, 0x0037, 0x01e9, 0x01ed,
|
||||
0x01e7, 0x03f3, 0x01ee, 0x03ed, 0x1ffa, 0x01ec, 0x01f2, 0x07f9,
|
||||
0x07f8, 0x03f8, 0x0ff8, 0x0008, 0x0038, 0x03f6, 0x0036, 0x0075,
|
||||
0x03f1, 0x03eb, 0x03ec, 0x0ff4, 0x0018, 0x0076, 0x07f4, 0x0039,
|
||||
0x0074, 0x03ef, 0x01f3, 0x01f4, 0x07f6, 0x01e8, 0x03ea, 0x1ffc,
|
||||
0x00f2, 0x01f1, 0x0ffb, 0x03f5, 0x07f3, 0x0ffc, 0x00ee, 0x03f7,
|
||||
0x7ffe, 0x01f0, 0x07f5, 0x7ffd, 0x1ffb, 0x3ffa, 0xffff, 0x00f1,
|
||||
0x03f0, 0x3ffc, 0x01ea, 0x03ee, 0x3ffb, 0x0ff6, 0x0ffa, 0x7ffc,
|
||||
0x07f2, 0x0ff5, 0xfffe, 0x03f4, 0x07f7, 0x7ffb, 0x0ff7, 0x0ff9,
|
||||
0x7ffa
|
||||
};
|
||||
static const uint8_t raac_hcb3_bits[81] = {
|
||||
1, 4, 8, 4, 5, 8, 9, 9, 10, 4, 6, 9, 6, 6, 9, 9,
|
||||
9, 10, 9, 10, 13, 9, 9, 11, 11, 10, 12, 4, 6, 10, 6, 7,
|
||||
10, 10, 10, 12, 5, 7, 11, 6, 7, 10, 9, 9, 11, 9, 10, 13,
|
||||
8, 9, 12, 10, 11, 12, 8, 10, 15, 9, 11, 15, 13, 14, 16, 8,
|
||||
10, 14, 9, 10, 14, 12, 12, 15, 11, 12, 16, 10, 11, 15, 12, 12,
|
||||
15
|
||||
};
|
||||
static const uint16_t raac_hcb4_code[81] = {
|
||||
0x0007, 0x0016, 0x00f6, 0x0018, 0x0008, 0x00ef, 0x01ef, 0x00f3,
|
||||
0x07f8, 0x0019, 0x0017, 0x00ed, 0x0015, 0x0001, 0x00e2, 0x00f0,
|
||||
0x0070, 0x03f0, 0x01ee, 0x00f1, 0x07fa, 0x00ee, 0x00e4, 0x03f2,
|
||||
0x07f6, 0x03ef, 0x07fd, 0x0005, 0x0014, 0x00f2, 0x0009, 0x0004,
|
||||
0x00e5, 0x00f4, 0x00e8, 0x03f4, 0x0006, 0x0002, 0x00e7, 0x0003,
|
||||
0x0000, 0x006b, 0x00e3, 0x0069, 0x01f3, 0x00eb, 0x00e6, 0x03f6,
|
||||
0x006e, 0x006a, 0x01f4, 0x03ec, 0x01f0, 0x03f9, 0x00f5, 0x00ec,
|
||||
0x07fb, 0x00ea, 0x006f, 0x03f7, 0x07f9, 0x03f3, 0x0fff, 0x00e9,
|
||||
0x006d, 0x03f8, 0x006c, 0x0068, 0x01f5, 0x03ee, 0x01f2, 0x07f4,
|
||||
0x07f7, 0x03f1, 0x0ffe, 0x03ed, 0x01f1, 0x07f5, 0x07fe, 0x03f5,
|
||||
0x07fc
|
||||
};
|
||||
static const uint8_t raac_hcb4_bits[81] = {
|
||||
4, 5, 8, 5, 4, 8, 9, 8, 11, 5, 5, 8, 5, 4, 8, 8,
|
||||
7, 10, 9, 8, 11, 8, 8, 10, 11, 10, 11, 4, 5, 8, 4, 4,
|
||||
8, 8, 8, 10, 4, 4, 8, 4, 4, 7, 8, 7, 9, 8, 8, 10,
|
||||
7, 7, 9, 10, 9, 10, 8, 8, 11, 8, 7, 10, 11, 10, 12, 8,
|
||||
7, 10, 7, 7, 9, 10, 9, 11, 11, 10, 12, 10, 9, 11, 11, 10,
|
||||
11
|
||||
};
|
||||
static const uint16_t raac_hcb5_code[81] = {
|
||||
0x1fff, 0x0ff7, 0x07f4, 0x07e8, 0x03f1, 0x07ee, 0x07f9, 0x0ff8,
|
||||
0x1ffd, 0x0ffd, 0x07f1, 0x03e8, 0x01e8, 0x00f0, 0x01ec, 0x03ee,
|
||||
0x07f2, 0x0ffa, 0x0ff4, 0x03ef, 0x01f2, 0x00e8, 0x0070, 0x00ec,
|
||||
0x01f0, 0x03ea, 0x07f3, 0x07eb, 0x01eb, 0x00ea, 0x001a, 0x0008,
|
||||
0x0019, 0x00ee, 0x01ef, 0x07ed, 0x03f0, 0x00f2, 0x0073, 0x000b,
|
||||
0x0000, 0x000a, 0x0071, 0x00f3, 0x07e9, 0x07ef, 0x01ee, 0x00ef,
|
||||
0x0018, 0x0009, 0x001b, 0x00eb, 0x01e9, 0x07ec, 0x07f6, 0x03eb,
|
||||
0x01f3, 0x00ed, 0x0072, 0x00e9, 0x01f1, 0x03ed, 0x07f7, 0x0ff6,
|
||||
0x07f0, 0x03e9, 0x01ed, 0x00f1, 0x01ea, 0x03ec, 0x07f8, 0x0ff9,
|
||||
0x1ffc, 0x0ffc, 0x0ff5, 0x07ea, 0x03f3, 0x03f2, 0x07f5, 0x0ffb,
|
||||
0x1ffe
|
||||
};
|
||||
static const uint8_t raac_hcb5_bits[81] = {
|
||||
13, 12, 11, 11, 10, 11, 11, 12, 13, 12, 11, 10, 9, 8, 9, 10,
|
||||
11, 12, 12, 10, 9, 8, 7, 8, 9, 10, 11, 11, 9, 8, 5, 4,
|
||||
5, 8, 9, 11, 10, 8, 7, 4, 1, 4, 7, 8, 11, 11, 9, 8,
|
||||
5, 4, 5, 8, 9, 11, 11, 10, 9, 8, 7, 8, 9, 10, 11, 12,
|
||||
11, 10, 9, 8, 9, 10, 11, 12, 13, 12, 12, 11, 10, 10, 11, 12,
|
||||
13
|
||||
};
|
||||
static const uint16_t raac_hcb6_code[81] = {
|
||||
0x07fe, 0x03fd, 0x01f1, 0x01eb, 0x01f4, 0x01ea, 0x01f0, 0x03fc,
|
||||
0x07fd, 0x03f6, 0x01e5, 0x00ea, 0x006c, 0x0071, 0x0068, 0x00f0,
|
||||
0x01e6, 0x03f7, 0x01f3, 0x00ef, 0x0032, 0x0027, 0x0028, 0x0026,
|
||||
0x0031, 0x00eb, 0x01f7, 0x01e8, 0x006f, 0x002e, 0x0008, 0x0004,
|
||||
0x0006, 0x0029, 0x006b, 0x01ee, 0x01ef, 0x0072, 0x002d, 0x0002,
|
||||
0x0000, 0x0003, 0x002f, 0x0073, 0x01fa, 0x01e7, 0x006e, 0x002b,
|
||||
0x0007, 0x0001, 0x0005, 0x002c, 0x006d, 0x01ec, 0x01f9, 0x00ee,
|
||||
0x0030, 0x0024, 0x002a, 0x0025, 0x0033, 0x00ec, 0x01f2, 0x03f8,
|
||||
0x01e4, 0x00ed, 0x006a, 0x0070, 0x0069, 0x0074, 0x00f1, 0x03fa,
|
||||
0x07ff, 0x03f9, 0x01f6, 0x01ed, 0x01f8, 0x01e9, 0x01f5, 0x03fb,
|
||||
0x07fc
|
||||
};
|
||||
static const uint8_t raac_hcb6_bits[81] = {
|
||||
11, 10, 9, 9, 9, 9, 9, 10, 11, 10, 9, 8, 7, 7, 7, 8,
|
||||
9, 10, 9, 8, 6, 6, 6, 6, 6, 8, 9, 9, 7, 6, 4, 4,
|
||||
4, 6, 7, 9, 9, 7, 6, 4, 4, 4, 6, 7, 9, 9, 7, 6,
|
||||
4, 4, 4, 6, 7, 9, 9, 8, 6, 6, 6, 6, 6, 8, 9, 10,
|
||||
9, 8, 7, 7, 7, 7, 8, 10, 11, 10, 9, 9, 9, 9, 9, 10,
|
||||
11
|
||||
};
|
||||
static const uint16_t raac_hcb7_code[64] = {
|
||||
0x0000, 0x0005, 0x0037, 0x0074, 0x00f2, 0x01eb, 0x03ed, 0x07f7,
|
||||
0x0004, 0x000c, 0x0035, 0x0071, 0x00ec, 0x00ee, 0x01ee, 0x01f5,
|
||||
0x0036, 0x0034, 0x0072, 0x00ea, 0x00f1, 0x01e9, 0x01f3, 0x03f5,
|
||||
0x0073, 0x0070, 0x00eb, 0x00f0, 0x01f1, 0x01f0, 0x03ec, 0x03fa,
|
||||
0x00f3, 0x00ed, 0x01e8, 0x01ef, 0x03ef, 0x03f1, 0x03f9, 0x07fb,
|
||||
0x01ed, 0x00ef, 0x01ea, 0x01f2, 0x03f3, 0x03f8, 0x07f9, 0x07fc,
|
||||
0x03ee, 0x01ec, 0x01f4, 0x03f4, 0x03f7, 0x07f8, 0x0ffd, 0x0ffe,
|
||||
0x07f6, 0x03f0, 0x03f2, 0x03f6, 0x07fa, 0x07fd, 0x0ffc, 0x0fff
|
||||
};
|
||||
static const uint8_t raac_hcb7_bits[64] = {
|
||||
1, 3, 6, 7, 8, 9, 10, 11, 3, 4, 6, 7, 8, 8, 9, 9,
|
||||
6, 6, 7, 8, 8, 9, 9, 10, 7, 7, 8, 8, 9, 9, 10, 10,
|
||||
8, 8, 9, 9, 10, 10, 10, 11, 9, 8, 9, 9, 10, 10, 11, 11,
|
||||
10, 9, 9, 10, 10, 11, 12, 12, 11, 10, 10, 10, 11, 11, 12, 12
|
||||
};
|
||||
static const uint16_t raac_hcb8_code[64] = {
|
||||
0x000e, 0x0005, 0x0010, 0x0030, 0x006f, 0x00f1, 0x01fa, 0x03fe,
|
||||
0x0003, 0x0000, 0x0004, 0x0012, 0x002c, 0x006a, 0x0075, 0x00f8,
|
||||
0x000f, 0x0002, 0x0006, 0x0014, 0x002e, 0x0069, 0x0072, 0x00f5,
|
||||
0x002f, 0x0011, 0x0013, 0x002a, 0x0032, 0x006c, 0x00ec, 0x00fa,
|
||||
0x0071, 0x002b, 0x002d, 0x0031, 0x006d, 0x0070, 0x00f2, 0x01f9,
|
||||
0x00ef, 0x0068, 0x0033, 0x006b, 0x006e, 0x00ee, 0x00f9, 0x03fc,
|
||||
0x01f8, 0x0074, 0x0073, 0x00ed, 0x00f0, 0x00f6, 0x01f6, 0x01fd,
|
||||
0x03fd, 0x00f3, 0x00f4, 0x00f7, 0x01f7, 0x01fb, 0x01fc, 0x03ff
|
||||
};
|
||||
static const uint8_t raac_hcb8_bits[64] = {
|
||||
5, 4, 5, 6, 7, 8, 9, 10, 4, 3, 4, 5, 6, 7, 7, 8,
|
||||
5, 4, 4, 5, 6, 7, 7, 8, 6, 5, 5, 6, 6, 7, 8, 8,
|
||||
7, 6, 6, 6, 7, 7, 8, 9, 8, 7, 6, 7, 7, 8, 8, 10,
|
||||
9, 7, 7, 8, 8, 8, 9, 9, 10, 8, 8, 8, 9, 9, 9, 10
|
||||
};
|
||||
static const uint16_t raac_hcb9_code[169] = {
|
||||
0x0000, 0x0005, 0x0037, 0x00e7, 0x01de, 0x03ce, 0x03d9, 0x07c8,
|
||||
0x07cd, 0x0fc8, 0x0fdd, 0x1fe4, 0x1fec, 0x0004, 0x000c, 0x0035,
|
||||
0x0072, 0x00ea, 0x00ed, 0x01e2, 0x03d1, 0x03d3, 0x03e0, 0x07d8,
|
||||
0x0fcf, 0x0fd5, 0x0036, 0x0034, 0x0071, 0x00e8, 0x00ec, 0x01e1,
|
||||
0x03cf, 0x03dd, 0x03db, 0x07d0, 0x0fc7, 0x0fd4, 0x0fe4, 0x00e6,
|
||||
0x0070, 0x00e9, 0x01dd, 0x01e3, 0x03d2, 0x03dc, 0x07cc, 0x07ca,
|
||||
0x07de, 0x0fd8, 0x0fea, 0x1fdb, 0x01df, 0x00eb, 0x01dc, 0x01e6,
|
||||
0x03d5, 0x03de, 0x07cb, 0x07dd, 0x07dc, 0x0fcd, 0x0fe2, 0x0fe7,
|
||||
0x1fe1, 0x03d0, 0x01e0, 0x01e4, 0x03d6, 0x07c5, 0x07d1, 0x07db,
|
||||
0x0fd2, 0x07e0, 0x0fd9, 0x0feb, 0x1fe3, 0x1fe9, 0x07c4, 0x01e5,
|
||||
0x03d7, 0x07c6, 0x07cf, 0x07da, 0x0fcb, 0x0fda, 0x0fe3, 0x0fe9,
|
||||
0x1fe6, 0x1ff3, 0x1ff7, 0x07d3, 0x03d8, 0x03e1, 0x07d4, 0x07d9,
|
||||
0x0fd3, 0x0fde, 0x1fdd, 0x1fd9, 0x1fe2, 0x1fea, 0x1ff1, 0x1ff6,
|
||||
0x07d2, 0x03d4, 0x03da, 0x07c7, 0x07d7, 0x07e2, 0x0fce, 0x0fdb,
|
||||
0x1fd8, 0x1fee, 0x3ff0, 0x1ff4, 0x3ff2, 0x07e1, 0x03df, 0x07c9,
|
||||
0x07d6, 0x0fca, 0x0fd0, 0x0fe5, 0x0fe6, 0x1feb, 0x1fef, 0x3ff3,
|
||||
0x3ff4, 0x3ff5, 0x0fe0, 0x07ce, 0x07d5, 0x0fc6, 0x0fd1, 0x0fe1,
|
||||
0x1fe0, 0x1fe8, 0x1ff0, 0x3ff1, 0x3ff8, 0x3ff6, 0x7ffc, 0x0fe8,
|
||||
0x07df, 0x0fc9, 0x0fd7, 0x0fdc, 0x1fdc, 0x1fdf, 0x1fed, 0x1ff5,
|
||||
0x3ff9, 0x3ffb, 0x7ffd, 0x7ffe, 0x1fe7, 0x0fcc, 0x0fd6, 0x0fdf,
|
||||
0x1fde, 0x1fda, 0x1fe5, 0x1ff2, 0x3ffa, 0x3ff7, 0x3ffc, 0x3ffd,
|
||||
0x7fff
|
||||
};
|
||||
static const uint8_t raac_hcb9_bits[169] = {
|
||||
1, 3, 6, 8, 9, 10, 10, 11, 11, 12, 12, 13, 13, 3, 4, 6,
|
||||
7, 8, 8, 9, 10, 10, 10, 11, 12, 12, 6, 6, 7, 8, 8, 9,
|
||||
10, 10, 10, 11, 12, 12, 12, 8, 7, 8, 9, 9, 10, 10, 11, 11,
|
||||
11, 12, 12, 13, 9, 8, 9, 9, 10, 10, 11, 11, 11, 12, 12, 12,
|
||||
13, 10, 9, 9, 10, 11, 11, 11, 12, 11, 12, 12, 13, 13, 11, 9,
|
||||
10, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 11, 10, 10, 11, 11,
|
||||
12, 12, 13, 13, 13, 13, 13, 13, 11, 10, 10, 11, 11, 11, 12, 12,
|
||||
13, 13, 14, 13, 14, 11, 10, 11, 11, 12, 12, 12, 12, 13, 13, 14,
|
||||
14, 14, 12, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 12,
|
||||
11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 15, 15, 13, 12, 12, 12,
|
||||
13, 13, 13, 13, 14, 14, 14, 14, 15
|
||||
};
|
||||
static const uint16_t raac_hcb10_code[169] = {
|
||||
0x0022, 0x0008, 0x001d, 0x0026, 0x005f, 0x00d3, 0x01cf, 0x03d0,
|
||||
0x03d7, 0x03ed, 0x07f0, 0x07f6, 0x0ffd, 0x0007, 0x0000, 0x0001,
|
||||
0x0009, 0x0020, 0x0054, 0x0060, 0x00d5, 0x00dc, 0x01d4, 0x03cd,
|
||||
0x03de, 0x07e7, 0x001c, 0x0002, 0x0006, 0x000c, 0x001e, 0x0028,
|
||||
0x005b, 0x00cd, 0x00d9, 0x01ce, 0x01dc, 0x03d9, 0x03f1, 0x0025,
|
||||
0x000b, 0x000a, 0x000d, 0x0024, 0x0057, 0x0061, 0x00cc, 0x00dd,
|
||||
0x01cc, 0x01de, 0x03d3, 0x03e7, 0x005d, 0x0021, 0x001f, 0x0023,
|
||||
0x0027, 0x0059, 0x0064, 0x00d8, 0x00df, 0x01d2, 0x01e2, 0x03dd,
|
||||
0x03ee, 0x00d1, 0x0055, 0x0029, 0x0056, 0x0058, 0x0062, 0x00ce,
|
||||
0x00e0, 0x00e2, 0x01da, 0x03d4, 0x03e3, 0x07eb, 0x01c9, 0x005e,
|
||||
0x005a, 0x005c, 0x0063, 0x00ca, 0x00da, 0x01c7, 0x01ca, 0x01e0,
|
||||
0x03db, 0x03e8, 0x07ec, 0x01e3, 0x00d2, 0x00cb, 0x00d0, 0x00d7,
|
||||
0x00db, 0x01c6, 0x01d5, 0x01d8, 0x03ca, 0x03da, 0x07ea, 0x07f1,
|
||||
0x01e1, 0x00d4, 0x00cf, 0x00d6, 0x00de, 0x00e1, 0x01d0, 0x01d6,
|
||||
0x03d1, 0x03d5, 0x03f2, 0x07ee, 0x07fb, 0x03e9, 0x01cd, 0x01c8,
|
||||
0x01cb, 0x01d1, 0x01d7, 0x01df, 0x03cf, 0x03e0, 0x03ef, 0x07e6,
|
||||
0x07f8, 0x0ffa, 0x03eb, 0x01dd, 0x01d3, 0x01d9, 0x01db, 0x03d2,
|
||||
0x03cc, 0x03dc, 0x03ea, 0x07ed, 0x07f3, 0x07f9, 0x0ff9, 0x07f2,
|
||||
0x03ce, 0x01e4, 0x03cb, 0x03d8, 0x03d6, 0x03e2, 0x03e5, 0x07e8,
|
||||
0x07f4, 0x07f5, 0x07f7, 0x0ffb, 0x07fa, 0x03ec, 0x03df, 0x03e1,
|
||||
0x03e4, 0x03e6, 0x03f0, 0x07e9, 0x07ef, 0x0ff8, 0x0ffe, 0x0ffc,
|
||||
0x0fff
|
||||
};
|
||||
static const uint8_t raac_hcb10_bits[169] = {
|
||||
6, 5, 6, 6, 7, 8, 9, 10, 10, 10, 11, 11, 12, 5, 4, 4,
|
||||
5, 6, 7, 7, 8, 8, 9, 10, 10, 11, 6, 4, 5, 5, 6, 6,
|
||||
7, 8, 8, 9, 9, 10, 10, 6, 5, 5, 5, 6, 7, 7, 8, 8,
|
||||
9, 9, 10, 10, 7, 6, 6, 6, 6, 7, 7, 8, 8, 9, 9, 10,
|
||||
10, 8, 7, 6, 7, 7, 7, 8, 8, 8, 9, 10, 10, 11, 9, 7,
|
||||
7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 9, 8, 8, 8, 8,
|
||||
8, 9, 9, 9, 10, 10, 11, 11, 9, 8, 8, 8, 8, 8, 9, 9,
|
||||
10, 10, 10, 11, 11, 10, 9, 9, 9, 9, 9, 9, 10, 10, 10, 11,
|
||||
11, 12, 10, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 12, 11,
|
||||
10, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 12, 11, 10, 10, 10,
|
||||
10, 10, 10, 11, 11, 12, 12, 12, 12
|
||||
};
|
||||
static const uint16_t raac_hcb11_code[289] = {
|
||||
0x0000, 0x0006, 0x0019, 0x003d, 0x009c, 0x00c6, 0x01a7, 0x0390,
|
||||
0x03c2, 0x03df, 0x07e6, 0x07f3, 0x0ffb, 0x07ec, 0x0ffa, 0x0ffe,
|
||||
0x038e, 0x0005, 0x0001, 0x0008, 0x0014, 0x0037, 0x0042, 0x0092,
|
||||
0x00af, 0x0191, 0x01a5, 0x01b5, 0x039e, 0x03c0, 0x03a2, 0x03cd,
|
||||
0x07d6, 0x00ae, 0x0017, 0x0007, 0x0009, 0x0018, 0x0039, 0x0040,
|
||||
0x008e, 0x00a3, 0x00b8, 0x0199, 0x01ac, 0x01c1, 0x03b1, 0x0396,
|
||||
0x03be, 0x03ca, 0x009d, 0x003c, 0x0015, 0x0016, 0x001a, 0x003b,
|
||||
0x0044, 0x0091, 0x00a5, 0x00be, 0x0196, 0x01ae, 0x01b9, 0x03a1,
|
||||
0x0391, 0x03a5, 0x03d5, 0x0094, 0x009a, 0x0036, 0x0038, 0x003a,
|
||||
0x0041, 0x008c, 0x009b, 0x00b0, 0x00c3, 0x019e, 0x01ab, 0x01bc,
|
||||
0x039f, 0x038f, 0x03a9, 0x03cf, 0x0093, 0x00bf, 0x003e, 0x003f,
|
||||
0x0043, 0x0045, 0x009e, 0x00a7, 0x00b9, 0x0194, 0x01a2, 0x01ba,
|
||||
0x01c3, 0x03a6, 0x03a7, 0x03bb, 0x03d4, 0x009f, 0x01a0, 0x008f,
|
||||
0x008d, 0x0090, 0x0098, 0x00a6, 0x00b6, 0x00c4, 0x019f, 0x01af,
|
||||
0x01bf, 0x0399, 0x03bf, 0x03b4, 0x03c9, 0x03e7, 0x00a8, 0x01b6,
|
||||
0x00ab, 0x00a4, 0x00aa, 0x00b2, 0x00c2, 0x00c5, 0x0198, 0x01a4,
|
||||
0x01b8, 0x038c, 0x03a4, 0x03c4, 0x03c6, 0x03dd, 0x03e8, 0x00ad,
|
||||
0x03af, 0x0192, 0x00bd, 0x00bc, 0x018e, 0x0197, 0x019a, 0x01a3,
|
||||
0x01b1, 0x038d, 0x0398, 0x03b7, 0x03d3, 0x03d1, 0x03db, 0x07dd,
|
||||
0x00b4, 0x03de, 0x01a9, 0x019b, 0x019c, 0x01a1, 0x01aa, 0x01ad,
|
||||
0x01b3, 0x038b, 0x03b2, 0x03b8, 0x03ce, 0x03e1, 0x03e0, 0x07d2,
|
||||
0x07e5, 0x00b7, 0x07e3, 0x01bb, 0x01a8, 0x01a6, 0x01b0, 0x01b2,
|
||||
0x01b7, 0x039b, 0x039a, 0x03ba, 0x03b5, 0x03d6, 0x07d7, 0x03e4,
|
||||
0x07d8, 0x07ea, 0x00ba, 0x07e8, 0x03a0, 0x01bd, 0x01b4, 0x038a,
|
||||
0x01c4, 0x0392, 0x03aa, 0x03b0, 0x03bc, 0x03d7, 0x07d4, 0x07dc,
|
||||
0x07db, 0x07d5, 0x07f0, 0x00c1, 0x07fb, 0x03c8, 0x03a3, 0x0395,
|
||||
0x039d, 0x03ac, 0x03ae, 0x03c5, 0x03d8, 0x03e2, 0x03e6, 0x07e4,
|
||||
0x07e7, 0x07e0, 0x07e9, 0x07f7, 0x0190, 0x07f2, 0x0393, 0x01be,
|
||||
0x01c0, 0x0394, 0x0397, 0x03ad, 0x03c3, 0x03c1, 0x03d2, 0x07da,
|
||||
0x07d9, 0x07df, 0x07eb, 0x07f4, 0x07fa, 0x0195, 0x07f8, 0x03bd,
|
||||
0x039c, 0x03ab, 0x03a8, 0x03b3, 0x03b9, 0x03d0, 0x03e3, 0x03e5,
|
||||
0x07e2, 0x07de, 0x07ed, 0x07f1, 0x07f9, 0x07fc, 0x0193, 0x0ffd,
|
||||
0x03dc, 0x03b6, 0x03c7, 0x03cc, 0x03cb, 0x03d9, 0x03da, 0x07d3,
|
||||
0x07e1, 0x07ee, 0x07ef, 0x07f5, 0x07f6, 0x0ffc, 0x0fff, 0x019d,
|
||||
0x01c2, 0x00b5, 0x00a1, 0x0096, 0x0097, 0x0095, 0x0099, 0x00a0,
|
||||
0x00a2, 0x00ac, 0x00a9, 0x00b1, 0x00b3, 0x00bb, 0x00c0, 0x018f,
|
||||
0x0004
|
||||
};
|
||||
static const uint8_t raac_hcb11_bits[289] = {
|
||||
4, 5, 6, 7, 8, 8, 9, 10, 10, 10, 11, 11, 12, 11, 12, 12,
|
||||
10, 5, 4, 5, 6, 7, 7, 8, 8, 9, 9, 9, 10, 10, 10, 10,
|
||||
11, 8, 6, 5, 5, 6, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10,
|
||||
10, 10, 8, 7, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 9, 10,
|
||||
10, 10, 10, 8, 8, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9,
|
||||
10, 10, 10, 10, 8, 8, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9,
|
||||
9, 10, 10, 10, 10, 8, 9, 8, 8, 8, 8, 8, 8, 8, 9, 9,
|
||||
9, 10, 10, 10, 10, 10, 8, 9, 8, 8, 8, 8, 8, 8, 9, 9,
|
||||
9, 10, 10, 10, 10, 10, 10, 8, 10, 9, 8, 8, 9, 9, 9, 9,
|
||||
9, 10, 10, 10, 10, 10, 10, 11, 8, 10, 9, 9, 9, 9, 9, 9,
|
||||
9, 10, 10, 10, 10, 10, 10, 11, 11, 8, 11, 9, 9, 9, 9, 9,
|
||||
9, 10, 10, 10, 10, 10, 11, 10, 11, 11, 8, 11, 10, 9, 9, 10,
|
||||
9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 8, 11, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 9, 11, 10, 9,
|
||||
9, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 9, 11, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 9, 12,
|
||||
10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 9,
|
||||
9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9,
|
||||
5
|
||||
};
|
||||
static const uint16_t raac_hcb_size[11] = {81,81,81,81,81,81,64,64,169,169,289};
|
||||
static const uint16_t *const raac_hcb_code[11] = {
|
||||
raac_hcb1_code, raac_hcb2_code, raac_hcb3_code, raac_hcb4_code, raac_hcb5_code, raac_hcb6_code, raac_hcb7_code, raac_hcb8_code, raac_hcb9_code, raac_hcb10_code, raac_hcb11_code
|
||||
};
|
||||
static const uint8_t *const raac_hcb_bits[11] = {
|
||||
raac_hcb1_bits, raac_hcb2_bits, raac_hcb3_bits, raac_hcb4_bits, raac_hcb5_bits, raac_hcb6_bits, raac_hcb7_bits, raac_hcb8_bits, raac_hcb9_bits, raac_hcb10_bits, raac_hcb11_bits
|
||||
};
|
||||
static const uint32_t raac_sf_code[121] = {
|
||||
0x3ffe8, 0x3ffe6, 0x3ffe7, 0x3ffe5, 0x7fff5, 0x7fff1, 0x7ffed, 0x7fff6,
|
||||
0x7ffee, 0x7ffef, 0x7fff0, 0x7fffc, 0x7fffd, 0x7ffff, 0x7fffe, 0x7fff7,
|
||||
0x7fff8, 0x7fffb, 0x7fff9, 0x3ffe4, 0x7fffa, 0x3ffe3, 0x1ffef, 0x1fff0,
|
||||
0x0fff5, 0x1ffee, 0x0fff2, 0x0fff3, 0x0fff4, 0x0fff1, 0x07ff6, 0x07ff7,
|
||||
0x03ff9, 0x03ff5, 0x03ff7, 0x03ff3, 0x03ff6, 0x03ff2, 0x01ff7, 0x01ff5,
|
||||
0x00ff9, 0x00ff7, 0x00ff6, 0x007f9, 0x00ff4, 0x007f8, 0x003f9, 0x003f7,
|
||||
0x003f5, 0x001f8, 0x001f7, 0x000fa, 0x000f8, 0x000f6, 0x00079, 0x0003a,
|
||||
0x00038, 0x0001a, 0x0000b, 0x00004, 0x00000, 0x0000a, 0x0000c, 0x0001b,
|
||||
0x00039, 0x0003b, 0x00078, 0x0007a, 0x000f7, 0x000f9, 0x001f6, 0x001f9,
|
||||
0x003f4, 0x003f6, 0x003f8, 0x007f5, 0x007f4, 0x007f6, 0x007f7, 0x00ff5,
|
||||
0x00ff8, 0x01ff4, 0x01ff6, 0x01ff8, 0x03ff8, 0x03ff4, 0x0fff0, 0x07ff4,
|
||||
0x0fff6, 0x07ff5, 0x3ffe2, 0x7ffd9, 0x7ffda, 0x7ffdb, 0x7ffdc, 0x7ffdd,
|
||||
0x7ffde, 0x7ffd8, 0x7ffd2, 0x7ffd3, 0x7ffd4, 0x7ffd5, 0x7ffd6, 0x7fff2,
|
||||
0x7ffdf, 0x7ffe7, 0x7ffe8, 0x7ffe9, 0x7ffea, 0x7ffeb, 0x7ffe6, 0x7ffe0,
|
||||
0x7ffe1, 0x7ffe2, 0x7ffe3, 0x7ffe4, 0x7ffe5, 0x7ffd7, 0x7ffec, 0x7fff4,
|
||||
0x7fff3
|
||||
};
|
||||
static const uint8_t raac_sf_bits[121] = {
|
||||
18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 18, 19, 18, 17, 17, 16, 17, 16, 16, 16, 16, 15, 15,
|
||||
14, 14, 14, 14, 14, 14, 13, 13, 12, 12, 12, 11, 12, 11, 10, 10,
|
||||
10, 9, 9, 8, 8, 8, 7, 6, 6, 5, 4, 3, 1, 4, 4, 5,
|
||||
6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11, 12,
|
||||
12, 13, 13, 13, 14, 14, 16, 15, 16, 15, 18, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19
|
||||
};
|
||||
static const uint16_t raac_swb_offset_1024_16[44] = {
|
||||
0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88,
|
||||
100, 112, 124, 136, 148, 160, 172, 184, 196, 212, 228, 244,
|
||||
260, 280, 300, 320, 344, 368, 396, 424, 456, 492, 532, 572,
|
||||
616, 664, 716, 772, 832, 896, 960, 1024
|
||||
};
|
||||
static const uint16_t raac_swb_offset_1024_24[48] = {
|
||||
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44,
|
||||
52, 60, 68, 76, 84, 92, 100, 108, 116, 124, 136, 148,
|
||||
160, 172, 188, 204, 220, 240, 260, 284, 308, 336, 364, 396,
|
||||
432, 468, 508, 552, 600, 652, 704, 768, 832, 896, 960, 1024
|
||||
};
|
||||
static const uint16_t raac_swb_offset_1024_32[52] = {
|
||||
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48,
|
||||
56, 64, 72, 80, 88, 96, 108, 120, 132, 144, 160, 176,
|
||||
196, 216, 240, 264, 292, 320, 352, 384, 416, 448, 480, 512,
|
||||
544, 576, 608, 640, 672, 704, 736, 768, 800, 832, 864, 896,
|
||||
928, 960, 992, 1024
|
||||
};
|
||||
static const uint16_t raac_swb_offset_1024_48[50] = {
|
||||
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48,
|
||||
56, 64, 72, 80, 88, 96, 108, 120, 132, 144, 160, 176,
|
||||
196, 216, 240, 264, 292, 320, 352, 384, 416, 448, 480, 512,
|
||||
544, 576, 608, 640, 672, 704, 736, 768, 800, 832, 864, 896,
|
||||
928, 1024
|
||||
};
|
||||
static const uint16_t raac_swb_offset_1024_64[48] = {
|
||||
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44,
|
||||
48, 52, 56, 64, 72, 80, 88, 100, 112, 124, 140, 156,
|
||||
172, 192, 216, 240, 268, 304, 344, 384, 424, 464, 504, 544,
|
||||
584, 624, 664, 704, 744, 784, 824, 864, 904, 944, 984, 1024
|
||||
};
|
||||
static const uint16_t raac_swb_offset_1024_8[41] = {
|
||||
0, 12, 24, 36, 48, 60, 72, 84, 96, 108, 120, 132,
|
||||
144, 156, 172, 188, 204, 220, 236, 252, 268, 288, 308, 328,
|
||||
348, 372, 396, 420, 448, 476, 508, 544, 580, 620, 664, 712,
|
||||
764, 820, 880, 944, 1024
|
||||
};
|
||||
static const uint16_t raac_swb_offset_1024_96[42] = {
|
||||
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44,
|
||||
48, 52, 56, 64, 72, 80, 88, 96, 108, 120, 132, 144,
|
||||
156, 172, 188, 212, 240, 276, 320, 384, 448, 512, 576, 640,
|
||||
704, 768, 832, 896, 960, 1024
|
||||
};
|
||||
static const uint16_t *const raac_swb_offset_1024[13] = {
|
||||
raac_swb_offset_1024_96, raac_swb_offset_1024_96, raac_swb_offset_1024_64,
|
||||
raac_swb_offset_1024_48, raac_swb_offset_1024_48, raac_swb_offset_1024_32,
|
||||
raac_swb_offset_1024_24, raac_swb_offset_1024_24, raac_swb_offset_1024_16,
|
||||
raac_swb_offset_1024_16, raac_swb_offset_1024_16, raac_swb_offset_1024_8,
|
||||
raac_swb_offset_1024_8
|
||||
};
|
||||
#include "raac_tables.h"
|
||||
|
||||
static const uint16_t raac_swb_offset_128_16[16] = {
|
||||
0, 4, 8, 12, 16, 20, 24, 28, 32, 40, 48, 60,
|
||||
72, 88, 108, 128
|
||||
@@ -693,9 +317,6 @@ static const uint16_t *const raac_swb_offset_128[13] = {
|
||||
raac_swb_offset_128_16, raac_swb_offset_128_16, raac_swb_offset_128_8,
|
||||
raac_swb_offset_128_8
|
||||
};
|
||||
static const uint8_t raac_num_swb_1024[13] = {
|
||||
41, 41, 47, 49, 49, 51, 47, 47, 43, 43, 43, 40, 40
|
||||
};
|
||||
static const uint8_t raac_num_swb_128[13] = {
|
||||
12, 12, 12, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15
|
||||
};
|
||||
@@ -709,10 +330,6 @@ static const uint8_t raac_tns_max_bands_128[13] = {
|
||||
9, 9, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14
|
||||
};
|
||||
|
||||
static const unsigned raac_sample_rates[13] = {
|
||||
96000, 88200, 64000, 48000, 44100, 32000,
|
||||
24000, 22050, 16000, 12000, 11025, 8000, 7350
|
||||
};
|
||||
|
||||
/* ===== bit reader (MSB first) ===== */
|
||||
|
||||
|
||||
@@ -0,0 +1,684 @@
|
||||
/* Copyright (C) 2010-2026 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (raac_encode.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* AAC-LC encoder. See raac_encode.h. Written from ISO/IEC 14496-3,
|
||||
* subpart 4, its tables shared with raac (raac_tables.h).
|
||||
*
|
||||
* The MDCT is a DCT-IV of the folded window, by a complex FFT of a
|
||||
* quarter its length. A band's scalefactor is sf = B + 2 log2(rms),
|
||||
* its step growing with the square root of the band's level: halfway
|
||||
* between the same noise in every band (the most signal-to-noise ratio
|
||||
* overall) and the same ratio in every band (quiet bands kept as well
|
||||
* as loud). B, one number a frame, is searched for the frame's bits;
|
||||
* no step is finer than 60 dB under the frame's loudest band. */
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <formats/raac_encode.h>
|
||||
|
||||
#include "raac_tables.h"
|
||||
|
||||
#define N 2048
|
||||
#define M 1024
|
||||
#define MAX_SFB 51
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float re, im;
|
||||
} cplx_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float prev[M]; /* the last frame's samples */
|
||||
float spec[M]; /* this frame's MDCT */
|
||||
int q[M]; /* its quantised values */
|
||||
int sf[MAX_SFB];
|
||||
uint8_t cb[MAX_SFB];
|
||||
int sf_floor; /* the frame's finest scalefactor */
|
||||
} enc_channel_t;
|
||||
|
||||
struct raac_encoder
|
||||
{
|
||||
raac_encoder_config_t cfg;
|
||||
unsigned sfi;
|
||||
unsigned num_swb, max_sfb;
|
||||
const uint16_t *swb;
|
||||
int debt; /* bits over the rate so far */
|
||||
int last_b; /* the last frame's B, where the search starts */
|
||||
bool flushed;
|
||||
|
||||
float window[N];
|
||||
cplx_t twiddle[M / 4]; /* the FFT's */
|
||||
cplx_t pre[M / 2], post[M / 2];
|
||||
uint16_t bitrev[M / 2];
|
||||
|
||||
enc_channel_t ch[2];
|
||||
|
||||
/* scratch */
|
||||
float x[N];
|
||||
cplx_t z[M / 2];
|
||||
|
||||
/* output */
|
||||
uint8_t *out;
|
||||
size_t cap, pos;
|
||||
uint32_t acc;
|
||||
unsigned nbits;
|
||||
bool overflow;
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Transform */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* In place, radix 2, M/2 points */
|
||||
static void fft(raac_encoder_t *e, cplx_t *z)
|
||||
{
|
||||
unsigned n = M / 2, i, len;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
unsigned j = e->bitrev[i];
|
||||
if (j > i)
|
||||
{
|
||||
cplx_t t = z[i];
|
||||
z[i] = z[j];
|
||||
z[j] = t;
|
||||
}
|
||||
}
|
||||
for (len = 2; len <= n; len <<= 1)
|
||||
{
|
||||
unsigned half = len / 2, step = n / len, k;
|
||||
for (i = 0; i < n; i += len)
|
||||
for (k = 0; k < half; k++)
|
||||
{
|
||||
cplx_t w = e->twiddle[k * step];
|
||||
cplx_t a = z[i + k], b = z[i + k + half], t;
|
||||
t.re = b.re * w.re - b.im * w.im;
|
||||
t.im = b.re * w.im + b.im * w.re;
|
||||
z[i + k].re = a.re + t.re;
|
||||
z[i + k].im = a.im + t.im;
|
||||
z[i + k + half].re = a.re - t.re;
|
||||
z[i + k + half].im = a.im - t.im;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The MDCT of N windowed samples into M coefficients:
|
||||
* X[k] = 2 sum x[n] cos(2 pi / N (n + 1/2 + N/4)(k + 1/2)) */
|
||||
/* sample @k of the fold, (-c_r - d, a - b_r) of the window's quarters */
|
||||
static float fold(const float *x, unsigned k)
|
||||
{
|
||||
return k < M / 2 ? -x[3 * M / 2 - 1 - k] - x[3 * M / 2 + k]
|
||||
: x[k - M / 2] - x[3 * M / 2 - 1 - k];
|
||||
}
|
||||
|
||||
static void mdct(raac_encoder_t *e, const float *x, float *out)
|
||||
{
|
||||
unsigned i;
|
||||
/* the DCT-IV of the fold by an M/2 point FFT, folded straight into
|
||||
* its input */
|
||||
for (i = 0; i < M / 2; i++)
|
||||
{
|
||||
float a = fold(x, 2 * i), b = fold(x, M - 1 - 2 * i);
|
||||
e->z[i].re = a * e->pre[i].re - b * e->pre[i].im;
|
||||
e->z[i].im = a * e->pre[i].im + b * e->pre[i].re;
|
||||
}
|
||||
fft(e, e->z);
|
||||
for (i = 0; i < M / 2; i++)
|
||||
{
|
||||
float re = e->z[i].re * e->post[i].re - e->z[i].im * e->post[i].im;
|
||||
float im = e->z[i].re * e->post[i].im + e->z[i].im * e->post[i].re;
|
||||
out[2 * i] = 2.0f * re;
|
||||
out[M - 1 - 2 * i] = -2.0f * im;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Setup */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
raac_encoder_t *raac_encoder_new(const raac_encoder_config_t *c)
|
||||
{
|
||||
raac_encoder_t *e;
|
||||
unsigned i, bits, cutoff, per_ch;
|
||||
|
||||
if (!c || (c->channels != 1 && c->channels != 2) || !c->bitrate)
|
||||
return NULL;
|
||||
for (i = 0; i < 13; i++)
|
||||
if (raac_sample_rates[i] == c->sample_rate)
|
||||
break;
|
||||
if (i == 13)
|
||||
return NULL;
|
||||
if (!(e = (raac_encoder_t*)calloc(1, sizeof(*e))))
|
||||
return NULL;
|
||||
e->cfg = *c;
|
||||
e->sfi = i;
|
||||
e->num_swb = raac_num_swb_1024[i];
|
||||
e->swb = raac_swb_offset_1024[i];
|
||||
|
||||
/* the bandwidth the rate allows a channel */
|
||||
per_ch = c->bitrate / c->channels;
|
||||
cutoff = per_ch >= 96000 ? 20000 : per_ch >= 64000 ? 16000
|
||||
: per_ch >= 48000 ? 13000 : per_ch >= 32000 ? 10000 : 7000;
|
||||
if (cutoff > c->sample_rate / 2)
|
||||
cutoff = c->sample_rate / 2;
|
||||
for (e->max_sfb = 0; e->max_sfb < e->num_swb; e->max_sfb++)
|
||||
if ((unsigned)e->swb[e->max_sfb] * c->sample_rate / (2 * M) >= cutoff)
|
||||
break;
|
||||
if (!e->max_sfb)
|
||||
e->max_sfb = 1;
|
||||
e->last_b = 60;
|
||||
|
||||
for (i = 0; i < N; i++)
|
||||
e->window[i] = (float)sin(M_PI * (i + 0.5) / N);
|
||||
for (i = 0; i < M / 4; i++)
|
||||
{
|
||||
e->twiddle[i].re = (float)cos(-2.0 * M_PI * i / (M / 2));
|
||||
e->twiddle[i].im = (float)sin(-2.0 * M_PI * i / (M / 2));
|
||||
}
|
||||
for (i = 0; i < M / 2; i++)
|
||||
{
|
||||
unsigned r = 0, k;
|
||||
for (k = 0, bits = i; k < 9; k++, bits >>= 1)
|
||||
r = (r << 1) | (bits & 1);
|
||||
e->bitrev[i] = (uint16_t)r;
|
||||
e->pre[i].re = (float)cos(-M_PI * (i + 0.25) / M);
|
||||
e->pre[i].im = (float)sin(-M_PI * (i + 0.25) / M);
|
||||
e->post[i].re = (float)cos(-M_PI * i / M);
|
||||
e->post[i].im = (float)sin(-M_PI * i / M);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
void raac_encoder_free(raac_encoder_t *e)
|
||||
{
|
||||
free(e);
|
||||
}
|
||||
|
||||
size_t raac_encoder_asc(const raac_encoder_t *e, uint8_t *dst, size_t cap)
|
||||
{
|
||||
if (!e || !dst || cap < 2)
|
||||
return 0;
|
||||
/* AAC LC (2), the rate's index, the channels; 1024-sample frames,
|
||||
* no core coder, no extension */
|
||||
dst[0] = (uint8_t)((2 << 3) | (e->sfi >> 1));
|
||||
dst[1] = (uint8_t)(((e->sfi & 1) << 7) | (e->cfg.channels << 3));
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Bits */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static void put_bits(raac_encoder_t *e, uint32_t v, unsigned n)
|
||||
{
|
||||
while (n)
|
||||
{
|
||||
unsigned k = n > 24 ? 24 : n;
|
||||
uint32_t part = (v >> (n - k)) & ((1u << k) - 1);
|
||||
e->acc = (e->acc << k) | part;
|
||||
e->nbits += k;
|
||||
n -= k;
|
||||
while (e->nbits >= 8)
|
||||
{
|
||||
e->nbits -= 8;
|
||||
if (e->pos < e->cap)
|
||||
e->out[e->pos++] = (uint8_t)(e->acc >> e->nbits);
|
||||
else
|
||||
e->overflow = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Quantisation and codebooks */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#define BIG 0x3FFFFFFF
|
||||
|
||||
static const uint8_t book_lav[12] = { 0, 1, 1, 2, 2, 4, 4, 7, 7, 12, 12, 16 };
|
||||
|
||||
/* A value's escape, for codebook 11: n ones, a zero, n + 4 bits */
|
||||
static unsigned esc_bits(int v)
|
||||
{
|
||||
unsigned n = 0;
|
||||
if (v < 16)
|
||||
return 0;
|
||||
while ((unsigned)v >= (32u << n))
|
||||
n++;
|
||||
return 2 * n + 5;
|
||||
}
|
||||
|
||||
/* Bits (or BIG) for a band's values in a codebook; with @put, codes them */
|
||||
static unsigned book_bits(raac_encoder_t *e, const int *q, unsigned w,
|
||||
unsigned cb, bool put)
|
||||
{
|
||||
const uint16_t *code = raac_hcb_code[cb - 1];
|
||||
const uint8_t *len = raac_hcb_bits[cb - 1];
|
||||
unsigned bits = 0, i;
|
||||
bool sign = cb == 3 || cb == 4 || cb >= 7;
|
||||
|
||||
if (cb <= 4)
|
||||
{
|
||||
for (i = 0; i < w; i += 4)
|
||||
{
|
||||
int a[4], k, idx = 0;
|
||||
for (k = 0; k < 4; k++)
|
||||
{
|
||||
a[k] = q[i + k];
|
||||
if (abs(a[k]) > book_lav[cb])
|
||||
return BIG;
|
||||
idx = idx * 3 + (sign ? abs(a[k]) : a[k] + 1);
|
||||
}
|
||||
bits += len[idx];
|
||||
if (put)
|
||||
put_bits(e, code[idx], len[idx]);
|
||||
if (sign)
|
||||
for (k = 0; k < 4; k++)
|
||||
if (a[k])
|
||||
{
|
||||
bits++;
|
||||
if (put)
|
||||
put_bits(e, a[k] < 0, 1);
|
||||
}
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
for (i = 0; i < w; i += 2)
|
||||
{
|
||||
int y = q[i], z = q[i + 1], idx, k, ay = abs(y), az = abs(z);
|
||||
if (cb <= 6)
|
||||
{
|
||||
if (ay > 4 || az > 4)
|
||||
return BIG;
|
||||
idx = 9 * (y + 4) + (z + 4);
|
||||
}
|
||||
else if (cb <= 10)
|
||||
{
|
||||
unsigned lav = cb <= 8 ? 8 : 13;
|
||||
if ((unsigned)ay >= lav || (unsigned)az >= lav)
|
||||
return BIG;
|
||||
idx = (int)lav * ay + az;
|
||||
}
|
||||
else
|
||||
idx = 17 * (ay > 16 ? 16 : ay) + (az > 16 ? 16 : az);
|
||||
bits += len[idx];
|
||||
if (put)
|
||||
put_bits(e, code[idx], len[idx]);
|
||||
if (sign)
|
||||
for (k = 0; k < 2; k++)
|
||||
{
|
||||
int v = k ? z : y;
|
||||
if (v)
|
||||
{
|
||||
bits++;
|
||||
if (put)
|
||||
put_bits(e, v < 0, 1);
|
||||
}
|
||||
}
|
||||
if (cb == 11)
|
||||
for (k = 0; k < 2; k++)
|
||||
{
|
||||
int v = k ? az : ay;
|
||||
unsigned eb = esc_bits(v);
|
||||
bits += eb;
|
||||
if (put && eb)
|
||||
{
|
||||
unsigned n = (eb - 5) / 2;
|
||||
put_bits(e, (1u << (n + 1)) - 2, n + 1); /* n ones, a zero */
|
||||
put_bits(e, (uint32_t)v - (16u << n), n + 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
/* The codebook that codes a band in the fewest bits; 0 if it is zero */
|
||||
static unsigned pick_book(raac_encoder_t *e, const int *q, unsigned w, unsigned *bits)
|
||||
{
|
||||
int m = 0;
|
||||
unsigned i, first, best = 0, best_bits = BIG, cb;
|
||||
for (i = 0; i < w; i++)
|
||||
if (abs(q[i]) > m)
|
||||
m = abs(q[i]);
|
||||
if (!m)
|
||||
{
|
||||
*bits = 0;
|
||||
return 0;
|
||||
}
|
||||
first = m <= 1 ? 1 : m <= 2 ? 3 : m <= 4 ? 5 : m <= 7 ? 7 : m <= 12 ? 9 : 11;
|
||||
for (cb = first; cb <= 11 && cb < first + 4; cb++)
|
||||
{
|
||||
unsigned b = book_bits(e, q, w, cb, false);
|
||||
if (b < best_bits)
|
||||
{
|
||||
best_bits = b;
|
||||
best = cb;
|
||||
}
|
||||
}
|
||||
*bits = best_bits;
|
||||
return best;
|
||||
}
|
||||
|
||||
/* The channel quantised at B: scalefactors, values, codebooks; returns
|
||||
* the bits its section, scalefactor and spectral data take */
|
||||
static unsigned quantise(raac_encoder_t *e, enc_channel_t *c, int B)
|
||||
{
|
||||
unsigned b, bits = 0;
|
||||
int prev = -1;
|
||||
|
||||
for (b = 0; b < e->max_sfb; b++)
|
||||
{
|
||||
unsigned s0 = e->swb[b], w = e->swb[b + 1] - s0, i, bb;
|
||||
double en = 0, mx = 0, gain;
|
||||
int sf;
|
||||
for (i = 0; i < w; i++)
|
||||
{
|
||||
double v = fabs(c->spec[s0 + i]);
|
||||
en += v * v;
|
||||
if (v > mx)
|
||||
mx = v;
|
||||
}
|
||||
if (mx < 1.0)
|
||||
{
|
||||
for (i = 0; i < w; i++)
|
||||
c->q[s0 + i] = 0;
|
||||
c->cb[b] = 0;
|
||||
continue;
|
||||
}
|
||||
sf = (int)floor(B + 2.0 * log(sqrt(en / w)) / log(2.0) + 0.5);
|
||||
/* no finer than the frame's floor: what lies that far under its
|
||||
* loudest band, or under the quietest 16-bit signal, is not heard */
|
||||
if (sf < c->sf_floor)
|
||||
sf = c->sf_floor;
|
||||
/* no value past 8191 */
|
||||
{
|
||||
int lo = (int)ceil(100 + 16.0 / 3.0 * (0.75 * log(mx) / log(2.0) - log(8191.0) / log(2.0)));
|
||||
if (sf < lo)
|
||||
sf = lo;
|
||||
}
|
||||
if (prev >= 0)
|
||||
{
|
||||
if (sf < prev - 60)
|
||||
sf = prev - 60;
|
||||
if (sf > prev + 60)
|
||||
sf = prev + 60;
|
||||
}
|
||||
if (sf < 0)
|
||||
sf = 0;
|
||||
if (sf > 255)
|
||||
sf = 255;
|
||||
gain = pow(2.0, -0.1875 * (sf - 100));
|
||||
for (i = 0; i < w; i++)
|
||||
{
|
||||
float v = c->spec[s0 + i];
|
||||
int l = (int)(pow(fabs(v), 0.75) * gain + 0.4054);
|
||||
if (l > 8191)
|
||||
l = 8191;
|
||||
c->q[s0 + i] = v < 0 ? -l : l;
|
||||
}
|
||||
c->cb[b] = (uint8_t)pick_book(e, c->q + s0, w, &bb);
|
||||
c->sf[b] = sf;
|
||||
if (!c->cb[b])
|
||||
continue;
|
||||
bits += bb;
|
||||
/* the scalefactor's delta */
|
||||
bits += raac_sf_bits[(prev < 0 ? 0 : sf - prev) + 60];
|
||||
prev = sf;
|
||||
}
|
||||
/* sections: a codebook, then its run in 5-bit pieces */
|
||||
for (b = 0; b < e->max_sfb; b++)
|
||||
{
|
||||
unsigned run = 1;
|
||||
while (b + 1 < e->max_sfb && c->cb[b + 1] == c->cb[b])
|
||||
{
|
||||
b++;
|
||||
run++;
|
||||
}
|
||||
bits += 4 + 5 * (run / 31 + 1);
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
static void write_ics_info(raac_encoder_t *e)
|
||||
{
|
||||
put_bits(e, 0, 1); /* ics_reserved_bit */
|
||||
put_bits(e, 0, 2); /* ONLY_LONG_SEQUENCE */
|
||||
put_bits(e, 0, 1); /* sine window */
|
||||
put_bits(e, e->max_sfb, 6);
|
||||
put_bits(e, 0, 1); /* no prediction */
|
||||
}
|
||||
|
||||
/* individual_channel_stream(): global_gain, ics_info unless a channel
|
||||
* pair's common window gave it, sections, scalefactors, no pulse, TNS
|
||||
* or gain control, the spectrum */
|
||||
static void write_ics(raac_encoder_t *e, enc_channel_t *c, bool info)
|
||||
{
|
||||
unsigned b, global = 100;
|
||||
int prev = -1;
|
||||
|
||||
for (b = 0; b < e->max_sfb; b++)
|
||||
if (c->cb[b])
|
||||
{
|
||||
global = (unsigned)c->sf[b];
|
||||
break;
|
||||
}
|
||||
put_bits(e, global, 8);
|
||||
if (info)
|
||||
write_ics_info(e);
|
||||
|
||||
for (b = 0; b < e->max_sfb; b++)
|
||||
{
|
||||
unsigned run = 1, cb = c->cb[b];
|
||||
while (b + 1 < e->max_sfb && c->cb[b + 1] == cb)
|
||||
{
|
||||
b++;
|
||||
run++;
|
||||
}
|
||||
put_bits(e, cb, 4);
|
||||
while (run >= 31)
|
||||
{
|
||||
put_bits(e, 31, 5);
|
||||
run -= 31;
|
||||
}
|
||||
put_bits(e, run, 5);
|
||||
}
|
||||
|
||||
for (b = 0; b < e->max_sfb; b++)
|
||||
{
|
||||
int d;
|
||||
if (!c->cb[b])
|
||||
continue;
|
||||
d = prev < 0 ? 0 : c->sf[b] - prev;
|
||||
put_bits(e, raac_sf_code[d + 60], raac_sf_bits[d + 60]);
|
||||
prev = c->sf[b];
|
||||
}
|
||||
put_bits(e, 0, 3); /* pulse, tns, gain control */
|
||||
|
||||
for (b = 0; b < e->max_sfb; b++)
|
||||
if (c->cb[b])
|
||||
{
|
||||
unsigned s0 = e->swb[b];
|
||||
book_bits(e, c->q + s0, e->swb[b + 1] - s0, c->cb[b], true);
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static size_t encode(raac_encoder_t *e, const int16_t *s16, const float *f32,
|
||||
uint8_t *dst, size_t cap, bool adts)
|
||||
{
|
||||
unsigned ch, i, n = e->cfg.channels;
|
||||
unsigned header = adts ? 7 : 0;
|
||||
int target, share, lo, hi, best_b, limit;
|
||||
unsigned bits_fixed = n == 1 ? 3 + 4 + 11 + 8 + 3 + 3
|
||||
: 3 + 4 + 1 + 11 + 2 + 2 * (8 + 3) + 3;
|
||||
|
||||
if (!e || !dst)
|
||||
return 0;
|
||||
if (!s16 && !f32)
|
||||
e->flushed = true;
|
||||
|
||||
for (ch = 0; ch < n; ch++)
|
||||
{
|
||||
enc_channel_t *c = &e->ch[ch];
|
||||
for (i = 0; i < M; i++)
|
||||
{
|
||||
float cur = s16 ? (float)s16[i * n + ch]
|
||||
: f32 ? f32[i * n + ch] * 32768.0f : 0.0f;
|
||||
e->x[i] = c->prev[i] * e->window[i];
|
||||
e->x[M + i] = cur * e->window[M + i];
|
||||
c->prev[i] = cur;
|
||||
}
|
||||
mdct(e, e->x, c->spec);
|
||||
|
||||
/* the floor: a step 60 dB under the loudest band's level, and at
|
||||
* least what a one-LSB sine comes to */
|
||||
{
|
||||
unsigned bb;
|
||||
double peak = 0;
|
||||
for (bb = 0; bb < e->max_sfb; bb++)
|
||||
{
|
||||
unsigned s0 = e->swb[bb], w = e->swb[bb + 1] - s0, k;
|
||||
double en = 0;
|
||||
for (k = 0; k < w; k++)
|
||||
en += (double)c->spec[s0 + k] * c->spec[s0 + k];
|
||||
if (en / w > peak)
|
||||
peak = en / w;
|
||||
}
|
||||
peak = sqrt(peak) * 0.001; /* -60 dB */
|
||||
if (peak < 64.0)
|
||||
peak = 64.0;
|
||||
c->sf_floor = (int)floor(100 + 4.0 * log(peak) / log(2.0) + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
/* the frame's bits: its share of the rate, the debt paid over eight
|
||||
* frames, within AAC's 6144 bits a channel */
|
||||
share = (int)((uint64_t)e->cfg.bitrate * M / e->cfg.sample_rate);
|
||||
target = share - e->debt / 8;
|
||||
limit = 6144 * (int)n - 8;
|
||||
if (target < share / 4)
|
||||
target = share / 4;
|
||||
if (target > limit)
|
||||
target = limit;
|
||||
|
||||
/* the largest B (coarsest) is never wanted; search for the smallest
|
||||
* B whose bits fit */
|
||||
lo = -120;
|
||||
hi = 255;
|
||||
best_b = hi;
|
||||
{
|
||||
int b0 = e->last_b;
|
||||
/* bisection over B, starting where the last frame ended */
|
||||
while (lo <= hi)
|
||||
{
|
||||
int mid = (lo + hi) / 2, total = (int)bits_fixed;
|
||||
if (b0 >= lo && b0 <= hi)
|
||||
{
|
||||
mid = b0;
|
||||
b0 = -1000;
|
||||
}
|
||||
for (ch = 0; ch < n; ch++)
|
||||
total += (int)quantise(e, &e->ch[ch], mid);
|
||||
if (total <= target)
|
||||
{
|
||||
best_b = mid;
|
||||
hi = mid - 1;
|
||||
}
|
||||
else
|
||||
lo = mid + 1;
|
||||
}
|
||||
}
|
||||
e->last_b = best_b;
|
||||
for (ch = 0; ch < n; ch++)
|
||||
quantise(e, &e->ch[ch], best_b);
|
||||
|
||||
e->out = dst;
|
||||
e->cap = cap;
|
||||
e->pos = 0;
|
||||
e->acc = 0;
|
||||
e->nbits = 0;
|
||||
e->overflow = false;
|
||||
if (adts)
|
||||
for (i = 0; i < 7; i++)
|
||||
put_bits(e, 0, 8); /* filled in below */
|
||||
|
||||
if (n == 1)
|
||||
{
|
||||
put_bits(e, 0, 3); /* ID_SCE */
|
||||
put_bits(e, 0, 4);
|
||||
write_ics(e, &e->ch[0], true);
|
||||
}
|
||||
else
|
||||
{
|
||||
put_bits(e, 1, 3); /* ID_CPE */
|
||||
put_bits(e, 0, 4);
|
||||
put_bits(e, 1, 1); /* common_window */
|
||||
write_ics_info(e);
|
||||
put_bits(e, 0, 2); /* no M/S */
|
||||
write_ics(e, &e->ch[0], false);
|
||||
write_ics(e, &e->ch[1], false);
|
||||
}
|
||||
put_bits(e, 7, 3); /* ID_END */
|
||||
if (e->nbits)
|
||||
put_bits(e, 0, 8 - e->nbits);
|
||||
if (e->overflow)
|
||||
return 0;
|
||||
|
||||
if (adts)
|
||||
{
|
||||
size_t len = e->pos;
|
||||
uint8_t *h = dst;
|
||||
h[0] = 0xFF;
|
||||
h[1] = 0xF1; /* MPEG-4, no CRC */
|
||||
h[2] = (uint8_t)((1 << 6) | (e->sfi << 2) | (n >> 2));
|
||||
h[3] = (uint8_t)(((n & 3) << 6) | ((len >> 11) & 3));
|
||||
h[4] = (uint8_t)(len >> 3);
|
||||
h[5] = (uint8_t)(((len & 7) << 5) | 0x1F);
|
||||
h[6] = 0xFC;
|
||||
}
|
||||
|
||||
e->debt += (int)((e->pos - header) * 8) - share;
|
||||
if (e->debt > 64 * share)
|
||||
e->debt = 64 * share;
|
||||
if (e->debt < -64 * share)
|
||||
e->debt = -64 * share;
|
||||
return e->pos;
|
||||
}
|
||||
|
||||
size_t raac_encoder_encode_s16(raac_encoder_t *e, const int16_t *pcm,
|
||||
uint8_t *dst, size_t cap, bool adts)
|
||||
{
|
||||
return encode(e, pcm, NULL, dst, cap, adts);
|
||||
}
|
||||
|
||||
size_t raac_encoder_encode_f32(raac_encoder_t *e, const float *pcm,
|
||||
uint8_t *dst, size_t cap, bool adts)
|
||||
{
|
||||
return encode(e, NULL, pcm, dst, cap, adts);
|
||||
}
|
||||
@@ -0,0 +1,420 @@
|
||||
/* Copyright (C) 2010-2026 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (raac_tables.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* The tables of ISO/IEC 14496-3 that raac decodes with and raac_encode
|
||||
* codes with: the spectral and scalefactor Huffman codebooks (Tables
|
||||
* 4.A.2 to 4.A.13), the long window's scalefactor bands (Tables 4.129
|
||||
* to 4.138) and the sampling frequency indices. Static data, for the two
|
||||
* files that include it. */
|
||||
|
||||
#ifndef __LIBRETRO_SDK_FORMAT_RAAC_TABLES_H
|
||||
#define __LIBRETRO_SDK_FORMAT_RAAC_TABLES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
static const uint16_t raac_hcb1_code[81] = {
|
||||
0x07f8, 0x01f1, 0x07fd, 0x03f5, 0x0068, 0x03f0, 0x07f7, 0x01ec,
|
||||
0x07f5, 0x03f1, 0x0072, 0x03f4, 0x0074, 0x0011, 0x0076, 0x01eb,
|
||||
0x006c, 0x03f6, 0x07fc, 0x01e1, 0x07f1, 0x01f0, 0x0061, 0x01f6,
|
||||
0x07f2, 0x01ea, 0x07fb, 0x01f2, 0x0069, 0x01ed, 0x0077, 0x0017,
|
||||
0x006f, 0x01e6, 0x0064, 0x01e5, 0x0067, 0x0015, 0x0062, 0x0012,
|
||||
0x0000, 0x0014, 0x0065, 0x0016, 0x006d, 0x01e9, 0x0063, 0x01e4,
|
||||
0x006b, 0x0013, 0x0071, 0x01e3, 0x0070, 0x01f3, 0x07fe, 0x01e7,
|
||||
0x07f3, 0x01ef, 0x0060, 0x01ee, 0x07f0, 0x01e2, 0x07fa, 0x03f3,
|
||||
0x006a, 0x01e8, 0x0075, 0x0010, 0x0073, 0x01f4, 0x006e, 0x03f7,
|
||||
0x07f6, 0x01e0, 0x07f9, 0x03f2, 0x0066, 0x01f5, 0x07ff, 0x01f7,
|
||||
0x07f4
|
||||
};
|
||||
static const uint8_t raac_hcb1_bits[81] = {
|
||||
11, 9, 11, 10, 7, 10, 11, 9, 11, 10, 7, 10, 7, 5, 7, 9,
|
||||
7, 10, 11, 9, 11, 9, 7, 9, 11, 9, 11, 9, 7, 9, 7, 5,
|
||||
7, 9, 7, 9, 7, 5, 7, 5, 1, 5, 7, 5, 7, 9, 7, 9,
|
||||
7, 5, 7, 9, 7, 9, 11, 9, 11, 9, 7, 9, 11, 9, 11, 10,
|
||||
7, 9, 7, 5, 7, 9, 7, 10, 11, 9, 11, 10, 7, 9, 11, 9,
|
||||
11
|
||||
};
|
||||
static const uint16_t raac_hcb2_code[81] = {
|
||||
0x01f3, 0x006f, 0x01fd, 0x00eb, 0x0023, 0x00ea, 0x01f7, 0x00e8,
|
||||
0x01fa, 0x00f2, 0x002d, 0x0070, 0x0020, 0x0006, 0x002b, 0x006e,
|
||||
0x0028, 0x00e9, 0x01f9, 0x0066, 0x00f8, 0x00e7, 0x001b, 0x00f1,
|
||||
0x01f4, 0x006b, 0x01f5, 0x00ec, 0x002a, 0x006c, 0x002c, 0x000a,
|
||||
0x0027, 0x0067, 0x001a, 0x00f5, 0x0024, 0x0008, 0x001f, 0x0009,
|
||||
0x0000, 0x0007, 0x001d, 0x000b, 0x0030, 0x00ef, 0x001c, 0x0064,
|
||||
0x001e, 0x000c, 0x0029, 0x00f3, 0x002f, 0x00f0, 0x01fc, 0x0071,
|
||||
0x01f2, 0x00f4, 0x0021, 0x00e6, 0x00f7, 0x0068, 0x01f8, 0x00ee,
|
||||
0x0022, 0x0065, 0x0031, 0x0002, 0x0026, 0x00ed, 0x0025, 0x006a,
|
||||
0x01fb, 0x0072, 0x01fe, 0x0069, 0x002e, 0x00f6, 0x01ff, 0x006d,
|
||||
0x01f6
|
||||
};
|
||||
static const uint8_t raac_hcb2_bits[81] = {
|
||||
9, 7, 9, 8, 6, 8, 9, 8, 9, 8, 6, 7, 6, 5, 6, 7,
|
||||
6, 8, 9, 7, 8, 8, 6, 8, 9, 7, 9, 8, 6, 7, 6, 5,
|
||||
6, 7, 6, 8, 6, 5, 6, 5, 3, 5, 6, 5, 6, 8, 6, 7,
|
||||
6, 5, 6, 8, 6, 8, 9, 7, 9, 8, 6, 8, 8, 7, 9, 8,
|
||||
6, 7, 6, 4, 6, 8, 6, 7, 9, 7, 9, 7, 6, 8, 9, 7,
|
||||
9
|
||||
};
|
||||
static const uint16_t raac_hcb3_code[81] = {
|
||||
0x0000, 0x0009, 0x00ef, 0x000b, 0x0019, 0x00f0, 0x01eb, 0x01e6,
|
||||
0x03f2, 0x000a, 0x0035, 0x01ef, 0x0034, 0x0037, 0x01e9, 0x01ed,
|
||||
0x01e7, 0x03f3, 0x01ee, 0x03ed, 0x1ffa, 0x01ec, 0x01f2, 0x07f9,
|
||||
0x07f8, 0x03f8, 0x0ff8, 0x0008, 0x0038, 0x03f6, 0x0036, 0x0075,
|
||||
0x03f1, 0x03eb, 0x03ec, 0x0ff4, 0x0018, 0x0076, 0x07f4, 0x0039,
|
||||
0x0074, 0x03ef, 0x01f3, 0x01f4, 0x07f6, 0x01e8, 0x03ea, 0x1ffc,
|
||||
0x00f2, 0x01f1, 0x0ffb, 0x03f5, 0x07f3, 0x0ffc, 0x00ee, 0x03f7,
|
||||
0x7ffe, 0x01f0, 0x07f5, 0x7ffd, 0x1ffb, 0x3ffa, 0xffff, 0x00f1,
|
||||
0x03f0, 0x3ffc, 0x01ea, 0x03ee, 0x3ffb, 0x0ff6, 0x0ffa, 0x7ffc,
|
||||
0x07f2, 0x0ff5, 0xfffe, 0x03f4, 0x07f7, 0x7ffb, 0x0ff7, 0x0ff9,
|
||||
0x7ffa
|
||||
};
|
||||
static const uint8_t raac_hcb3_bits[81] = {
|
||||
1, 4, 8, 4, 5, 8, 9, 9, 10, 4, 6, 9, 6, 6, 9, 9,
|
||||
9, 10, 9, 10, 13, 9, 9, 11, 11, 10, 12, 4, 6, 10, 6, 7,
|
||||
10, 10, 10, 12, 5, 7, 11, 6, 7, 10, 9, 9, 11, 9, 10, 13,
|
||||
8, 9, 12, 10, 11, 12, 8, 10, 15, 9, 11, 15, 13, 14, 16, 8,
|
||||
10, 14, 9, 10, 14, 12, 12, 15, 11, 12, 16, 10, 11, 15, 12, 12,
|
||||
15
|
||||
};
|
||||
static const uint16_t raac_hcb4_code[81] = {
|
||||
0x0007, 0x0016, 0x00f6, 0x0018, 0x0008, 0x00ef, 0x01ef, 0x00f3,
|
||||
0x07f8, 0x0019, 0x0017, 0x00ed, 0x0015, 0x0001, 0x00e2, 0x00f0,
|
||||
0x0070, 0x03f0, 0x01ee, 0x00f1, 0x07fa, 0x00ee, 0x00e4, 0x03f2,
|
||||
0x07f6, 0x03ef, 0x07fd, 0x0005, 0x0014, 0x00f2, 0x0009, 0x0004,
|
||||
0x00e5, 0x00f4, 0x00e8, 0x03f4, 0x0006, 0x0002, 0x00e7, 0x0003,
|
||||
0x0000, 0x006b, 0x00e3, 0x0069, 0x01f3, 0x00eb, 0x00e6, 0x03f6,
|
||||
0x006e, 0x006a, 0x01f4, 0x03ec, 0x01f0, 0x03f9, 0x00f5, 0x00ec,
|
||||
0x07fb, 0x00ea, 0x006f, 0x03f7, 0x07f9, 0x03f3, 0x0fff, 0x00e9,
|
||||
0x006d, 0x03f8, 0x006c, 0x0068, 0x01f5, 0x03ee, 0x01f2, 0x07f4,
|
||||
0x07f7, 0x03f1, 0x0ffe, 0x03ed, 0x01f1, 0x07f5, 0x07fe, 0x03f5,
|
||||
0x07fc
|
||||
};
|
||||
static const uint8_t raac_hcb4_bits[81] = {
|
||||
4, 5, 8, 5, 4, 8, 9, 8, 11, 5, 5, 8, 5, 4, 8, 8,
|
||||
7, 10, 9, 8, 11, 8, 8, 10, 11, 10, 11, 4, 5, 8, 4, 4,
|
||||
8, 8, 8, 10, 4, 4, 8, 4, 4, 7, 8, 7, 9, 8, 8, 10,
|
||||
7, 7, 9, 10, 9, 10, 8, 8, 11, 8, 7, 10, 11, 10, 12, 8,
|
||||
7, 10, 7, 7, 9, 10, 9, 11, 11, 10, 12, 10, 9, 11, 11, 10,
|
||||
11
|
||||
};
|
||||
static const uint16_t raac_hcb5_code[81] = {
|
||||
0x1fff, 0x0ff7, 0x07f4, 0x07e8, 0x03f1, 0x07ee, 0x07f9, 0x0ff8,
|
||||
0x1ffd, 0x0ffd, 0x07f1, 0x03e8, 0x01e8, 0x00f0, 0x01ec, 0x03ee,
|
||||
0x07f2, 0x0ffa, 0x0ff4, 0x03ef, 0x01f2, 0x00e8, 0x0070, 0x00ec,
|
||||
0x01f0, 0x03ea, 0x07f3, 0x07eb, 0x01eb, 0x00ea, 0x001a, 0x0008,
|
||||
0x0019, 0x00ee, 0x01ef, 0x07ed, 0x03f0, 0x00f2, 0x0073, 0x000b,
|
||||
0x0000, 0x000a, 0x0071, 0x00f3, 0x07e9, 0x07ef, 0x01ee, 0x00ef,
|
||||
0x0018, 0x0009, 0x001b, 0x00eb, 0x01e9, 0x07ec, 0x07f6, 0x03eb,
|
||||
0x01f3, 0x00ed, 0x0072, 0x00e9, 0x01f1, 0x03ed, 0x07f7, 0x0ff6,
|
||||
0x07f0, 0x03e9, 0x01ed, 0x00f1, 0x01ea, 0x03ec, 0x07f8, 0x0ff9,
|
||||
0x1ffc, 0x0ffc, 0x0ff5, 0x07ea, 0x03f3, 0x03f2, 0x07f5, 0x0ffb,
|
||||
0x1ffe
|
||||
};
|
||||
static const uint8_t raac_hcb5_bits[81] = {
|
||||
13, 12, 11, 11, 10, 11, 11, 12, 13, 12, 11, 10, 9, 8, 9, 10,
|
||||
11, 12, 12, 10, 9, 8, 7, 8, 9, 10, 11, 11, 9, 8, 5, 4,
|
||||
5, 8, 9, 11, 10, 8, 7, 4, 1, 4, 7, 8, 11, 11, 9, 8,
|
||||
5, 4, 5, 8, 9, 11, 11, 10, 9, 8, 7, 8, 9, 10, 11, 12,
|
||||
11, 10, 9, 8, 9, 10, 11, 12, 13, 12, 12, 11, 10, 10, 11, 12,
|
||||
13
|
||||
};
|
||||
static const uint16_t raac_hcb6_code[81] = {
|
||||
0x07fe, 0x03fd, 0x01f1, 0x01eb, 0x01f4, 0x01ea, 0x01f0, 0x03fc,
|
||||
0x07fd, 0x03f6, 0x01e5, 0x00ea, 0x006c, 0x0071, 0x0068, 0x00f0,
|
||||
0x01e6, 0x03f7, 0x01f3, 0x00ef, 0x0032, 0x0027, 0x0028, 0x0026,
|
||||
0x0031, 0x00eb, 0x01f7, 0x01e8, 0x006f, 0x002e, 0x0008, 0x0004,
|
||||
0x0006, 0x0029, 0x006b, 0x01ee, 0x01ef, 0x0072, 0x002d, 0x0002,
|
||||
0x0000, 0x0003, 0x002f, 0x0073, 0x01fa, 0x01e7, 0x006e, 0x002b,
|
||||
0x0007, 0x0001, 0x0005, 0x002c, 0x006d, 0x01ec, 0x01f9, 0x00ee,
|
||||
0x0030, 0x0024, 0x002a, 0x0025, 0x0033, 0x00ec, 0x01f2, 0x03f8,
|
||||
0x01e4, 0x00ed, 0x006a, 0x0070, 0x0069, 0x0074, 0x00f1, 0x03fa,
|
||||
0x07ff, 0x03f9, 0x01f6, 0x01ed, 0x01f8, 0x01e9, 0x01f5, 0x03fb,
|
||||
0x07fc
|
||||
};
|
||||
static const uint8_t raac_hcb6_bits[81] = {
|
||||
11, 10, 9, 9, 9, 9, 9, 10, 11, 10, 9, 8, 7, 7, 7, 8,
|
||||
9, 10, 9, 8, 6, 6, 6, 6, 6, 8, 9, 9, 7, 6, 4, 4,
|
||||
4, 6, 7, 9, 9, 7, 6, 4, 4, 4, 6, 7, 9, 9, 7, 6,
|
||||
4, 4, 4, 6, 7, 9, 9, 8, 6, 6, 6, 6, 6, 8, 9, 10,
|
||||
9, 8, 7, 7, 7, 7, 8, 10, 11, 10, 9, 9, 9, 9, 9, 10,
|
||||
11
|
||||
};
|
||||
static const uint16_t raac_hcb7_code[64] = {
|
||||
0x0000, 0x0005, 0x0037, 0x0074, 0x00f2, 0x01eb, 0x03ed, 0x07f7,
|
||||
0x0004, 0x000c, 0x0035, 0x0071, 0x00ec, 0x00ee, 0x01ee, 0x01f5,
|
||||
0x0036, 0x0034, 0x0072, 0x00ea, 0x00f1, 0x01e9, 0x01f3, 0x03f5,
|
||||
0x0073, 0x0070, 0x00eb, 0x00f0, 0x01f1, 0x01f0, 0x03ec, 0x03fa,
|
||||
0x00f3, 0x00ed, 0x01e8, 0x01ef, 0x03ef, 0x03f1, 0x03f9, 0x07fb,
|
||||
0x01ed, 0x00ef, 0x01ea, 0x01f2, 0x03f3, 0x03f8, 0x07f9, 0x07fc,
|
||||
0x03ee, 0x01ec, 0x01f4, 0x03f4, 0x03f7, 0x07f8, 0x0ffd, 0x0ffe,
|
||||
0x07f6, 0x03f0, 0x03f2, 0x03f6, 0x07fa, 0x07fd, 0x0ffc, 0x0fff
|
||||
};
|
||||
static const uint8_t raac_hcb7_bits[64] = {
|
||||
1, 3, 6, 7, 8, 9, 10, 11, 3, 4, 6, 7, 8, 8, 9, 9,
|
||||
6, 6, 7, 8, 8, 9, 9, 10, 7, 7, 8, 8, 9, 9, 10, 10,
|
||||
8, 8, 9, 9, 10, 10, 10, 11, 9, 8, 9, 9, 10, 10, 11, 11,
|
||||
10, 9, 9, 10, 10, 11, 12, 12, 11, 10, 10, 10, 11, 11, 12, 12
|
||||
};
|
||||
static const uint16_t raac_hcb8_code[64] = {
|
||||
0x000e, 0x0005, 0x0010, 0x0030, 0x006f, 0x00f1, 0x01fa, 0x03fe,
|
||||
0x0003, 0x0000, 0x0004, 0x0012, 0x002c, 0x006a, 0x0075, 0x00f8,
|
||||
0x000f, 0x0002, 0x0006, 0x0014, 0x002e, 0x0069, 0x0072, 0x00f5,
|
||||
0x002f, 0x0011, 0x0013, 0x002a, 0x0032, 0x006c, 0x00ec, 0x00fa,
|
||||
0x0071, 0x002b, 0x002d, 0x0031, 0x006d, 0x0070, 0x00f2, 0x01f9,
|
||||
0x00ef, 0x0068, 0x0033, 0x006b, 0x006e, 0x00ee, 0x00f9, 0x03fc,
|
||||
0x01f8, 0x0074, 0x0073, 0x00ed, 0x00f0, 0x00f6, 0x01f6, 0x01fd,
|
||||
0x03fd, 0x00f3, 0x00f4, 0x00f7, 0x01f7, 0x01fb, 0x01fc, 0x03ff
|
||||
};
|
||||
static const uint8_t raac_hcb8_bits[64] = {
|
||||
5, 4, 5, 6, 7, 8, 9, 10, 4, 3, 4, 5, 6, 7, 7, 8,
|
||||
5, 4, 4, 5, 6, 7, 7, 8, 6, 5, 5, 6, 6, 7, 8, 8,
|
||||
7, 6, 6, 6, 7, 7, 8, 9, 8, 7, 6, 7, 7, 8, 8, 10,
|
||||
9, 7, 7, 8, 8, 8, 9, 9, 10, 8, 8, 8, 9, 9, 9, 10
|
||||
};
|
||||
static const uint16_t raac_hcb9_code[169] = {
|
||||
0x0000, 0x0005, 0x0037, 0x00e7, 0x01de, 0x03ce, 0x03d9, 0x07c8,
|
||||
0x07cd, 0x0fc8, 0x0fdd, 0x1fe4, 0x1fec, 0x0004, 0x000c, 0x0035,
|
||||
0x0072, 0x00ea, 0x00ed, 0x01e2, 0x03d1, 0x03d3, 0x03e0, 0x07d8,
|
||||
0x0fcf, 0x0fd5, 0x0036, 0x0034, 0x0071, 0x00e8, 0x00ec, 0x01e1,
|
||||
0x03cf, 0x03dd, 0x03db, 0x07d0, 0x0fc7, 0x0fd4, 0x0fe4, 0x00e6,
|
||||
0x0070, 0x00e9, 0x01dd, 0x01e3, 0x03d2, 0x03dc, 0x07cc, 0x07ca,
|
||||
0x07de, 0x0fd8, 0x0fea, 0x1fdb, 0x01df, 0x00eb, 0x01dc, 0x01e6,
|
||||
0x03d5, 0x03de, 0x07cb, 0x07dd, 0x07dc, 0x0fcd, 0x0fe2, 0x0fe7,
|
||||
0x1fe1, 0x03d0, 0x01e0, 0x01e4, 0x03d6, 0x07c5, 0x07d1, 0x07db,
|
||||
0x0fd2, 0x07e0, 0x0fd9, 0x0feb, 0x1fe3, 0x1fe9, 0x07c4, 0x01e5,
|
||||
0x03d7, 0x07c6, 0x07cf, 0x07da, 0x0fcb, 0x0fda, 0x0fe3, 0x0fe9,
|
||||
0x1fe6, 0x1ff3, 0x1ff7, 0x07d3, 0x03d8, 0x03e1, 0x07d4, 0x07d9,
|
||||
0x0fd3, 0x0fde, 0x1fdd, 0x1fd9, 0x1fe2, 0x1fea, 0x1ff1, 0x1ff6,
|
||||
0x07d2, 0x03d4, 0x03da, 0x07c7, 0x07d7, 0x07e2, 0x0fce, 0x0fdb,
|
||||
0x1fd8, 0x1fee, 0x3ff0, 0x1ff4, 0x3ff2, 0x07e1, 0x03df, 0x07c9,
|
||||
0x07d6, 0x0fca, 0x0fd0, 0x0fe5, 0x0fe6, 0x1feb, 0x1fef, 0x3ff3,
|
||||
0x3ff4, 0x3ff5, 0x0fe0, 0x07ce, 0x07d5, 0x0fc6, 0x0fd1, 0x0fe1,
|
||||
0x1fe0, 0x1fe8, 0x1ff0, 0x3ff1, 0x3ff8, 0x3ff6, 0x7ffc, 0x0fe8,
|
||||
0x07df, 0x0fc9, 0x0fd7, 0x0fdc, 0x1fdc, 0x1fdf, 0x1fed, 0x1ff5,
|
||||
0x3ff9, 0x3ffb, 0x7ffd, 0x7ffe, 0x1fe7, 0x0fcc, 0x0fd6, 0x0fdf,
|
||||
0x1fde, 0x1fda, 0x1fe5, 0x1ff2, 0x3ffa, 0x3ff7, 0x3ffc, 0x3ffd,
|
||||
0x7fff
|
||||
};
|
||||
static const uint8_t raac_hcb9_bits[169] = {
|
||||
1, 3, 6, 8, 9, 10, 10, 11, 11, 12, 12, 13, 13, 3, 4, 6,
|
||||
7, 8, 8, 9, 10, 10, 10, 11, 12, 12, 6, 6, 7, 8, 8, 9,
|
||||
10, 10, 10, 11, 12, 12, 12, 8, 7, 8, 9, 9, 10, 10, 11, 11,
|
||||
11, 12, 12, 13, 9, 8, 9, 9, 10, 10, 11, 11, 11, 12, 12, 12,
|
||||
13, 10, 9, 9, 10, 11, 11, 11, 12, 11, 12, 12, 13, 13, 11, 9,
|
||||
10, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 11, 10, 10, 11, 11,
|
||||
12, 12, 13, 13, 13, 13, 13, 13, 11, 10, 10, 11, 11, 11, 12, 12,
|
||||
13, 13, 14, 13, 14, 11, 10, 11, 11, 12, 12, 12, 12, 13, 13, 14,
|
||||
14, 14, 12, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 12,
|
||||
11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 15, 15, 13, 12, 12, 12,
|
||||
13, 13, 13, 13, 14, 14, 14, 14, 15
|
||||
};
|
||||
static const uint16_t raac_hcb10_code[169] = {
|
||||
0x0022, 0x0008, 0x001d, 0x0026, 0x005f, 0x00d3, 0x01cf, 0x03d0,
|
||||
0x03d7, 0x03ed, 0x07f0, 0x07f6, 0x0ffd, 0x0007, 0x0000, 0x0001,
|
||||
0x0009, 0x0020, 0x0054, 0x0060, 0x00d5, 0x00dc, 0x01d4, 0x03cd,
|
||||
0x03de, 0x07e7, 0x001c, 0x0002, 0x0006, 0x000c, 0x001e, 0x0028,
|
||||
0x005b, 0x00cd, 0x00d9, 0x01ce, 0x01dc, 0x03d9, 0x03f1, 0x0025,
|
||||
0x000b, 0x000a, 0x000d, 0x0024, 0x0057, 0x0061, 0x00cc, 0x00dd,
|
||||
0x01cc, 0x01de, 0x03d3, 0x03e7, 0x005d, 0x0021, 0x001f, 0x0023,
|
||||
0x0027, 0x0059, 0x0064, 0x00d8, 0x00df, 0x01d2, 0x01e2, 0x03dd,
|
||||
0x03ee, 0x00d1, 0x0055, 0x0029, 0x0056, 0x0058, 0x0062, 0x00ce,
|
||||
0x00e0, 0x00e2, 0x01da, 0x03d4, 0x03e3, 0x07eb, 0x01c9, 0x005e,
|
||||
0x005a, 0x005c, 0x0063, 0x00ca, 0x00da, 0x01c7, 0x01ca, 0x01e0,
|
||||
0x03db, 0x03e8, 0x07ec, 0x01e3, 0x00d2, 0x00cb, 0x00d0, 0x00d7,
|
||||
0x00db, 0x01c6, 0x01d5, 0x01d8, 0x03ca, 0x03da, 0x07ea, 0x07f1,
|
||||
0x01e1, 0x00d4, 0x00cf, 0x00d6, 0x00de, 0x00e1, 0x01d0, 0x01d6,
|
||||
0x03d1, 0x03d5, 0x03f2, 0x07ee, 0x07fb, 0x03e9, 0x01cd, 0x01c8,
|
||||
0x01cb, 0x01d1, 0x01d7, 0x01df, 0x03cf, 0x03e0, 0x03ef, 0x07e6,
|
||||
0x07f8, 0x0ffa, 0x03eb, 0x01dd, 0x01d3, 0x01d9, 0x01db, 0x03d2,
|
||||
0x03cc, 0x03dc, 0x03ea, 0x07ed, 0x07f3, 0x07f9, 0x0ff9, 0x07f2,
|
||||
0x03ce, 0x01e4, 0x03cb, 0x03d8, 0x03d6, 0x03e2, 0x03e5, 0x07e8,
|
||||
0x07f4, 0x07f5, 0x07f7, 0x0ffb, 0x07fa, 0x03ec, 0x03df, 0x03e1,
|
||||
0x03e4, 0x03e6, 0x03f0, 0x07e9, 0x07ef, 0x0ff8, 0x0ffe, 0x0ffc,
|
||||
0x0fff
|
||||
};
|
||||
static const uint8_t raac_hcb10_bits[169] = {
|
||||
6, 5, 6, 6, 7, 8, 9, 10, 10, 10, 11, 11, 12, 5, 4, 4,
|
||||
5, 6, 7, 7, 8, 8, 9, 10, 10, 11, 6, 4, 5, 5, 6, 6,
|
||||
7, 8, 8, 9, 9, 10, 10, 6, 5, 5, 5, 6, 7, 7, 8, 8,
|
||||
9, 9, 10, 10, 7, 6, 6, 6, 6, 7, 7, 8, 8, 9, 9, 10,
|
||||
10, 8, 7, 6, 7, 7, 7, 8, 8, 8, 9, 10, 10, 11, 9, 7,
|
||||
7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 9, 8, 8, 8, 8,
|
||||
8, 9, 9, 9, 10, 10, 11, 11, 9, 8, 8, 8, 8, 8, 9, 9,
|
||||
10, 10, 10, 11, 11, 10, 9, 9, 9, 9, 9, 9, 10, 10, 10, 11,
|
||||
11, 12, 10, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 12, 11,
|
||||
10, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 12, 11, 10, 10, 10,
|
||||
10, 10, 10, 11, 11, 12, 12, 12, 12
|
||||
};
|
||||
static const uint16_t raac_hcb11_code[289] = {
|
||||
0x0000, 0x0006, 0x0019, 0x003d, 0x009c, 0x00c6, 0x01a7, 0x0390,
|
||||
0x03c2, 0x03df, 0x07e6, 0x07f3, 0x0ffb, 0x07ec, 0x0ffa, 0x0ffe,
|
||||
0x038e, 0x0005, 0x0001, 0x0008, 0x0014, 0x0037, 0x0042, 0x0092,
|
||||
0x00af, 0x0191, 0x01a5, 0x01b5, 0x039e, 0x03c0, 0x03a2, 0x03cd,
|
||||
0x07d6, 0x00ae, 0x0017, 0x0007, 0x0009, 0x0018, 0x0039, 0x0040,
|
||||
0x008e, 0x00a3, 0x00b8, 0x0199, 0x01ac, 0x01c1, 0x03b1, 0x0396,
|
||||
0x03be, 0x03ca, 0x009d, 0x003c, 0x0015, 0x0016, 0x001a, 0x003b,
|
||||
0x0044, 0x0091, 0x00a5, 0x00be, 0x0196, 0x01ae, 0x01b9, 0x03a1,
|
||||
0x0391, 0x03a5, 0x03d5, 0x0094, 0x009a, 0x0036, 0x0038, 0x003a,
|
||||
0x0041, 0x008c, 0x009b, 0x00b0, 0x00c3, 0x019e, 0x01ab, 0x01bc,
|
||||
0x039f, 0x038f, 0x03a9, 0x03cf, 0x0093, 0x00bf, 0x003e, 0x003f,
|
||||
0x0043, 0x0045, 0x009e, 0x00a7, 0x00b9, 0x0194, 0x01a2, 0x01ba,
|
||||
0x01c3, 0x03a6, 0x03a7, 0x03bb, 0x03d4, 0x009f, 0x01a0, 0x008f,
|
||||
0x008d, 0x0090, 0x0098, 0x00a6, 0x00b6, 0x00c4, 0x019f, 0x01af,
|
||||
0x01bf, 0x0399, 0x03bf, 0x03b4, 0x03c9, 0x03e7, 0x00a8, 0x01b6,
|
||||
0x00ab, 0x00a4, 0x00aa, 0x00b2, 0x00c2, 0x00c5, 0x0198, 0x01a4,
|
||||
0x01b8, 0x038c, 0x03a4, 0x03c4, 0x03c6, 0x03dd, 0x03e8, 0x00ad,
|
||||
0x03af, 0x0192, 0x00bd, 0x00bc, 0x018e, 0x0197, 0x019a, 0x01a3,
|
||||
0x01b1, 0x038d, 0x0398, 0x03b7, 0x03d3, 0x03d1, 0x03db, 0x07dd,
|
||||
0x00b4, 0x03de, 0x01a9, 0x019b, 0x019c, 0x01a1, 0x01aa, 0x01ad,
|
||||
0x01b3, 0x038b, 0x03b2, 0x03b8, 0x03ce, 0x03e1, 0x03e0, 0x07d2,
|
||||
0x07e5, 0x00b7, 0x07e3, 0x01bb, 0x01a8, 0x01a6, 0x01b0, 0x01b2,
|
||||
0x01b7, 0x039b, 0x039a, 0x03ba, 0x03b5, 0x03d6, 0x07d7, 0x03e4,
|
||||
0x07d8, 0x07ea, 0x00ba, 0x07e8, 0x03a0, 0x01bd, 0x01b4, 0x038a,
|
||||
0x01c4, 0x0392, 0x03aa, 0x03b0, 0x03bc, 0x03d7, 0x07d4, 0x07dc,
|
||||
0x07db, 0x07d5, 0x07f0, 0x00c1, 0x07fb, 0x03c8, 0x03a3, 0x0395,
|
||||
0x039d, 0x03ac, 0x03ae, 0x03c5, 0x03d8, 0x03e2, 0x03e6, 0x07e4,
|
||||
0x07e7, 0x07e0, 0x07e9, 0x07f7, 0x0190, 0x07f2, 0x0393, 0x01be,
|
||||
0x01c0, 0x0394, 0x0397, 0x03ad, 0x03c3, 0x03c1, 0x03d2, 0x07da,
|
||||
0x07d9, 0x07df, 0x07eb, 0x07f4, 0x07fa, 0x0195, 0x07f8, 0x03bd,
|
||||
0x039c, 0x03ab, 0x03a8, 0x03b3, 0x03b9, 0x03d0, 0x03e3, 0x03e5,
|
||||
0x07e2, 0x07de, 0x07ed, 0x07f1, 0x07f9, 0x07fc, 0x0193, 0x0ffd,
|
||||
0x03dc, 0x03b6, 0x03c7, 0x03cc, 0x03cb, 0x03d9, 0x03da, 0x07d3,
|
||||
0x07e1, 0x07ee, 0x07ef, 0x07f5, 0x07f6, 0x0ffc, 0x0fff, 0x019d,
|
||||
0x01c2, 0x00b5, 0x00a1, 0x0096, 0x0097, 0x0095, 0x0099, 0x00a0,
|
||||
0x00a2, 0x00ac, 0x00a9, 0x00b1, 0x00b3, 0x00bb, 0x00c0, 0x018f,
|
||||
0x0004
|
||||
};
|
||||
static const uint8_t raac_hcb11_bits[289] = {
|
||||
4, 5, 6, 7, 8, 8, 9, 10, 10, 10, 11, 11, 12, 11, 12, 12,
|
||||
10, 5, 4, 5, 6, 7, 7, 8, 8, 9, 9, 9, 10, 10, 10, 10,
|
||||
11, 8, 6, 5, 5, 6, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10,
|
||||
10, 10, 8, 7, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 9, 10,
|
||||
10, 10, 10, 8, 8, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9,
|
||||
10, 10, 10, 10, 8, 8, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9,
|
||||
9, 10, 10, 10, 10, 8, 9, 8, 8, 8, 8, 8, 8, 8, 9, 9,
|
||||
9, 10, 10, 10, 10, 10, 8, 9, 8, 8, 8, 8, 8, 8, 9, 9,
|
||||
9, 10, 10, 10, 10, 10, 10, 8, 10, 9, 8, 8, 9, 9, 9, 9,
|
||||
9, 10, 10, 10, 10, 10, 10, 11, 8, 10, 9, 9, 9, 9, 9, 9,
|
||||
9, 10, 10, 10, 10, 10, 10, 11, 11, 8, 11, 9, 9, 9, 9, 9,
|
||||
9, 10, 10, 10, 10, 10, 11, 10, 11, 11, 8, 11, 10, 9, 9, 10,
|
||||
9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 8, 11, 10, 10, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 9, 11, 10, 9,
|
||||
9, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 9, 11, 10,
|
||||
10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 9, 12,
|
||||
10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 9,
|
||||
9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9,
|
||||
5
|
||||
};
|
||||
static const uint16_t raac_hcb_size[11] = {81,81,81,81,81,81,64,64,169,169,289};
|
||||
static const uint16_t *const raac_hcb_code[11] = {
|
||||
raac_hcb1_code, raac_hcb2_code, raac_hcb3_code, raac_hcb4_code, raac_hcb5_code, raac_hcb6_code, raac_hcb7_code, raac_hcb8_code, raac_hcb9_code, raac_hcb10_code, raac_hcb11_code
|
||||
};
|
||||
static const uint8_t *const raac_hcb_bits[11] = {
|
||||
raac_hcb1_bits, raac_hcb2_bits, raac_hcb3_bits, raac_hcb4_bits, raac_hcb5_bits, raac_hcb6_bits, raac_hcb7_bits, raac_hcb8_bits, raac_hcb9_bits, raac_hcb10_bits, raac_hcb11_bits
|
||||
};
|
||||
static const uint32_t raac_sf_code[121] = {
|
||||
0x3ffe8, 0x3ffe6, 0x3ffe7, 0x3ffe5, 0x7fff5, 0x7fff1, 0x7ffed, 0x7fff6,
|
||||
0x7ffee, 0x7ffef, 0x7fff0, 0x7fffc, 0x7fffd, 0x7ffff, 0x7fffe, 0x7fff7,
|
||||
0x7fff8, 0x7fffb, 0x7fff9, 0x3ffe4, 0x7fffa, 0x3ffe3, 0x1ffef, 0x1fff0,
|
||||
0x0fff5, 0x1ffee, 0x0fff2, 0x0fff3, 0x0fff4, 0x0fff1, 0x07ff6, 0x07ff7,
|
||||
0x03ff9, 0x03ff5, 0x03ff7, 0x03ff3, 0x03ff6, 0x03ff2, 0x01ff7, 0x01ff5,
|
||||
0x00ff9, 0x00ff7, 0x00ff6, 0x007f9, 0x00ff4, 0x007f8, 0x003f9, 0x003f7,
|
||||
0x003f5, 0x001f8, 0x001f7, 0x000fa, 0x000f8, 0x000f6, 0x00079, 0x0003a,
|
||||
0x00038, 0x0001a, 0x0000b, 0x00004, 0x00000, 0x0000a, 0x0000c, 0x0001b,
|
||||
0x00039, 0x0003b, 0x00078, 0x0007a, 0x000f7, 0x000f9, 0x001f6, 0x001f9,
|
||||
0x003f4, 0x003f6, 0x003f8, 0x007f5, 0x007f4, 0x007f6, 0x007f7, 0x00ff5,
|
||||
0x00ff8, 0x01ff4, 0x01ff6, 0x01ff8, 0x03ff8, 0x03ff4, 0x0fff0, 0x07ff4,
|
||||
0x0fff6, 0x07ff5, 0x3ffe2, 0x7ffd9, 0x7ffda, 0x7ffdb, 0x7ffdc, 0x7ffdd,
|
||||
0x7ffde, 0x7ffd8, 0x7ffd2, 0x7ffd3, 0x7ffd4, 0x7ffd5, 0x7ffd6, 0x7fff2,
|
||||
0x7ffdf, 0x7ffe7, 0x7ffe8, 0x7ffe9, 0x7ffea, 0x7ffeb, 0x7ffe6, 0x7ffe0,
|
||||
0x7ffe1, 0x7ffe2, 0x7ffe3, 0x7ffe4, 0x7ffe5, 0x7ffd7, 0x7ffec, 0x7fff4,
|
||||
0x7fff3
|
||||
};
|
||||
static const uint8_t raac_sf_bits[121] = {
|
||||
18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 18, 19, 18, 17, 17, 16, 17, 16, 16, 16, 16, 15, 15,
|
||||
14, 14, 14, 14, 14, 14, 13, 13, 12, 12, 12, 11, 12, 11, 10, 10,
|
||||
10, 9, 9, 8, 8, 8, 7, 6, 6, 5, 4, 3, 1, 4, 4, 5,
|
||||
6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11, 12,
|
||||
12, 13, 13, 13, 14, 14, 16, 15, 16, 15, 18, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19
|
||||
};
|
||||
static const uint16_t raac_swb_offset_1024_16[44] = {
|
||||
0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88,
|
||||
100, 112, 124, 136, 148, 160, 172, 184, 196, 212, 228, 244,
|
||||
260, 280, 300, 320, 344, 368, 396, 424, 456, 492, 532, 572,
|
||||
616, 664, 716, 772, 832, 896, 960, 1024
|
||||
};
|
||||
static const uint16_t raac_swb_offset_1024_24[48] = {
|
||||
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44,
|
||||
52, 60, 68, 76, 84, 92, 100, 108, 116, 124, 136, 148,
|
||||
160, 172, 188, 204, 220, 240, 260, 284, 308, 336, 364, 396,
|
||||
432, 468, 508, 552, 600, 652, 704, 768, 832, 896, 960, 1024
|
||||
};
|
||||
static const uint16_t raac_swb_offset_1024_32[52] = {
|
||||
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48,
|
||||
56, 64, 72, 80, 88, 96, 108, 120, 132, 144, 160, 176,
|
||||
196, 216, 240, 264, 292, 320, 352, 384, 416, 448, 480, 512,
|
||||
544, 576, 608, 640, 672, 704, 736, 768, 800, 832, 864, 896,
|
||||
928, 960, 992, 1024
|
||||
};
|
||||
static const uint16_t raac_swb_offset_1024_48[50] = {
|
||||
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48,
|
||||
56, 64, 72, 80, 88, 96, 108, 120, 132, 144, 160, 176,
|
||||
196, 216, 240, 264, 292, 320, 352, 384, 416, 448, 480, 512,
|
||||
544, 576, 608, 640, 672, 704, 736, 768, 800, 832, 864, 896,
|
||||
928, 1024
|
||||
};
|
||||
static const uint16_t raac_swb_offset_1024_64[48] = {
|
||||
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44,
|
||||
48, 52, 56, 64, 72, 80, 88, 100, 112, 124, 140, 156,
|
||||
172, 192, 216, 240, 268, 304, 344, 384, 424, 464, 504, 544,
|
||||
584, 624, 664, 704, 744, 784, 824, 864, 904, 944, 984, 1024
|
||||
};
|
||||
static const uint16_t raac_swb_offset_1024_8[41] = {
|
||||
0, 12, 24, 36, 48, 60, 72, 84, 96, 108, 120, 132,
|
||||
144, 156, 172, 188, 204, 220, 236, 252, 268, 288, 308, 328,
|
||||
348, 372, 396, 420, 448, 476, 508, 544, 580, 620, 664, 712,
|
||||
764, 820, 880, 944, 1024
|
||||
};
|
||||
static const uint16_t raac_swb_offset_1024_96[42] = {
|
||||
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44,
|
||||
48, 52, 56, 64, 72, 80, 88, 96, 108, 120, 132, 144,
|
||||
156, 172, 188, 212, 240, 276, 320, 384, 448, 512, 576, 640,
|
||||
704, 768, 832, 896, 960, 1024
|
||||
};
|
||||
static const uint16_t *const raac_swb_offset_1024[13] = {
|
||||
raac_swb_offset_1024_96, raac_swb_offset_1024_96, raac_swb_offset_1024_64,
|
||||
raac_swb_offset_1024_48, raac_swb_offset_1024_48, raac_swb_offset_1024_32,
|
||||
raac_swb_offset_1024_24, raac_swb_offset_1024_24, raac_swb_offset_1024_16,
|
||||
raac_swb_offset_1024_16, raac_swb_offset_1024_16, raac_swb_offset_1024_8,
|
||||
raac_swb_offset_1024_8
|
||||
};
|
||||
static const uint8_t raac_num_swb_1024[13] = {
|
||||
41, 41, 47, 49, 49, 51, 47, 47, 43, 43, 43, 40, 40
|
||||
};
|
||||
static const unsigned raac_sample_rates[13] = {
|
||||
96000, 88200, 64000, 48000, 44100, 32000,
|
||||
24000, 22050, 16000, 12000, 11025, 8000, 7350
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -127,6 +127,12 @@ static size_t audio_transfer_ogg_page(const uint8_t *buf, size_t size,
|
||||
#ifdef HAVE_RLPCM
|
||||
#include <formats/rlpcm.h>
|
||||
#endif
|
||||
#ifdef HAVE_RATRAC3
|
||||
#include <formats/ratrac3.h>
|
||||
#endif
|
||||
#ifdef HAVE_RATRAC3P
|
||||
#include <formats/ratrac3p.h>
|
||||
#endif
|
||||
#ifdef HAVE_RAAC
|
||||
#include <formats/raac.h>
|
||||
#ifdef HAVE_RMP4
|
||||
@@ -493,7 +499,8 @@ static size_t audio_transfer_ogg_page(const uint8_t *buf, size_t size,
|
||||
* audio_transfer_webm_audio_type), .ogg being ambiguous between Vorbis
|
||||
* and Opus in any case. */
|
||||
|
||||
#if defined(HAVE_RWAV) || defined(HAVE_RAC3)
|
||||
#if defined(HAVE_RWAV) || defined(HAVE_RAC3) || defined(HAVE_RATRAC3) \
|
||||
|| defined(HAVE_RATRAC3P)
|
||||
/* Unit-scale float (full scale +-1.0) to s16, the conversion raac
|
||||
* applies at its own edge, for the arms whose float arrives at unit
|
||||
* scale already (float WAV, AC-3). A float source can carry anything, including
|
||||
@@ -513,6 +520,12 @@ static int16_t audio_transfer_unit_to_s16(float unit)
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint32_t audio_transfer_le32(const uint8_t *p)
|
||||
{
|
||||
return (uint32_t)p[0] | ((uint32_t)p[1] << 8)
|
||||
| ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
|
||||
}
|
||||
|
||||
/* One transfer context per codec. Each backend keeps only what it needs;
|
||||
* the enum 'type' handed to every entry point selects which arm runs, the
|
||||
* same switch-dispatch pattern formats/image_transfer.c uses. */
|
||||
@@ -1407,6 +1420,337 @@ static int audio_transfer_ac3_read(struct audio_transfer_ac3 *a,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_RATRAC3) || defined(HAVE_RATRAC3P)
|
||||
/* ATRAC3 and ATRAC3plus: OpenMG files (.oma, .aa3: an optional "ea3"
|
||||
* tag, then the 96-byte EA3 header naming the codec and its frame
|
||||
* size) and WAVE files (.at3: format tag 270h, or FFFEh with the
|
||||
* ATRAC3plus sub-format). Frames are block_align bytes, 1024 samples a
|
||||
* channel for ATRAC3 and 2048 for ATRAC3plus, decoded one at a time
|
||||
* into a pending block the reads drain. Encrypted OpenMG is refused.
|
||||
*
|
||||
* ATRAC3plus decodes in Sony's order - FL FR FC, then the back pair,
|
||||
* the back centre or the side pair, and LFE last - which is put into
|
||||
* the WAV shape for the count, as the AC-3 arm does: 5.1, 6.1 and 7.1
|
||||
* reordered, 6.1's back pair in WAV 7's side slots (the fold treats
|
||||
* them alike), and 4.0's lone back centre split into a phantom pair at
|
||||
* -3 dB each, five channels out. A frame that does not parse comes out
|
||||
* as silence, the decoders keeping their history. */
|
||||
struct audio_transfer_atrac
|
||||
{
|
||||
const uint8_t *buf;
|
||||
size_t buf_size;
|
||||
size_t avail; /* resident prefix, 0 = all */
|
||||
size_t data, data_end;
|
||||
size_t pos; /* the next frame's offset */
|
||||
unsigned block_align;
|
||||
unsigned spf; /* samples a channel a frame */
|
||||
unsigned dec_channels; /* the stream's */
|
||||
unsigned channels; /* handed over, in the WAV shape */
|
||||
unsigned rate;
|
||||
bool plus;
|
||||
bool joint;
|
||||
bool identity;
|
||||
bool ended;
|
||||
signed char map[8]; /* output channel: the decoded one */
|
||||
float gain[8];
|
||||
#ifdef HAVE_RATRAC3
|
||||
ratrac3_t *d3;
|
||||
#endif
|
||||
#ifdef HAVE_RATRAC3P
|
||||
ratrac3p_t *d3p;
|
||||
#endif
|
||||
float *raw; /* spf * dec_channels */
|
||||
float *pend; /* spf * channels */
|
||||
size_t pend_n, pend_off;
|
||||
uint64_t total_frames;
|
||||
uint64_t frame_pos;
|
||||
};
|
||||
|
||||
static unsigned audio_transfer_be16(const uint8_t *p)
|
||||
{
|
||||
return ((unsigned)p[0] << 8) | p[1];
|
||||
}
|
||||
|
||||
/* The container: codec, frame size, rate and where the frames are */
|
||||
static bool audio_transfer_atrac_parse(struct audio_transfer_atrac *a)
|
||||
{
|
||||
static const unsigned rates[8] = { 32000, 44100, 48000, 88200, 96000, 0, 0, 0 };
|
||||
static const unsigned plus_ch[8] = { 0, 1, 2, 3, 4, 6, 7, 8 };
|
||||
const uint8_t *b = a->buf;
|
||||
size_t n = a->buf_size, off = 0;
|
||||
|
||||
if (n >= 12 && !memcmp(b, "RIFF", 4) && !memcmp(b + 8, "WAVE", 4))
|
||||
{
|
||||
size_t c = 12;
|
||||
bool fmt = false;
|
||||
while (c + 8 <= n)
|
||||
{
|
||||
size_t len = audio_transfer_le32(b + c + 4);
|
||||
if (len > n - c - 8)
|
||||
len = n - c - 8;
|
||||
if (!memcmp(b + c, "fmt ", 4))
|
||||
{
|
||||
#ifdef HAVE_RATRAC3P
|
||||
ratrac3p_info_t pi;
|
||||
if (ratrac3p_parse_wave_fmt(b + c + 8, len, &pi))
|
||||
{
|
||||
a->plus = true; a->dec_channels = pi.channels;
|
||||
a->rate = pi.sample_rate; a->block_align = pi.block_align;
|
||||
fmt = true;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_RATRAC3
|
||||
if (!fmt)
|
||||
{
|
||||
ratrac3_info_t ti;
|
||||
if (ratrac3_parse_wave_fmt(b + c + 8, len, &ti))
|
||||
{
|
||||
a->plus = false; a->dec_channels = ti.channels;
|
||||
a->rate = ti.sample_rate; a->block_align = ti.block_align;
|
||||
a->joint = ti.joint_stereo;
|
||||
fmt = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!fmt)
|
||||
return false;
|
||||
}
|
||||
else if (!memcmp(b + c, "data", 4) && fmt)
|
||||
{
|
||||
a->data = c + 8;
|
||||
a->data_end = c + 8 + len;
|
||||
return true;
|
||||
}
|
||||
c += 8 + len + (len & 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* OpenMG: "ea3" tag (an ID3v2.3 tag by another name), then "EA3" */
|
||||
if (n >= 10 && !memcmp(b, "ea3", 3))
|
||||
off = 10 + (((size_t)(b[6] & 0x7f) << 21) | ((size_t)(b[7] & 0x7f) << 14)
|
||||
| ((size_t)(b[8] & 0x7f) << 7) | (b[9] & 0x7f));
|
||||
if (off > n || n - off < 96 || memcmp(b + off, "EA3", 3))
|
||||
return false;
|
||||
{
|
||||
const uint8_t *h = b + off;
|
||||
unsigned hsize = audio_transfer_be16(h + 4);
|
||||
unsigned eid = audio_transfer_be16(h + 6);
|
||||
unsigned codec = h[32];
|
||||
uint32_t params = ((uint32_t)h[33] << 16) | ((uint32_t)h[34] << 8) | h[35];
|
||||
if (eid != 0xFFFF && eid != 0xFF80)
|
||||
return false; /* encrypted */
|
||||
if (hsize < 96 || hsize > n - off)
|
||||
return false;
|
||||
a->rate = rates[(params >> 13) & 7];
|
||||
switch (codec)
|
||||
{
|
||||
#ifdef HAVE_RATRAC3
|
||||
case 0:
|
||||
a->plus = false;
|
||||
a->dec_channels = 2;
|
||||
a->joint = ((params >> 17) & 1) != 0;
|
||||
a->block_align = (unsigned)(params & 0x3FF) * 8;
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_RATRAC3P
|
||||
case 1:
|
||||
a->plus = true;
|
||||
a->dec_channels = plus_ch[(params >> 10) & 7];
|
||||
a->block_align = (unsigned)(params & 0x3FF) * 8 + 8;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
a->data = off + hsize;
|
||||
a->data_end = n;
|
||||
}
|
||||
(void)plus_ch;
|
||||
return a->rate && a->dec_channels && a->block_align;
|
||||
}
|
||||
|
||||
/* the WAV shape for ATRAC3plus's channel count (see above) */
|
||||
static void audio_transfer_atrac_map(struct audio_transfer_atrac *a)
|
||||
{
|
||||
static const signed char maps[9][8] = {
|
||||
{ 0 }, { 0 }, { 0, 1 }, { 0, 1, 2 },
|
||||
{ 0, 1, 2, 3, 3 }, /* FL FR FC BC: BC split */
|
||||
{ 0 },
|
||||
{ 0, 1, 2, 5, 3, 4 }, /* FL FR FC BL BR LFE */
|
||||
{ 0, 1, 2, 6, 5, 3, 4 }, /* FL FR FC BL BR BC LFE */
|
||||
{ 0, 1, 2, 7, 3, 4, 5, 6 } /* FL FR FC BL BR SL SR LFE */
|
||||
};
|
||||
unsigned i, n = a->dec_channels;
|
||||
a->channels = n == 4 ? 5 : n;
|
||||
for (i = 0; i < a->channels; i++)
|
||||
{
|
||||
a->map[i] = a->plus ? maps[n][i] : (signed char)i;
|
||||
a->gain[i] = (a->plus && n == 4 && i >= 3) ? 0.70710678f : 1.0f;
|
||||
}
|
||||
a->identity = true;
|
||||
for (i = 0; i < a->channels; i++)
|
||||
if (a->map[i] != (signed char)i || a->gain[i] != 1.0f)
|
||||
a->identity = false;
|
||||
if (a->channels != n)
|
||||
a->identity = false;
|
||||
}
|
||||
|
||||
static size_t audio_transfer_atrac_end(const struct audio_transfer_atrac *a)
|
||||
{
|
||||
size_t end = a->data_end;
|
||||
if (a->avail && a->avail < end)
|
||||
end = a->avail;
|
||||
return end;
|
||||
}
|
||||
|
||||
/* Decodes the frame at pos into @fdst (floats) or @sdst (s16) in the
|
||||
* WAV shape and advances pos: 1 with @frames, 0 at the end of the
|
||||
* frames or the frontier */
|
||||
static int audio_transfer_atrac_next_into(struct audio_transfer_atrac *a,
|
||||
float *fdst, int16_t *sdst, size_t *frames)
|
||||
{
|
||||
size_t end = audio_transfer_atrac_end(a), i;
|
||||
float *dec;
|
||||
unsigned c;
|
||||
int r = -1;
|
||||
if (a->pos >= end || a->block_align > end - a->pos)
|
||||
return 0;
|
||||
dec = (a->identity && fdst) ? fdst : a->raw;
|
||||
#ifdef HAVE_RATRAC3P
|
||||
if (a->plus)
|
||||
r = ratrac3p_decode_float(a->d3p, a->buf + a->pos, a->block_align, dec);
|
||||
#endif
|
||||
#ifdef HAVE_RATRAC3
|
||||
if (!a->plus)
|
||||
r = ratrac3_decode_float(a->d3, a->buf + a->pos, a->block_align, dec);
|
||||
#endif
|
||||
(void)r; /* a frame that does not parse is silence */
|
||||
if (dec != fdst)
|
||||
{
|
||||
if (a->identity)
|
||||
for (i = 0; i < (size_t)a->spf * a->channels; i++)
|
||||
sdst[i] = audio_transfer_unit_to_s16(a->raw[i]);
|
||||
else
|
||||
for (i = 0; i < a->spf; i++)
|
||||
{
|
||||
const float *in = a->raw + i * a->dec_channels;
|
||||
for (c = 0; c < a->channels; c++)
|
||||
{
|
||||
float v = in[a->map[c]] * a->gain[c];
|
||||
if (fdst)
|
||||
fdst[i * a->channels + c] = v;
|
||||
else
|
||||
sdst[i * a->channels + c] = audio_transfer_unit_to_s16(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
a->pos += a->block_align;
|
||||
*frames = a->spf;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int audio_transfer_atrac_read(struct audio_transfer_atrac *a,
|
||||
float *out_f32, int16_t *out_s16, size_t frames, size_t *frames_out)
|
||||
{
|
||||
size_t produced = 0;
|
||||
if (!a || !a->raw)
|
||||
return AUDIO_PROCESS_ERROR;
|
||||
while (produced < frames)
|
||||
{
|
||||
size_t take, i, n;
|
||||
const float *src;
|
||||
if (a->pend_off >= a->pend_n)
|
||||
{
|
||||
size_t got = 0;
|
||||
int r;
|
||||
if (a->ended)
|
||||
break;
|
||||
/* room for a whole frame: straight into the caller's buffer */
|
||||
if (frames - produced >= a->spf)
|
||||
{
|
||||
r = audio_transfer_atrac_next_into(a,
|
||||
out_f32 ? out_f32 + produced * a->channels : NULL,
|
||||
out_f32 ? NULL : out_s16 + produced * a->channels, &got);
|
||||
if (r == 1)
|
||||
{
|
||||
a->frame_pos += got;
|
||||
produced += got;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
r = audio_transfer_atrac_next_into(a, a->pend, NULL, &got);
|
||||
if (r == 1)
|
||||
{
|
||||
a->pend_n = got;
|
||||
a->pend_off = 0;
|
||||
}
|
||||
}
|
||||
if (r == 0)
|
||||
{
|
||||
if (audio_transfer_atrac_end(a) >= a->data_end)
|
||||
a->ended = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
take = a->pend_n - a->pend_off;
|
||||
if (take > frames - produced)
|
||||
take = frames - produced;
|
||||
src = a->pend + a->pend_off * a->channels;
|
||||
n = take * a->channels;
|
||||
if (out_f32)
|
||||
memcpy(out_f32 + produced * a->channels, src, n * sizeof(float));
|
||||
else
|
||||
for (i = 0; i < n; i++)
|
||||
out_s16[produced * a->channels + i] = audio_transfer_unit_to_s16(src[i]);
|
||||
a->pend_off += take;
|
||||
a->frame_pos += take;
|
||||
produced += take;
|
||||
}
|
||||
if (frames_out)
|
||||
*frames_out = produced;
|
||||
if (produced == 0 && a->ended)
|
||||
return AUDIO_PROCESS_END;
|
||||
return AUDIO_PROCESS_NEXT;
|
||||
}
|
||||
|
||||
/* Fresh history: the frame before the target decoded and dropped, so
|
||||
* the overlap is what a playthrough would have left */
|
||||
static bool audio_transfer_atrac_seek_to(struct audio_transfer_atrac *a, uint64_t frame)
|
||||
{
|
||||
uint64_t index = frame / a->spf;
|
||||
size_t got;
|
||||
if (frame >= a->total_frames)
|
||||
return false;
|
||||
#ifdef HAVE_RATRAC3P
|
||||
if (a->plus)
|
||||
ratrac3p_reset(a->d3p);
|
||||
#endif
|
||||
#ifdef HAVE_RATRAC3
|
||||
if (!a->plus)
|
||||
ratrac3_reset(a->d3);
|
||||
#endif
|
||||
a->ended = false;
|
||||
a->pend_n = a->pend_off = 0;
|
||||
if (index)
|
||||
{
|
||||
a->pos = a->data + (size_t)(index - 1) * a->block_align;
|
||||
audio_transfer_atrac_next_into(a, a->pend, NULL, &got);
|
||||
}
|
||||
a->pos = a->data + (size_t)index * a->block_align;
|
||||
a->frame_pos = index * a->spf;
|
||||
if (audio_transfer_atrac_next_into(a, a->pend, NULL, &got) == 1)
|
||||
{
|
||||
a->pend_n = got;
|
||||
a->pend_off = (size_t)(frame - a->frame_pos);
|
||||
a->frame_pos = frame;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RAAC
|
||||
struct audio_transfer_aac
|
||||
{
|
||||
@@ -1577,6 +1921,10 @@ void *audio_transfer_new(enum audio_type_enum type)
|
||||
case AUDIO_TYPE_AAC:
|
||||
return calloc(1, sizeof(struct audio_transfer_aac));
|
||||
#endif
|
||||
#if defined(HAVE_RATRAC3) || defined(HAVE_RATRAC3P)
|
||||
case AUDIO_TYPE_ATRAC:
|
||||
return calloc(1, sizeof(struct audio_transfer_atrac));
|
||||
#endif
|
||||
#ifdef HAVE_RAC3
|
||||
case AUDIO_TYPE_AC3:
|
||||
return calloc(1, sizeof(struct audio_transfer_ac3));
|
||||
@@ -1682,6 +2030,18 @@ void audio_transfer_set_buffer_ptr(void *data, enum audio_type_enum type,
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_RATRAC3) || defined(HAVE_RATRAC3P)
|
||||
case AUDIO_TYPE_ATRAC:
|
||||
{
|
||||
struct audio_transfer_atrac *a = (struct audio_transfer_atrac*)data;
|
||||
if (a)
|
||||
{
|
||||
a->buf = (const uint8_t*)ptr;
|
||||
a->buf_size = len;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_RAC3
|
||||
case AUDIO_TYPE_AC3:
|
||||
{
|
||||
@@ -2387,6 +2747,15 @@ void audio_transfer_set_avail(void *data, enum audio_type_enum type,
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_RATRAC3) || defined(HAVE_RATRAC3P)
|
||||
case AUDIO_TYPE_ATRAC:
|
||||
{
|
||||
struct audio_transfer_atrac *a = (struct audio_transfer_atrac*)data;
|
||||
if (a)
|
||||
a->avail = avail;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_RAC3
|
||||
case AUDIO_TYPE_AC3:
|
||||
{
|
||||
@@ -2569,6 +2938,228 @@ enum audio_type_enum audio_transfer_webm_audio_type(const void *buf,
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ---- a file's arm from its bytes ------------------------------------ */
|
||||
|
||||
#ifdef HAVE_RMP3
|
||||
/* An MPEG audio frame header's frame length (layers I to III, MPEG-1,
|
||||
* 2 and 2.5), 0 when @h is not one; free format is not taken */
|
||||
static size_t audio_transfer_mpa_len(const uint8_t *h)
|
||||
{
|
||||
static const uint16_t kbps[2][3][15] = {
|
||||
{ { 0,32,64,96,128,160,192,224,256,288,320,352,384,416,448 },
|
||||
{ 0,32,48,56,64,80,96,112,128,160,192,224,256,320,384 },
|
||||
{ 0,32,40,48,56,64,80,96,112,128,160,192,224,256,320 } },
|
||||
{ { 0,32,48,56,64,80,96,112,128,144,160,176,192,224,256 },
|
||||
{ 0,8,16,24,32,40,48,56,64,80,96,112,128,144,160 },
|
||||
{ 0,8,16,24,32,40,48,56,64,80,96,112,128,144,160 } }
|
||||
};
|
||||
static const uint16_t rates[3] = { 44100, 48000, 32000 };
|
||||
unsigned ver, layer, bi, si, pad, rate, lsf;
|
||||
uint32_t br;
|
||||
if (h[0] != 0xFF || (h[1] & 0xE0) != 0xE0)
|
||||
return 0;
|
||||
ver = (h[1] >> 3) & 3; /* 0 MPEG-2.5, 1 reserved, 2 MPEG-2, 3 MPEG-1 */
|
||||
layer = 4 - ((h[1] >> 1) & 3);
|
||||
bi = h[2] >> 4;
|
||||
si = (h[2] >> 2) & 3;
|
||||
pad = (h[2] >> 1) & 1;
|
||||
if (ver == 1 || layer == 4 || bi == 0 || bi == 15 || si == 3)
|
||||
return 0;
|
||||
lsf = ver != 3;
|
||||
rate = rates[si] >> (ver == 3 ? 0 : ver == 2 ? 1 : 2);
|
||||
br = (uint32_t)kbps[lsf][layer - 1][bi] * 1000;
|
||||
if (layer == 1)
|
||||
return (size_t)((12 * br / rate + pad) * 4);
|
||||
if (layer == 3 && lsf)
|
||||
return (size_t)(72 * br / rate + pad);
|
||||
return (size_t)(144 * br / rate + pad);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The length of the raw-stream frame at @p of @type's syntax, 0 when
|
||||
* there is none there */
|
||||
static size_t audio_transfer_raw_frame(const uint8_t *p, size_t n,
|
||||
enum audio_type_enum type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
#ifdef HAVE_RMP3
|
||||
case AUDIO_TYPE_MP3:
|
||||
return n >= 4 ? audio_transfer_mpa_len(p) : 0;
|
||||
#endif
|
||||
#ifdef HAVE_RAAC
|
||||
case AUDIO_TYPE_AAC:
|
||||
{
|
||||
raac_adts_t h;
|
||||
return raac_adts_parse(p, n, &h) == 0 ? h.frame_size : 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_RAC3
|
||||
case AUDIO_TYPE_AC3:
|
||||
{
|
||||
rac3_frame_info_t info;
|
||||
return rac3_parse_frame_info(p, n, &info) == RAC3_OK
|
||||
? info.frame_bytes : 0;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
(void)p; (void)n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum audio_type_enum audio_transfer_sniff_type(const void *buf, size_t len,
|
||||
size_t *skip)
|
||||
{
|
||||
const uint8_t *b = (const uint8_t*)buf;
|
||||
size_t at = 0, i;
|
||||
if (skip)
|
||||
*skip = 0;
|
||||
if (!b)
|
||||
return AUDIO_TYPE_NONE;
|
||||
|
||||
#if defined(HAVE_RATRAC3) || defined(HAVE_RATRAC3P)
|
||||
/* OpenMG: its "ea3" tag, or the EA3 header itself; the arm reads
|
||||
* both */
|
||||
if (len >= 10 && (!memcmp(b, "ea3", 3) || !memcmp(b, "EA3", 3)))
|
||||
return AUDIO_TYPE_ATRAC;
|
||||
#endif
|
||||
|
||||
/* ID3v2 tags in front of a stream, each 10 bytes, a syncsafe size
|
||||
* and 10 more for a footer */
|
||||
while (len - at >= 10 && !memcmp(b + at, "ID3", 3) && b[at + 3] != 0xFF
|
||||
&& !((b[at + 6] | b[at + 7] | b[at + 8] | b[at + 9]) & 0x80))
|
||||
{
|
||||
size_t tag = 10 + (((size_t)b[at + 6] << 21) | ((size_t)b[at + 7] << 14)
|
||||
| ((size_t)b[at + 8] << 7) | b[at + 9]) + ((b[at + 5] & 0x10) ? 10 : 0);
|
||||
if (tag > len - at)
|
||||
return AUDIO_TYPE_NONE;
|
||||
at += tag;
|
||||
}
|
||||
b += at;
|
||||
len -= at;
|
||||
if (skip)
|
||||
*skip = at;
|
||||
|
||||
#ifdef HAVE_RFLAC
|
||||
if (len >= 4 && !memcmp(b, "fLaC", 4))
|
||||
return AUDIO_TYPE_FLAC;
|
||||
#endif
|
||||
if (len >= 4 && !memcmp(b, "OggS", 4))
|
||||
return audio_transfer_ogg_audio_type(b, len);
|
||||
if (len >= 4 && b[0] == 0x1A && b[1] == 0x45 && b[2] == 0xDF && b[3] == 0xA3)
|
||||
return audio_transfer_webm_audio_type(b, len);
|
||||
|
||||
if (len >= 12 && !memcmp(b, "RIFF", 4))
|
||||
{
|
||||
size_t c = 12;
|
||||
#ifdef HAVE_RWMA
|
||||
if (!memcmp(b + 8, "XWMA", 4))
|
||||
return AUDIO_TYPE_WMA;
|
||||
#endif
|
||||
if (memcmp(b + 8, "WAVE", 4))
|
||||
return AUDIO_TYPE_NONE;
|
||||
/* the format tag says which arm */
|
||||
while (c + 8 <= len)
|
||||
{
|
||||
uint32_t clen = audio_transfer_le32(b + c + 4);
|
||||
if (!memcmp(b + c, "fmt ", 4) && clen >= 2 && len - c - 8 >= 2)
|
||||
{
|
||||
unsigned tag = b[c + 8] | ((unsigned)b[c + 9] << 8);
|
||||
if (tag == 0xFFFE && clen >= 26 && len - c - 8 >= 26)
|
||||
tag = b[c + 32] | ((unsigned)b[c + 33] << 8);
|
||||
#ifdef HAVE_RWAV
|
||||
if (tag == 1 || tag == 3)
|
||||
return AUDIO_TYPE_WAV;
|
||||
#endif
|
||||
#ifdef HAVE_RWMA
|
||||
if (tag == 0x0161 || tag == 0x0162 || tag == 0x0163)
|
||||
return AUDIO_TYPE_WMA;
|
||||
#endif
|
||||
#ifdef HAVE_RATRAC3
|
||||
if (tag == 0x0270)
|
||||
return AUDIO_TYPE_ATRAC;
|
||||
#endif
|
||||
#ifdef HAVE_RATRAC3P
|
||||
{
|
||||
/* the ATRAC3plus sub-format GUID */
|
||||
static const uint8_t g[16] = { 0xBF,0xAA,0x23,0xE9,0x58,0xCB,0x71,0x44,
|
||||
0xA1,0x19,0xFF,0xFA,0x01,0xE4,0xCE,0x62 };
|
||||
if ( b[c + 8] == 0xFE && b[c + 9] == 0xFF && clen >= 40
|
||||
&& len - c - 8 >= 40 && !memcmp(b + c + 32, g, 16))
|
||||
return AUDIO_TYPE_ATRAC;
|
||||
}
|
||||
#endif
|
||||
return AUDIO_TYPE_NONE;
|
||||
}
|
||||
if (clen > len - c - 8)
|
||||
break;
|
||||
c += 8 + clen + (clen & 1);
|
||||
}
|
||||
return AUDIO_TYPE_NONE;
|
||||
}
|
||||
|
||||
#ifdef HAVE_RWMA
|
||||
{
|
||||
static const uint8_t asf[16] = { 0x30,0x26,0xB2,0x75,0x8E,0x66,0xCF,0x11,
|
||||
0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C };
|
||||
if (len >= 16 && !memcmp(b, asf, 16))
|
||||
return AUDIO_TYPE_WMA;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_RAAC) && defined(HAVE_RMP4)
|
||||
if (len >= 8 && (!memcmp(b + 4, "ftyp", 4) || !memcmp(b + 4, "moov", 4)))
|
||||
return AUDIO_TYPE_AAC;
|
||||
#endif
|
||||
#ifdef HAVE_RMODTRACKER
|
||||
if ( (len >= 17 && !memcmp(b, "Extended Module: ", 17))
|
||||
|| (len >= 4 && !memcmp(b, "IMPM", 4))
|
||||
|| (len >= 48 && !memcmp(b + 44, "SCRM", 4)))
|
||||
return AUDIO_TYPE_MOD;
|
||||
if (len >= 1084)
|
||||
{
|
||||
static const char tags[][5] = { "M.K.", "M!K!", "FLT4", "FLT8", "EXO4",
|
||||
"EXO8", "OKTA", "OCTA", "CD81", "FA08" };
|
||||
const uint8_t *t = b + 1080;
|
||||
for (i = 0; i < sizeof(tags) / sizeof(tags[0]); i++)
|
||||
if (!memcmp(t, tags[i], 4))
|
||||
return AUDIO_TYPE_MOD;
|
||||
if ( (t[0] >= '1' && t[0] <= '9' && !memcmp(t + 1, "CHN", 3))
|
||||
|| (t[0] >= '1' && t[0] <= '9' && t[1] >= '0' && t[1] <= '9'
|
||||
&& !memcmp(t + 2, "CH", 2)))
|
||||
return AUDIO_TYPE_MOD;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Raw streams: a frame header, and another where it says the next
|
||||
* one is (or the end of the file), at the start or after a little
|
||||
* junk. */
|
||||
{
|
||||
static const enum audio_type_enum raw[3] = {
|
||||
AUDIO_TYPE_AC3, AUDIO_TYPE_AAC, AUDIO_TYPE_MP3 };
|
||||
size_t limit = len < 65536 ? len : 65536;
|
||||
for (i = 0; i + 4 <= limit; i++)
|
||||
{
|
||||
unsigned k;
|
||||
for (k = 0; k < 3; k++)
|
||||
{
|
||||
size_t f = audio_transfer_raw_frame(b + i, len - i, raw[k]);
|
||||
if ( f && f <= len - i
|
||||
&& (f == len - i
|
||||
|| audio_transfer_raw_frame(b + i + f, len - i - f, raw[k])))
|
||||
{
|
||||
if (skip)
|
||||
*skip = at + i;
|
||||
return raw[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(void)i;
|
||||
return AUDIO_TYPE_NONE;
|
||||
}
|
||||
|
||||
bool audio_transfer_set_start_trim(void *data, enum audio_type_enum type,
|
||||
uint64_t frames)
|
||||
{
|
||||
@@ -2687,16 +3278,22 @@ static int audio_transfer_mp3_gapless(const uint8_t *b, size_t len,
|
||||
if (!frames)
|
||||
return 0;
|
||||
/* The LAME tag starts here; its delay and padding are twelve
|
||||
* bits each, packed into three bytes at offset 21. */
|
||||
* bits each, packed into three bytes at offset 21. Its delay is
|
||||
* the encoder's; the decoder's own, 529 samples, comes on top,
|
||||
* as rmp3's pull API (RMP3_DECODER_DELAY) and FFmpeg take it -
|
||||
* without it the audio started 529 samples late and its last
|
||||
* 529 were cut. The padding is net of it already. */
|
||||
if ((size_t)(p - b) + 24 <= len)
|
||||
{
|
||||
delay = ((uint64_t)p[21] << 4) | (p[22] >> 4);
|
||||
pad = ((uint64_t)(p[22] & 0xf) << 8) | p[23];
|
||||
*out_delay = (uint64_t)spf + delay + RMP3_DECODER_DELAY;
|
||||
}
|
||||
else
|
||||
*out_delay = (uint64_t)spf;
|
||||
/* The filler frame is decoded like any other, so it is priming
|
||||
* too. What is left to play is the stated audio less both
|
||||
* ends. */
|
||||
*out_delay = (uint64_t)spf + delay;
|
||||
*out_frames = (uint64_t)frames * spf;
|
||||
*out_frames = (*out_frames > delay + pad)
|
||||
? *out_frames - delay - pad : 0;
|
||||
@@ -4033,6 +4630,39 @@ bool audio_transfer_start(void *data, enum audio_type_enum type)
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_RATRAC3) || defined(HAVE_RATRAC3P)
|
||||
case AUDIO_TYPE_ATRAC:
|
||||
{
|
||||
struct audio_transfer_atrac *a = (struct audio_transfer_atrac*)data;
|
||||
if (!a || !a->buf || !audio_transfer_atrac_parse(a))
|
||||
return false;
|
||||
a->spf = a->plus ? 2048 : 1024;
|
||||
audio_transfer_atrac_map(a);
|
||||
#ifdef HAVE_RATRAC3P
|
||||
if (a->plus && !(a->d3p = ratrac3p_new(a->dec_channels, a->block_align)))
|
||||
return false;
|
||||
#endif
|
||||
#ifdef HAVE_RATRAC3
|
||||
if (!a->plus && !(a->d3 = ratrac3_new(a->dec_channels, a->block_align, a->joint)))
|
||||
return false;
|
||||
#endif
|
||||
a->raw = (float*)malloc((size_t)a->spf * a->dec_channels * sizeof(float));
|
||||
a->pend = (float*)malloc((size_t)a->spf * a->channels * sizeof(float));
|
||||
if (!a->raw || !a->pend)
|
||||
{
|
||||
free(a->raw);
|
||||
free(a->pend);
|
||||
a->raw = a->pend = NULL;
|
||||
return false;
|
||||
}
|
||||
a->total_frames = (uint64_t)((a->data_end - a->data) / a->block_align) * a->spf;
|
||||
a->pos = a->data;
|
||||
a->pend_n = a->pend_off = 0;
|
||||
a->frame_pos = 0;
|
||||
a->ended = false;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_RAC3
|
||||
case AUDIO_TYPE_AC3:
|
||||
{
|
||||
@@ -4294,6 +4924,10 @@ bool audio_transfer_start(void *data, enum audio_type_enum type)
|
||||
return false;
|
||||
}
|
||||
ac->channels = raac_channels(ac->handle);
|
||||
/* the WAVE order every arm but Vorbis and Opus hands over, and
|
||||
* audio_transfer_fold_q15 folds by; a layout raac has no WAVE
|
||||
* map for stays in stream order */
|
||||
raac_set_channel_order(ac->handle, RAAC_ORDER_WAVE);
|
||||
ac->trim_left = ac->start_trim;
|
||||
ac->emitted = 0;
|
||||
ac->pkt_index = 0;
|
||||
@@ -4360,6 +4994,13 @@ bool audio_transfer_is_valid(void *data, enum audio_type_enum type)
|
||||
return op && op->handle;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_RATRAC3) || defined(HAVE_RATRAC3P)
|
||||
case AUDIO_TYPE_ATRAC:
|
||||
{
|
||||
struct audio_transfer_atrac *a = (struct audio_transfer_atrac*)data;
|
||||
return a && a->raw;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_RAC3
|
||||
case AUDIO_TYPE_AC3:
|
||||
{
|
||||
@@ -4388,11 +5029,106 @@ bool audio_transfer_is_valid(void *data, enum audio_type_enum type)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ---- folding to stereo ----------------------------------------------
|
||||
*
|
||||
* The arms do no channel conversion: wider than stereo comes out as the
|
||||
* codec orders it, and the consumer folds. Vorbis and Opus (mapping
|
||||
* family 1) order the channels one way (Vorbis I 4.3.9), everything
|
||||
* else - WAV, FLAC, AAC (put into this order at start), AC-3 (shaped
|
||||
* into it), MP3 - the WAVEFORMATEXTENSIBLE way:
|
||||
*
|
||||
* Vorbis 3 L C R 4 L R RL RR 5 L C R RL RR
|
||||
* 6 L C R RL RR LFE 7 L C R RL RR BC LFE
|
||||
* 8 L C R RL RR SL SR LFE
|
||||
* WAV 3 FL FR FC 4 FL FR BL BR 5 FL FR FC BL BR
|
||||
* 6 FL FR FC LFE BL BR 7 FL FR FC LFE BC SL SR
|
||||
* 8 FL FR FC LFE BL BR SL SR
|
||||
*
|
||||
* Folding one with the other's table is not a subtle error: on 5.1 it
|
||||
* sends front-right to both sides, front-centre to the right alone,
|
||||
* LFE into the mix and back-right nowhere.
|
||||
*
|
||||
* Coefficients are the usual ITU-R BS.775 ones: centre and surrounds
|
||||
* enter both sides at -3 dB, a lone back centre at -6 dB into each, LFE
|
||||
* is dropped. Not normalised: scaling by the coefficient sum would put
|
||||
* 5.1 content 7.7 dB below the same material in a stereo file, which is
|
||||
* a surprising thing for a file's channel count to do to its volume;
|
||||
* the sum only reaches full scale when the channels are correlated.
|
||||
* Q15 in int32: unity is 32768, which an int16 would wrap. */
|
||||
#define AT_FOLD_UNITY 32768
|
||||
#define AT_FOLD_M3DB 23170
|
||||
#define AT_FOLD_M6DB 16384
|
||||
|
||||
static const int32_t audio_transfer_fold_vorbis[9][8][2] = {
|
||||
{ {0,0} },
|
||||
{ {AT_FOLD_UNITY,AT_FOLD_UNITY} },
|
||||
{ {AT_FOLD_UNITY,0}, {0,AT_FOLD_UNITY} },
|
||||
/* 3: L C R */
|
||||
{ {AT_FOLD_UNITY,0}, {AT_FOLD_M3DB,AT_FOLD_M3DB}, {0,AT_FOLD_UNITY} },
|
||||
/* 4: L R RL RR */
|
||||
{ {AT_FOLD_UNITY,0}, {0,AT_FOLD_UNITY},
|
||||
{AT_FOLD_M3DB,0}, {0,AT_FOLD_M3DB} },
|
||||
/* 5: L C R RL RR */
|
||||
{ {AT_FOLD_UNITY,0}, {AT_FOLD_M3DB,AT_FOLD_M3DB}, {0,AT_FOLD_UNITY},
|
||||
{AT_FOLD_M3DB,0}, {0,AT_FOLD_M3DB} },
|
||||
/* 6: L C R RL RR LFE */
|
||||
{ {AT_FOLD_UNITY,0}, {AT_FOLD_M3DB,AT_FOLD_M3DB}, {0,AT_FOLD_UNITY},
|
||||
{AT_FOLD_M3DB,0}, {0,AT_FOLD_M3DB}, {0,0} },
|
||||
/* 7: L C R RL RR BC LFE */
|
||||
{ {AT_FOLD_UNITY,0}, {AT_FOLD_M3DB,AT_FOLD_M3DB}, {0,AT_FOLD_UNITY},
|
||||
{AT_FOLD_M3DB,0}, {0,AT_FOLD_M3DB},
|
||||
{AT_FOLD_M6DB,AT_FOLD_M6DB}, {0,0} },
|
||||
/* 8: L C R RL RR SL SR LFE */
|
||||
{ {AT_FOLD_UNITY,0}, {AT_FOLD_M3DB,AT_FOLD_M3DB}, {0,AT_FOLD_UNITY},
|
||||
{AT_FOLD_M3DB,0}, {0,AT_FOLD_M3DB},
|
||||
{AT_FOLD_M3DB,0}, {0,AT_FOLD_M3DB}, {0,0} }
|
||||
};
|
||||
|
||||
static const int32_t audio_transfer_fold_wav[9][8][2] = {
|
||||
{ {0,0} },
|
||||
{ {AT_FOLD_UNITY,AT_FOLD_UNITY} },
|
||||
{ {AT_FOLD_UNITY,0}, {0,AT_FOLD_UNITY} },
|
||||
/* 3: FL FR FC */
|
||||
{ {AT_FOLD_UNITY,0}, {0,AT_FOLD_UNITY}, {AT_FOLD_M3DB,AT_FOLD_M3DB} },
|
||||
/* 4: FL FR BL BR */
|
||||
{ {AT_FOLD_UNITY,0}, {0,AT_FOLD_UNITY},
|
||||
{AT_FOLD_M3DB,0}, {0,AT_FOLD_M3DB} },
|
||||
/* 5: FL FR FC BL BR */
|
||||
{ {AT_FOLD_UNITY,0}, {0,AT_FOLD_UNITY}, {AT_FOLD_M3DB,AT_FOLD_M3DB},
|
||||
{AT_FOLD_M3DB,0}, {0,AT_FOLD_M3DB} },
|
||||
/* 6: FL FR FC LFE BL BR */
|
||||
{ {AT_FOLD_UNITY,0}, {0,AT_FOLD_UNITY}, {AT_FOLD_M3DB,AT_FOLD_M3DB},
|
||||
{0,0}, {AT_FOLD_M3DB,0}, {0,AT_FOLD_M3DB} },
|
||||
/* 7: FL FR FC LFE BC SL SR */
|
||||
{ {AT_FOLD_UNITY,0}, {0,AT_FOLD_UNITY}, {AT_FOLD_M3DB,AT_FOLD_M3DB},
|
||||
{0,0}, {AT_FOLD_M6DB,AT_FOLD_M6DB},
|
||||
{AT_FOLD_M3DB,0}, {0,AT_FOLD_M3DB} },
|
||||
/* 8: FL FR FC LFE BL BR SL SR */
|
||||
{ {AT_FOLD_UNITY,0}, {0,AT_FOLD_UNITY}, {AT_FOLD_M3DB,AT_FOLD_M3DB},
|
||||
{0,0}, {AT_FOLD_M3DB,0}, {0,AT_FOLD_M3DB},
|
||||
{AT_FOLD_M3DB,0}, {0,AT_FOLD_M3DB} }
|
||||
};
|
||||
|
||||
const int32_t (*audio_transfer_fold_q15(enum audio_type_enum type,
|
||||
unsigned channels))[2]
|
||||
{
|
||||
if (channels < 1 || channels > 8)
|
||||
return NULL;
|
||||
if (type == AUDIO_TYPE_VORBIS || type == AUDIO_TYPE_OPUS)
|
||||
return audio_transfer_fold_vorbis[channels];
|
||||
return audio_transfer_fold_wav[channels];
|
||||
}
|
||||
|
||||
bool audio_transfer_stereo_matrix(void *data, enum audio_type_enum type,
|
||||
int32_t matrix[8][2])
|
||||
{
|
||||
const int32_t (*fold)[2];
|
||||
unsigned ch = 0;
|
||||
if (!data || !matrix)
|
||||
return false;
|
||||
#ifdef HAVE_RWMA
|
||||
if (data && matrix && type == AUDIO_TYPE_WMA)
|
||||
/* by the stream's speaker mask */
|
||||
if (type == AUDIO_TYPE_WMA)
|
||||
{
|
||||
static const uint32_t defaults[9] = {0,4,3,7,51,55,63,1807,1599};
|
||||
struct audio_transfer_wma *a = (struct audio_transfer_wma*)data;
|
||||
@@ -4425,10 +5161,14 @@ bool audio_transfer_stereo_matrix(void *data, enum audio_type_enum type,
|
||||
}
|
||||
return lane == a->channels;
|
||||
}
|
||||
#else
|
||||
(void)data; (void)type; (void)matrix;
|
||||
#endif
|
||||
return false;
|
||||
/* by the channel count, in the order the arm hands them over */
|
||||
if ( !audio_transfer_info(data, type, &ch, NULL, NULL)
|
||||
|| !(fold = audio_transfer_fold_q15(type, ch)))
|
||||
return false;
|
||||
memset(matrix, 0, 8 * 2 * sizeof(int32_t));
|
||||
memcpy(matrix, fold, ch * 2 * sizeof(int32_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool audio_transfer_stereo_matrix_f32(void *data, enum audio_type_enum type,
|
||||
@@ -4455,7 +5195,9 @@ bool audio_transfer_info(void *data, enum audio_type_enum type,
|
||||
if (!a || !a->stream) return false;
|
||||
if (channels) *channels = a->channels;
|
||||
if (rate) *rate = a->rate;
|
||||
if (total_frames) *total_frames = 0;
|
||||
/* what the container states: the decode runs on past it by
|
||||
* the codec's priming */
|
||||
if (total_frames) *total_frames = rwma_stream_frames(a->stream);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -4602,6 +5344,18 @@ bool audio_transfer_info(void *data, enum audio_type_enum type,
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_RATRAC3) || defined(HAVE_RATRAC3P)
|
||||
case AUDIO_TYPE_ATRAC:
|
||||
{
|
||||
struct audio_transfer_atrac *a = (struct audio_transfer_atrac*)data;
|
||||
if (!a || !a->raw)
|
||||
return false;
|
||||
if (channels) *channels = a->channels;
|
||||
if (rate) *rate = a->rate;
|
||||
if (total_frames) *total_frames = a->total_frames;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_RAC3
|
||||
case AUDIO_TYPE_AC3:
|
||||
{
|
||||
@@ -6096,6 +6850,11 @@ int audio_transfer_read_s16(void *data, enum audio_type_enum type,
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_RATRAC3) || defined(HAVE_RATRAC3P)
|
||||
case AUDIO_TYPE_ATRAC:
|
||||
return audio_transfer_atrac_read((struct audio_transfer_atrac*)data,
|
||||
NULL, out, frames, frames_out);
|
||||
#endif
|
||||
#ifdef HAVE_RAC3
|
||||
case AUDIO_TYPE_AC3:
|
||||
return audio_transfer_ac3_read((struct audio_transfer_ac3*)data,
|
||||
@@ -6420,6 +7179,11 @@ int audio_transfer_read_f32(void *data, enum audio_type_enum type,
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_RATRAC3) || defined(HAVE_RATRAC3P)
|
||||
case AUDIO_TYPE_ATRAC:
|
||||
return audio_transfer_atrac_read((struct audio_transfer_atrac*)data,
|
||||
out, NULL, frames, frames_out);
|
||||
#endif
|
||||
#ifdef HAVE_RAC3
|
||||
case AUDIO_TYPE_AC3:
|
||||
return audio_transfer_ac3_read((struct audio_transfer_ac3*)data,
|
||||
@@ -6635,6 +7399,13 @@ size_t audio_transfer_buffer_tell(void *data, enum audio_type_enum type)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_RATRAC3) || defined(HAVE_RATRAC3P)
|
||||
case AUDIO_TYPE_ATRAC:
|
||||
{
|
||||
struct audio_transfer_atrac *a = (struct audio_transfer_atrac*)data;
|
||||
return a ? a->pos : 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_RAC3
|
||||
case AUDIO_TYPE_AC3:
|
||||
{
|
||||
@@ -6991,6 +7762,15 @@ bool audio_transfer_seek(void *data, enum audio_type_enum type,
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_RATRAC3) || defined(HAVE_RATRAC3P)
|
||||
case AUDIO_TYPE_ATRAC:
|
||||
{
|
||||
struct audio_transfer_atrac *a = (struct audio_transfer_atrac*)data;
|
||||
if (!a || !a->raw)
|
||||
return false;
|
||||
return audio_transfer_atrac_seek_to(a, frame);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_RAC3
|
||||
case AUDIO_TYPE_AC3:
|
||||
{
|
||||
@@ -7157,6 +7937,24 @@ void audio_transfer_free(void *data, enum audio_type_enum type)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_RATRAC3) || defined(HAVE_RATRAC3P)
|
||||
case AUDIO_TYPE_ATRAC:
|
||||
{
|
||||
struct audio_transfer_atrac *a = (struct audio_transfer_atrac*)data;
|
||||
if (a)
|
||||
{
|
||||
#ifdef HAVE_RATRAC3P
|
||||
ratrac3p_free(a->d3p);
|
||||
#endif
|
||||
#ifdef HAVE_RATRAC3
|
||||
ratrac3_free(a->d3);
|
||||
#endif
|
||||
free(a->raw);
|
||||
free(a->pend);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_RAC3
|
||||
case AUDIO_TYPE_AC3:
|
||||
{
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
/* Copyright (C) 2010-2026 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (rcontainer.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* AVI and ASF headers: see formats/rcontainer.h. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <formats/rcontainer.h>
|
||||
|
||||
static uint32_t rc_le16(const uint8_t *p) { return (uint32_t)p[0] | ((uint32_t)p[1] << 8); }
|
||||
static uint32_t rc_le32(const uint8_t *p)
|
||||
{
|
||||
return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
|
||||
}
|
||||
static uint64_t rc_le64(const uint8_t *p)
|
||||
{
|
||||
return (uint64_t)rc_le32(p) | ((uint64_t)rc_le32(p + 4) << 32);
|
||||
}
|
||||
|
||||
/* a WAVEFORMATEX into an audio stream */
|
||||
static void rc_wave(rcontainer_stream *s, const uint8_t *p, size_t n)
|
||||
{
|
||||
s->type = RCONTAINER_STREAM_AUDIO;
|
||||
if (n < 16)
|
||||
return;
|
||||
s->format_tag = rc_le16(p);
|
||||
s->channels = rc_le16(p + 2);
|
||||
s->sample_rate = rc_le32(p + 4);
|
||||
s->bitrate = rc_le32(p + 8) * 8;
|
||||
/* WAVE_FORMAT_EXTENSIBLE: the sub-format's first two bytes */
|
||||
if (s->format_tag == 0xFFFE && n >= 26 && rc_le16(p + 16) >= 22)
|
||||
s->format_tag = rc_le16(p + 24);
|
||||
}
|
||||
|
||||
/* a BITMAPINFOHEADER into a video stream */
|
||||
static void rc_bitmap(rcontainer_stream *s, const uint8_t *p, size_t n)
|
||||
{
|
||||
int32_t h;
|
||||
s->type = RCONTAINER_STREAM_VIDEO;
|
||||
if (n < 20)
|
||||
return;
|
||||
s->width = rc_le32(p + 4);
|
||||
h = (int32_t)rc_le32(p + 8);
|
||||
s->height = (unsigned)(h < 0 ? -h : h);
|
||||
s->fourcc = rc_le32(p + 16);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* AVI */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* the chunk of @id among those in [@at, @end): its body */
|
||||
static bool rc_chunk(const uint8_t *p, size_t at, size_t end, const char *id,
|
||||
const char *list, size_t *body, size_t *body_end)
|
||||
{
|
||||
while (at + 8 <= end)
|
||||
{
|
||||
size_t len = rc_le32(p + at + 4);
|
||||
if (len > end - at - 8)
|
||||
len = end - at - 8;
|
||||
if (!memcmp(p + at, id, 4) && (!list || (len >= 4 && !memcmp(p + at + 8, list, 4))))
|
||||
{
|
||||
*body = at + 8 + (list ? 4 : 0);
|
||||
*body_end = at + 8 + len;
|
||||
return true;
|
||||
}
|
||||
at += 8 + len + (len & 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool rc_avi(const uint8_t *p, size_t n, rcontainer_info *info)
|
||||
{
|
||||
size_t hdrl, hdrl_end, b, b_end, at;
|
||||
uint64_t frames = 0, period = 0, bytes[RCONTAINER_MAX_STREAMS];
|
||||
double seconds = 0;
|
||||
unsigned i;
|
||||
|
||||
if (!rc_chunk(p, 12, n, "LIST", "hdrl", &hdrl, &hdrl_end))
|
||||
return false;
|
||||
info->kind = RCONTAINER_AVI;
|
||||
if (rc_chunk(p, hdrl, hdrl_end, "avih", NULL, &b, &b_end) && b_end - b >= 20)
|
||||
{
|
||||
period = rc_le32(p + b); /* microseconds a frame */
|
||||
frames = rc_le32(p + b + 16);
|
||||
}
|
||||
/* each stream list in turn */
|
||||
for (at = hdrl; at + 8 <= hdrl_end; )
|
||||
{
|
||||
size_t len = rc_le32(p + at + 4), sl, sl_end, h, h_end, f, f_end;
|
||||
if (len > hdrl_end - at - 8)
|
||||
len = hdrl_end - at - 8;
|
||||
if (!memcmp(p + at, "LIST", 4) && len >= 4 && !memcmp(p + at + 8, "strl", 4)
|
||||
&& info->num_streams < RCONTAINER_MAX_STREAMS)
|
||||
{
|
||||
rcontainer_stream *s = &info->streams[info->num_streams++];
|
||||
sl = at + 12;
|
||||
sl_end = at + 8 + len;
|
||||
if (rc_chunk(p, sl, sl_end, "strh", NULL, &h, &h_end) && h_end - h >= 36)
|
||||
{
|
||||
uint32_t scale = rc_le32(p + h + 20), rate = rc_le32(p + h + 24);
|
||||
uint32_t length = rc_le32(p + h + 32);
|
||||
if (rc_chunk(p, sl, sl_end, "strf", NULL, &f, &f_end))
|
||||
{
|
||||
if (!memcmp(p + h, "vids", 4))
|
||||
rc_bitmap(s, p + f, f_end - f);
|
||||
else if (!memcmp(p + h, "auds", 4))
|
||||
rc_wave(s, p + f, f_end - f);
|
||||
}
|
||||
/* the longest stream's length is the file's, as FFmpeg
|
||||
* gives it */
|
||||
if (scale && rate && (double)length * scale / rate > seconds)
|
||||
seconds = (double)length * scale / rate;
|
||||
}
|
||||
}
|
||||
at += 8 + len + (len & 1);
|
||||
}
|
||||
if (!seconds && frames && period)
|
||||
seconds = (double)frames * period / 1e6;
|
||||
info->duration_us = (int64_t)(seconds * 1e6 + 0.5);
|
||||
|
||||
/* each stream's bytes, from idx1: "NNxx" ids, NN the stream */
|
||||
memset(bytes, 0, sizeof(bytes));
|
||||
if (seconds > 0 && rc_chunk(p, 12, n, "idx1", NULL, &b, &b_end))
|
||||
{
|
||||
for (at = b; at + 16 <= b_end; at += 16)
|
||||
{
|
||||
unsigned d0 = p[at], d1 = p[at + 1], k;
|
||||
if (d0 < '0' || d0 > '9' || d1 < '0' || d1 > '9')
|
||||
continue;
|
||||
k = (d0 - '0') * 10 + (d1 - '0');
|
||||
if (k < info->num_streams)
|
||||
bytes[k] += rc_le32(p + at + 12);
|
||||
}
|
||||
for (i = 0; i < info->num_streams; i++)
|
||||
if (bytes[i] && info->streams[i].type == RCONTAINER_STREAM_VIDEO)
|
||||
info->streams[i].bitrate = (uint32_t)(bytes[i] * 8 / seconds);
|
||||
}
|
||||
return info->num_streams > 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* ASF */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
static const uint8_t rc_asf_header[16] = { 0x30,0x26,0xB2,0x75,0x8E,0x66,0xCF,0x11,0xA6,0xD9,0x00,0xAA,0x00,0x62,0xCE,0x6C };
|
||||
static const uint8_t rc_asf_file[16] = { 0xA1,0xDC,0xAB,0x8C,0x47,0xA9,0xCF,0x11,0x8E,0xE4,0x00,0xC0,0x0C,0x20,0x53,0x65 };
|
||||
static const uint8_t rc_asf_stream[16] = { 0x91,0x07,0xDC,0xB7,0xB7,0xA9,0xCF,0x11,0x8E,0xE6,0x00,0xC0,0x0C,0x20,0x53,0x65 };
|
||||
static const uint8_t rc_asf_audio[16] = { 0x40,0x9E,0x69,0xF8,0x4D,0x5B,0xCF,0x11,0xA8,0xFD,0x00,0x80,0x5F,0x5C,0x44,0x2B };
|
||||
static const uint8_t rc_asf_video[16] = { 0xC0,0xEF,0x19,0xBC,0x4D,0x5B,0xCF,0x11,0xA8,0xFD,0x00,0x80,0x5F,0x5C,0x44,0x2B };
|
||||
static const uint8_t rc_asf_bitrate[16] = { 0xCE,0x75,0xF8,0x7B,0x8D,0x46,0xD1,0x11,0x8D,0x82,0x00,0x60,0x97,0xC9,0xA2,0xB2 };
|
||||
|
||||
static bool rc_asf(const uint8_t *p, size_t n, rcontainer_info *info)
|
||||
{
|
||||
uint64_t size = rc_le64(p + 16);
|
||||
size_t end = size < n ? (size_t)size : n, at = 30;
|
||||
unsigned number[RCONTAINER_MAX_STREAMS], i;
|
||||
uint32_t rates[128];
|
||||
|
||||
info->kind = RCONTAINER_ASF;
|
||||
memset(rates, 0, sizeof(rates));
|
||||
while (at + 24 <= end)
|
||||
{
|
||||
uint64_t osize = rc_le64(p + at + 16);
|
||||
size_t body = at + 24, oend;
|
||||
if (osize < 24 || osize > end - at)
|
||||
break;
|
||||
oend = at + (size_t)osize;
|
||||
if (!memcmp(p + at, rc_asf_file, 16) && oend - body >= 68)
|
||||
{
|
||||
uint64_t play = rc_le64(p + body + 40), preroll = rc_le64(p + body + 56);
|
||||
if (!(rc_le32(p + body + 64) & 1) && preroll < play / 10000)
|
||||
info->duration_us = (int64_t)((play - preroll * 10000) / 10);
|
||||
}
|
||||
else if (!memcmp(p + at, rc_asf_stream, 16) && oend - body >= 54
|
||||
&& info->num_streams < RCONTAINER_MAX_STREAMS)
|
||||
{
|
||||
rcontainer_stream *s = &info->streams[info->num_streams];
|
||||
uint32_t tlen = rc_le32(p + body + 40);
|
||||
size_t t = body + 54;
|
||||
number[info->num_streams++] = rc_le16(p + body + 48) & 0x7f;
|
||||
if (tlen > oend - t)
|
||||
tlen = (uint32_t)(oend - t);
|
||||
if (!memcmp(p + body, rc_asf_audio, 16))
|
||||
rc_wave(s, p + t, tlen);
|
||||
else if (!memcmp(p + body, rc_asf_video, 16))
|
||||
{
|
||||
/* width, height, a flag byte, the format data's size, then
|
||||
* a BITMAPINFOHEADER */
|
||||
s->type = RCONTAINER_STREAM_VIDEO;
|
||||
if (tlen >= 11)
|
||||
rc_bitmap(s, p + t + 11, tlen - 11);
|
||||
if (tlen >= 8)
|
||||
{
|
||||
s->width = rc_le32(p + t);
|
||||
s->height = rc_le32(p + t + 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!memcmp(p + at, rc_asf_bitrate, 16) && oend - body >= 2)
|
||||
{
|
||||
unsigned count = rc_le16(p + body), k;
|
||||
for (k = 0; k < count && body + 2 + k * 6 + 6 <= oend; k++)
|
||||
{
|
||||
const uint8_t *r = p + body + 2 + k * 6;
|
||||
rates[rc_le16(r) & 0x7f] = rc_le32(r + 2);
|
||||
}
|
||||
}
|
||||
at = oend;
|
||||
}
|
||||
for (i = 0; i < info->num_streams; i++)
|
||||
if (rates[number[i]])
|
||||
info->streams[i].bitrate = rates[number[i]];
|
||||
return info->num_streams > 0;
|
||||
}
|
||||
|
||||
bool rcontainer_probe(const uint8_t *data, size_t len, rcontainer_info *info)
|
||||
{
|
||||
if (!info)
|
||||
return false;
|
||||
memset(info, 0, sizeof(*info));
|
||||
if (!data)
|
||||
return false;
|
||||
if (len >= 12 && !memcmp(data, "RIFF", 4) && !memcmp(data + 8, "AVI ", 4))
|
||||
return rc_avi(data, len, info);
|
||||
if (len >= 30 && !memcmp(data, rc_asf_header, 16))
|
||||
return rc_asf(data, len, info);
|
||||
return false;
|
||||
}
|
||||
@@ -1259,6 +1259,10 @@ static int data_transfer_read_at(data_transfer_t *dt, size_t off,
|
||||
int64_t save, r;
|
||||
if (dt->read_at)
|
||||
return dt->read_at(dt->read_ud,off,dst,n) == (int64_t)n;
|
||||
/* At the offset, the cursor and read-ahead untouched; seek and read
|
||||
* where the file has no positional reads */
|
||||
if ((r = filestream_read_at(dt->f, dst, (int64_t)n, (int64_t)off)) >= 0)
|
||||
return r == (int64_t)n;
|
||||
save = filestream_tell(dt->f);
|
||||
if (save < 0
|
||||
|| (save != (int64_t)off
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
#include <limits.h>
|
||||
|
||||
#include <retro_inline.h>
|
||||
#include <retro_endianness.h>
|
||||
|
||||
#include <formats/image.h>
|
||||
#include <formats/rdds.h>
|
||||
@@ -90,7 +91,20 @@
|
||||
( (unsigned long long)RDDS_RL32((const unsigned char*)(p)) \
|
||||
| ((unsigned long long)RDDS_RL32((const unsigned char*)(p) + 4) << 32))
|
||||
|
||||
static void rdds_bcdec__color_block(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int onlyOpaqueMode) {
|
||||
/* Inlined into each of its callers whatever the compiler would choose, so
|
||||
* that a decoder taking a constant order (RGBA or BGRA) is built for it
|
||||
* alone, with no test of the order per block. */
|
||||
#if defined(_MSC_VER)
|
||||
#define RDDS_FORCE_INLINE static __forceinline
|
||||
#elif defined(__GNUC__)
|
||||
#define RDDS_FORCE_INLINE static INLINE __attribute__((always_inline))
|
||||
#else
|
||||
#define RDDS_FORCE_INLINE static INLINE
|
||||
#endif
|
||||
|
||||
/* bgra: B,G,R,A in memory instead of R,G,B,A (red and blue swapped in
|
||||
* the reference colours) */
|
||||
RDDS_FORCE_INLINE void rdds_bcdec__color_block_order(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int onlyOpaqueMode, int bgra) {
|
||||
unsigned short c0, c1;
|
||||
unsigned int refColors[4]; /* 0xAABBGGRR */
|
||||
unsigned char* dstColors;
|
||||
@@ -146,6 +160,12 @@ static void rdds_bcdec__color_block(const void* compressedBlock, void* decompres
|
||||
|
||||
colorIndices = RDDS_RL32((const unsigned char*)compressedBlock + 4);
|
||||
|
||||
if (bgra) {
|
||||
for (i = 0; i < 4; ++i)
|
||||
refColors[i] = (refColors[i] & 0xFF00FF00u) | ((refColors[i] >> 16) & 0xFFu)
|
||||
| ((refColors[i] & 0xFFu) << 16);
|
||||
}
|
||||
|
||||
/* Fill out the decompressed color block */
|
||||
dstColors = (unsigned char*)decompressedBlock;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
@@ -162,6 +182,14 @@ static void rdds_bcdec__color_block(const void* compressedBlock, void* decompres
|
||||
}
|
||||
}
|
||||
|
||||
static void rdds_bcdec__color_block(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int onlyOpaqueMode) {
|
||||
rdds_bcdec__color_block_order(compressedBlock, decompressedBlock, destinationPitch, onlyOpaqueMode, 0);
|
||||
}
|
||||
|
||||
static void rdds_bcdec__color_block_bgra(const void* compressedBlock, void* decompressedBlock, int destinationPitch, int onlyOpaqueMode) {
|
||||
rdds_bcdec__color_block_order(compressedBlock, decompressedBlock, destinationPitch, onlyOpaqueMode, 1);
|
||||
}
|
||||
|
||||
static void rdds_bcdec__sharp_alpha_block(const void* compressedBlock, void* decompressedBlock, int destinationPitch) {
|
||||
const unsigned char* alpha;
|
||||
unsigned char* decompressed;
|
||||
@@ -390,6 +418,21 @@ static void rdds_bcdec_bc3(const void* compressedBlock, void* decompressedBlock,
|
||||
rdds_bcdec__smooth_alpha_block(compressedBlock, ((char*)decompressedBlock) + 3, destinationPitch, 4);
|
||||
}
|
||||
|
||||
/* The same, B,G,R,A in memory: alpha stays the fourth byte */
|
||||
static void rdds_bcdec_bc1_bgra(const void* compressedBlock, void* decompressedBlock, int destinationPitch) {
|
||||
rdds_bcdec__color_block_bgra(compressedBlock, decompressedBlock, destinationPitch, 0);
|
||||
}
|
||||
|
||||
static void rdds_bcdec_bc2_bgra(const void* compressedBlock, void* decompressedBlock, int destinationPitch) {
|
||||
rdds_bcdec__color_block_bgra(((char*)compressedBlock) + 8, decompressedBlock, destinationPitch, 1);
|
||||
rdds_bcdec__sharp_alpha_block(compressedBlock, ((char*)decompressedBlock) + 3, destinationPitch);
|
||||
}
|
||||
|
||||
static void rdds_bcdec_bc3_bgra(const void* compressedBlock, void* decompressedBlock, int destinationPitch) {
|
||||
rdds_bcdec__color_block_bgra(((char*)compressedBlock) + 8, decompressedBlock, destinationPitch, 1);
|
||||
rdds_bcdec__smooth_alpha_block(compressedBlock, ((char*)decompressedBlock) + 3, destinationPitch, 4);
|
||||
}
|
||||
|
||||
#ifndef BCDEC_BC4BC5_PRECISE
|
||||
static void rdds_bcdec_bc4(const void* compressedBlock, void* decompressedBlock, int destinationPitch) {
|
||||
rdds_bcdec__smooth_alpha_block(compressedBlock, decompressedBlock, destinationPitch, 1);
|
||||
@@ -1891,7 +1934,7 @@ static const unsigned char rdds_d6[190] = {
|
||||
* stores the compiler already coalesces, so it needs no fused variant
|
||||
* and no punch-through handling here.) */
|
||||
static INLINE void rdds_bc_refcolors(const unsigned char *cp,
|
||||
unsigned int ref[4])
|
||||
unsigned int ref[4], int bgra)
|
||||
{
|
||||
unsigned c0 = RDDS_RL16(cp), c1 = RDDS_RL16(cp + 2);
|
||||
unsigned r0 = (c0 >> 11) & 0x1F, g0 = (c0 >> 5) & 0x3F, b0 = c0 & 0x1F;
|
||||
@@ -1905,11 +1948,19 @@ static INLINE void rdds_bc_refcolors(const unsigned char *cp,
|
||||
| ((unsigned)rdds_d6[2 * g0 + g1] << 8) | rdds_d5[2 * r0 + r1];
|
||||
ref[3] = 0xFF000000u | ((unsigned)rdds_d5[b0 + 2 * b1] << 16)
|
||||
| ((unsigned)rdds_d6[g0 + 2 * g1] << 8) | rdds_d5[r0 + 2 * r1];
|
||||
if (bgra) /* A<<24|R<<16|G<<8|B, for a BGRA surface */
|
||||
{
|
||||
int k;
|
||||
for (k = 0; k < 4; k++)
|
||||
ref[k] = (ref[k] & 0xFF00FF00u) | ((ref[k] >> 16) & 0xFFu)
|
||||
| ((ref[k] & 0xFFu) << 16);
|
||||
}
|
||||
}
|
||||
|
||||
/* BC2: opaque colour + explicit 4-bit alpha, fused into one store. */
|
||||
static void rdds_bcdec_bc2_direct(const void *compressedBlock,
|
||||
void *decompressedBlock, int destinationPitch)
|
||||
/* BC2: opaque colour + explicit 4-bit alpha, fused into one store.
|
||||
* bgra: the uint32 is A<<24|R<<16|G<<8|B instead of A<<24|B<<16|G<<8|R. */
|
||||
RDDS_FORCE_INLINE void rdds_bcdec_bc2_fused(const void *compressedBlock,
|
||||
void *decompressedBlock, int destinationPitch, int bgra)
|
||||
{
|
||||
const unsigned char *p = (const unsigned char*)compressedBlock;
|
||||
unsigned char *dst = (unsigned char*)decompressedBlock;
|
||||
@@ -1917,7 +1968,7 @@ static void rdds_bcdec_bc2_direct(const void *compressedBlock,
|
||||
unsigned int ci = RDDS_RL32(p + 12);
|
||||
int i, j;
|
||||
|
||||
rdds_bc_refcolors(p + 8, ref);
|
||||
rdds_bc_refcolors(p + 8, ref, bgra);
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
unsigned int arow = RDDS_RL16(p + 2 * i); /* four 4-bit alphas */
|
||||
@@ -1934,9 +1985,11 @@ static void rdds_bcdec_bc2_direct(const void *compressedBlock,
|
||||
}
|
||||
}
|
||||
|
||||
/* BC3: opaque colour + smooth (interpolated) 8-value alpha, one store. */
|
||||
static void rdds_bcdec_bc3_direct(const void *compressedBlock,
|
||||
void *decompressedBlock, int destinationPitch)
|
||||
/* BC3: opaque colour + smooth (interpolated) 8-value alpha, one store.
|
||||
* The alpha ramp rounds as rdds_bcdec__smooth_alpha_block does, so this
|
||||
* path and the scratch one agree for every texel. */
|
||||
RDDS_FORCE_INLINE void rdds_bcdec_bc3_fused(const void *compressedBlock,
|
||||
void *decompressedBlock, int destinationPitch, int bgra)
|
||||
{
|
||||
const unsigned char *p = (const unsigned char*)compressedBlock;
|
||||
unsigned char *dst = (unsigned char*)decompressedBlock;
|
||||
@@ -1951,24 +2004,24 @@ static void rdds_bcdec_bc3_direct(const void *compressedBlock,
|
||||
al[1] = (unsigned char)((blk >> 8) & 0xFF);
|
||||
if (al[0] > al[1])
|
||||
{
|
||||
al[2] = (unsigned char)((6 * al[0] + al[1]) / 7);
|
||||
al[3] = (unsigned char)((5 * al[0] + 2 * al[1]) / 7);
|
||||
al[4] = (unsigned char)((4 * al[0] + 3 * al[1]) / 7);
|
||||
al[5] = (unsigned char)((3 * al[0] + 4 * al[1]) / 7);
|
||||
al[6] = (unsigned char)((2 * al[0] + 5 * al[1]) / 7);
|
||||
al[7] = (unsigned char)(( al[0] + 6 * al[1]) / 7);
|
||||
al[2] = (unsigned char)((6 * al[0] + al[1] + 3) / 7);
|
||||
al[3] = (unsigned char)((5 * al[0] + 2 * al[1] + 3) / 7);
|
||||
al[4] = (unsigned char)((4 * al[0] + 3 * al[1] + 3) / 7);
|
||||
al[5] = (unsigned char)((3 * al[0] + 4 * al[1] + 3) / 7);
|
||||
al[6] = (unsigned char)((2 * al[0] + 5 * al[1] + 3) / 7);
|
||||
al[7] = (unsigned char)(( al[0] + 6 * al[1] + 3) / 7);
|
||||
}
|
||||
else
|
||||
{
|
||||
al[2] = (unsigned char)((4 * al[0] + al[1]) / 5);
|
||||
al[3] = (unsigned char)((3 * al[0] + 2 * al[1]) / 5);
|
||||
al[4] = (unsigned char)((2 * al[0] + 3 * al[1]) / 5);
|
||||
al[5] = (unsigned char)(( al[0] + 4 * al[1]) / 5);
|
||||
al[2] = (unsigned char)((4 * al[0] + al[1] + 2) / 5);
|
||||
al[3] = (unsigned char)((3 * al[0] + 2 * al[1] + 2) / 5);
|
||||
al[4] = (unsigned char)((2 * al[0] + 3 * al[1] + 2) / 5);
|
||||
al[5] = (unsigned char)(( al[0] + 4 * al[1] + 2) / 5);
|
||||
al[6] = 0x00;
|
||||
al[7] = 0xFF;
|
||||
}
|
||||
|
||||
rdds_bc_refcolors(p + 8, ref);
|
||||
rdds_bc_refcolors(p + 8, ref, bgra);
|
||||
ci = RDDS_RL32(p + 12);
|
||||
idx = blk >> 16; /* 16 * 3-bit indices */
|
||||
for (i = 0; i < 4; ++i)
|
||||
@@ -1985,6 +2038,15 @@ static void rdds_bcdec_bc3_direct(const void *compressedBlock,
|
||||
}
|
||||
}
|
||||
|
||||
static void rdds_bcdec_bc2_direct(const void *b, void *o, int pitch)
|
||||
{ rdds_bcdec_bc2_fused(b, o, pitch, 0); }
|
||||
static void rdds_bcdec_bc3_direct(const void *b, void *o, int pitch)
|
||||
{ rdds_bcdec_bc3_fused(b, o, pitch, 0); }
|
||||
static void rdds_bcdec_bc2_direct_bgra(const void *b, void *o, int pitch)
|
||||
{ rdds_bcdec_bc2_fused(b, o, pitch, 1); }
|
||||
static void rdds_bcdec_bc3_direct_bgra(const void *b, void *o, int pitch)
|
||||
{ rdds_bcdec_bc3_fused(b, o, pitch, 1); }
|
||||
|
||||
/* Emit an edge (partially out-of-range) block from a decoded RGBA8
|
||||
* scratch into the surface with per-texel bounds tests. Shared by every
|
||||
* path so the hot interior loops stay branch-free. */
|
||||
@@ -2060,6 +2122,17 @@ RDDS_GEN_ROWS_DIRECT(rdds_rows_bc1_rgba, rdds_bcdec_bc1, 8u)
|
||||
RDDS_GEN_ROWS_DIRECT(rdds_rows_bc2_rgba, rdds_bcdec_bc2_direct, 16u)
|
||||
RDDS_GEN_ROWS_DIRECT(rdds_rows_bc3_rgba, rdds_bcdec_bc3_direct, 16u)
|
||||
|
||||
#ifndef MSB_FIRST
|
||||
/* The same for a BGRA video driver, little-endian only: there the
|
||||
* A<<24|R<<16|G<<8|B pixel is the bytes B,G,R,A, which the BGRA block
|
||||
* decoders write, so the edge scratch passes through rdds_emit_edge's
|
||||
* byte order unchanged (as with RGBA). Big-endian keeps the scratch
|
||||
* path below. */
|
||||
RDDS_GEN_ROWS_DIRECT(rdds_rows_bc1_bgra, rdds_bcdec_bc1_bgra, 8u)
|
||||
RDDS_GEN_ROWS_DIRECT(rdds_rows_bc2_bgra, rdds_bcdec_bc2_direct_bgra, 16u)
|
||||
RDDS_GEN_ROWS_DIRECT(rdds_rows_bc3_bgra, rdds_bcdec_bc3_direct_bgra, 16u)
|
||||
#endif
|
||||
|
||||
/* Decode block rows [by0, by1) of a BCn surface into 'out'. The caller
|
||||
* has already validated that the payload holds every block. */
|
||||
static void rdds_rows_compressed(const rdds_info_t *info,
|
||||
@@ -2093,6 +2166,22 @@ static void rdds_rows_compressed(const rdds_info_t *info,
|
||||
break; /* BC4/BC5/BC7 fall through to the scratch loop */
|
||||
}
|
||||
}
|
||||
#ifndef MSB_FIRST
|
||||
else if (!premul)
|
||||
{
|
||||
switch (info->fmt)
|
||||
{
|
||||
case RDDS_FMT_BC1:
|
||||
rdds_rows_bc1_bgra(info, data, out, by0, by1); return;
|
||||
case RDDS_FMT_BC2:
|
||||
rdds_rows_bc2_bgra(info, data, out, by0, by1); return;
|
||||
case RDDS_FMT_BC3:
|
||||
rdds_rows_bc3_bgra(info, data, out, by0, by1); return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Generic scratch path: BGRA output order, premultiplied alpha,
|
||||
* BC4/BC5 channel expansion, and BC7 (whose decode dominates, so the
|
||||
@@ -2722,3 +2811,6 @@ void rdds_decode_block_bc1(const void *block, void *out, int pitch) { rdds_bcdec
|
||||
void rdds_decode_block_bc2(const void *block, void *out, int pitch) { rdds_bcdec_bc2(block, out, pitch); }
|
||||
void rdds_decode_block_bc3(const void *block, void *out, int pitch) { rdds_bcdec_bc3(block, out, pitch); }
|
||||
void rdds_decode_block_bc7(const void *block, void *out, int pitch) { rdds_bcdec_bc7(block, out, pitch); }
|
||||
void rdds_decode_block_bc1_bgra(const void *block, void *out, int pitch) { rdds_bcdec_bc1_bgra(block, out, pitch); }
|
||||
void rdds_decode_block_bc2_bgra(const void *block, void *out, int pitch) { rdds_bcdec_bc2_bgra(block, out, pitch); }
|
||||
void rdds_decode_block_bc3_bgra(const void *block, void *out, int pitch) { rdds_bcdec_bc3_bgra(block, out, pitch); }
|
||||
@@ -131,7 +131,13 @@ bool rdvd_vfs_service(rdvd_vfs_t *vfs)
|
||||
memset(&result, 0, sizeof(result));
|
||||
result.ticket = request.ticket; result.bytes = -1;
|
||||
bytes = request.bytes < 65536 ? request.bytes : 65536;
|
||||
if (filestream_seek(request.file, (int64_t)request.offset,
|
||||
/* At the offset in one call; seek and read where there is none */
|
||||
if ((result.bytes = filestream_read_at(request.file, request.destination,
|
||||
(int64_t)bytes, (int64_t)request.offset)) >= 0)
|
||||
{
|
||||
if (result.bytes > (int64_t)bytes) result.bytes = -1;
|
||||
}
|
||||
else if (filestream_seek(request.file, (int64_t)request.offset,
|
||||
RETRO_VFS_SEEK_POSITION_START) == 0
|
||||
&& filestream_tell(request.file) == (int64_t)request.offset)
|
||||
{
|
||||
|
||||
@@ -20,27 +20,37 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <formats/rflv_mux.h>
|
||||
#include <formats/rav1_sequence.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
enum flv_output
|
||||
{
|
||||
FLV_HEADER, FLV_VIDEO_CONFIG, FLV_AUDIO_CONFIG, FLV_MEDIA, FLV_IDLE
|
||||
FLV_HEADER, FLV_COLOR, FLV_VIDEO_CONFIG, FLV_AUDIO_CONFIG, FLV_MEDIA, FLV_IDLE
|
||||
};
|
||||
|
||||
enum flv_codec { FLV_AVC, FLV_HEVC, FLV_AV1 };
|
||||
|
||||
struct rflv_mux
|
||||
{
|
||||
uint64_t last[2], input_dts;
|
||||
rflv_span_t spans[3];
|
||||
uint8_t *config;
|
||||
uint8_t *converted;
|
||||
uint8_t *metadata;
|
||||
rav1_sequence_t *av1_sequence;
|
||||
rav1_config_t av1_config;
|
||||
const uint8_t *input;
|
||||
size_t avcc_size, asc_size, limit, size, offset, span_count;
|
||||
size_t converted_size;
|
||||
size_t metadata_size;
|
||||
uint32_t timestamp;
|
||||
int32_t composition;
|
||||
unsigned timescale[2], track;
|
||||
enum flv_output output;
|
||||
uint8_t prefix[16], suffix[4];
|
||||
uint8_t prefix[19], suffix[4];
|
||||
bool pending, scanning, failed, finished, seen[2], keyframe, vcl, idr;
|
||||
bool annexb, hevc, av1;
|
||||
};
|
||||
|
||||
static void flv_uint(uint8_t *out, uint32_t value, unsigned count)
|
||||
@@ -90,6 +100,42 @@ static bool flv_avcc(const uint8_t *data, size_t size)
|
||||
return flv_sets(data, size, &pos, count, 13) && pos == size;
|
||||
}
|
||||
|
||||
static bool flv_hvcc(const uint8_t *data, size_t size)
|
||||
{
|
||||
size_t at = 23;
|
||||
unsigned arrays, count, type, length, present = 0;
|
||||
if (!data || size < 23 || size > 65536 || data[0] != 1
|
||||
|| (data[13] & 0xf0) != 0xf0 || (data[15] & 0xfc) != 0xfc
|
||||
|| (data[16] & 0xfc) != 0xfc || (data[17] & 0xf8) != 0xf8
|
||||
|| (data[18] & 0xf8) != 0xf8
|
||||
|| (data[21] & 3) != 3 || !data[22])
|
||||
return false;
|
||||
for (arrays = data[22]; arrays; arrays--)
|
||||
{
|
||||
if (size - at < 3 || (data[at] & 0x40))
|
||||
return false;
|
||||
type = data[at++] & 63;
|
||||
count = ((unsigned)data[at] << 8) | data[at + 1];
|
||||
at += 2;
|
||||
if (!count)
|
||||
return false;
|
||||
while (count--)
|
||||
{
|
||||
if (size - at < 2)
|
||||
return false;
|
||||
length = ((unsigned)data[at] << 8) | data[at + 1];
|
||||
at += 2;
|
||||
if (length < 2 || length > size - at || (data[at] & 0x80)
|
||||
|| ((data[at] >> 1) & 63) != type || !(data[at + 1] & 7))
|
||||
return false;
|
||||
at += length;
|
||||
}
|
||||
if (type >= 32 && type <= 34)
|
||||
present |= 1u << (type - 32);
|
||||
}
|
||||
return at == size && present == 7;
|
||||
}
|
||||
|
||||
static unsigned flv_bits(const uint8_t *data, size_t size, unsigned *pos, unsigned count)
|
||||
{
|
||||
unsigned i, value = 0;
|
||||
@@ -123,7 +169,7 @@ static bool flv_asc(const uint8_t *data, size_t size)
|
||||
static void flv_tag(rflv_mux_t *m, unsigned track, const void *data,
|
||||
size_t size, uint32_t timestamp, int32_t composition, bool keyframe, bool config)
|
||||
{
|
||||
unsigned bytes = track == 1 ? 5 : 2;
|
||||
unsigned bytes = track == 1 ? (m->hevc && !config && composition ? 8 : 5) : 2;
|
||||
memset(m->prefix, 0, sizeof(m->prefix));
|
||||
m->prefix[0] = track == 1 ? 9 : 8;
|
||||
flv_uint(m->prefix + 1, (uint32_t)size + bytes, 3);
|
||||
@@ -131,7 +177,15 @@ static void flv_tag(rflv_mux_t *m, unsigned track, const void *data,
|
||||
m->prefix[7] = (uint8_t)(timestamp >> 24);
|
||||
m->prefix[11] = track == 1 ? (keyframe ? 0x17 : 0x27) : 0xaf;
|
||||
m->prefix[12] = config ? 0 : 1;
|
||||
if (track == 1)
|
||||
if (track == 1 && (m->hevc || m->av1))
|
||||
{
|
||||
m->prefix[11] = (uint8_t)(0x80 | (keyframe ? 0x10 : 0x20)
|
||||
| (config ? 0 : m->av1 || composition ? 1 : 3));
|
||||
memcpy(m->prefix + 12, m->av1 ? "av01" : "hvc1", 4);
|
||||
if (bytes == 8)
|
||||
flv_uint(m->prefix + 16, (uint32_t)composition, 3);
|
||||
}
|
||||
else if (track == 1)
|
||||
flv_uint(m->prefix + 13, (uint32_t)composition, 3);
|
||||
flv_uint(m->suffix, (uint32_t)size + bytes + 11, 4);
|
||||
m->spans[0].data = m->prefix;
|
||||
@@ -144,11 +198,16 @@ static void flv_tag(rflv_mux_t *m, unsigned track, const void *data,
|
||||
m->pending = true;
|
||||
}
|
||||
|
||||
rflv_mux_t *rflv_mux_new(const rflv_config_t *c)
|
||||
static rflv_mux_t *flv_new(const rflv_config_t *c, enum flv_codec codec)
|
||||
{
|
||||
rflv_mux_t *m;
|
||||
if (!c || (!c->avcc && !c->asc) || !c->max_packet_size || c->max_packet_size > 0xfffffa
|
||||
|| (c->avcc ? !c->video_timescale || !flv_avcc((const uint8_t*)c->avcc, c->avcc_size)
|
||||
bool hevc = codec == FLV_HEVC, av1 = codec == FLV_AV1;
|
||||
if (!c || (!c->avcc && !c->asc) || ((hevc || av1) && !c->avcc)
|
||||
|| !c->max_packet_size || c->max_packet_size > (hevc ? 0xfffff7u : 0xfffffau)
|
||||
|| (c->avcc ? !c->video_timescale
|
||||
|| !(av1 ? c->avcc_size >= 4 && c->avcc_size <= 65536
|
||||
: hevc ? flv_hvcc((const uint8_t*)c->avcc, c->avcc_size)
|
||||
: flv_avcc((const uint8_t*)c->avcc, c->avcc_size))
|
||||
: c->avcc_size || c->video_timescale)
|
||||
|| (c->asc ? !c->audio_timescale || !flv_asc((const uint8_t*)c->asc, c->asc_size)
|
||||
: c->asc_size || c->audio_timescale))
|
||||
@@ -171,6 +230,18 @@ rflv_mux_t *rflv_mux_new(const rflv_config_t *c)
|
||||
m->timescale[0] = c->video_timescale;
|
||||
m->timescale[1] = c->audio_timescale;
|
||||
m->limit = c->max_packet_size;
|
||||
m->hevc = hevc;
|
||||
m->av1 = av1;
|
||||
if (av1)
|
||||
{
|
||||
m->av1_sequence = (rav1_sequence_t*)malloc(sizeof(*m->av1_sequence));
|
||||
if (!m->av1_sequence || !rav1_config_parse(&m->av1_config, m->config, m->avcc_size)
|
||||
|| !rav1_config_sequence(m->av1_sequence, &m->av1_config))
|
||||
{
|
||||
rflv_mux_free(m);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
memcpy(m->prefix, "FLV\1\0\0\0\0\11\0\0\0\0", 13);
|
||||
m->prefix[4] = (c->avcc ? 1 : 0) | (c->asc ? 4 : 0);
|
||||
m->spans[0].data = m->prefix;
|
||||
@@ -180,6 +251,511 @@ rflv_mux_t *rflv_mux_new(const rflv_config_t *c)
|
||||
return m;
|
||||
}
|
||||
|
||||
rflv_mux_t *rflv_mux_new(const rflv_config_t *c)
|
||||
{
|
||||
return flv_new(c, FLV_AVC);
|
||||
}
|
||||
|
||||
rflv_mux_t *rflv_mux_new_hevc(const rflv_config_t *c)
|
||||
{
|
||||
return flv_new(c, FLV_HEVC);
|
||||
}
|
||||
|
||||
rflv_mux_t *rflv_mux_new_av1(const rflv_config_t *c)
|
||||
{
|
||||
return flv_new(c, FLV_AV1);
|
||||
}
|
||||
|
||||
rflv_mux_t *rflv_mux_new_av1_obu(const rflv_config_t *c)
|
||||
{
|
||||
rav1_obu_t obu, sequence;
|
||||
rav1_sequence_t *info;
|
||||
rflv_config_t config;
|
||||
rflv_mux_t *m = NULL;
|
||||
uint8_t *data;
|
||||
size_t at = 0, used;
|
||||
int result;
|
||||
if (!c || !c->avcc || !c->avcc_size || c->avcc_size > 65532)
|
||||
return NULL;
|
||||
memset(&sequence, 0, sizeof(sequence));
|
||||
while ((result = rav1_obu_next(&obu, (const uint8_t*)c->avcc, c->avcc_size, &at, false)) > 0)
|
||||
{
|
||||
if (obu.type == 1)
|
||||
{
|
||||
if (sequence.data)
|
||||
return NULL;
|
||||
sequence = obu;
|
||||
}
|
||||
else if (obu.type != 2 && obu.type != 5 && obu.type != 15)
|
||||
return NULL;
|
||||
}
|
||||
if (result < 0 || !sequence.data)
|
||||
return NULL;
|
||||
info = (rav1_sequence_t*)malloc(sizeof(*info));
|
||||
if (!info)
|
||||
return NULL;
|
||||
if (!rav1_sequence_parse(info, sequence.payload, sequence.payload_size))
|
||||
{
|
||||
free(info);
|
||||
return NULL;
|
||||
}
|
||||
data = (uint8_t*)malloc(c->avcc_size + 4);
|
||||
if (data)
|
||||
{
|
||||
data[0] = 0x81;
|
||||
data[1] = (uint8_t)((info->profile << 5) | info->operating_points[0].level);
|
||||
data[2] = (uint8_t)((info->operating_points[0].tier << 7)
|
||||
| ((info->bit_depth > 8) << 6) | ((info->bit_depth == 12) << 5)
|
||||
| (info->monochrome << 4) | (info->subsampling_x << 3)
|
||||
| (info->subsampling_y << 2) | info->chroma_sample_position);
|
||||
data[3] = 0;
|
||||
memcpy(data + 4, sequence.data, sequence.size);
|
||||
used = sequence.size + 4;
|
||||
at = 0;
|
||||
while (rav1_obu_next(&obu, (const uint8_t*)c->avcc, c->avcc_size, &at, false) > 0)
|
||||
if (obu.type == 5)
|
||||
{
|
||||
memcpy(data + used, obu.data, obu.size);
|
||||
used += obu.size;
|
||||
}
|
||||
config = *c;
|
||||
config.avcc = data;
|
||||
config.avcc_size = used;
|
||||
m = rflv_mux_new_av1(&config);
|
||||
free(data);
|
||||
}
|
||||
free(info);
|
||||
return m;
|
||||
}
|
||||
|
||||
struct flv_metadata_writer
|
||||
{
|
||||
uint8_t *data;
|
||||
size_t used;
|
||||
bool failed;
|
||||
};
|
||||
|
||||
static void flv_metadata_bytes(struct flv_metadata_writer *w,
|
||||
const void *data, size_t size)
|
||||
{
|
||||
if (w->failed || size > 512 - w->used)
|
||||
{
|
||||
w->failed = true;
|
||||
return;
|
||||
}
|
||||
memcpy(w->data + w->used, data, size);
|
||||
w->used += size;
|
||||
}
|
||||
|
||||
static void flv_metadata_name(struct flv_metadata_writer *w,
|
||||
const char *name, bool property)
|
||||
{
|
||||
uint8_t header[3];
|
||||
size_t size = strlen(name);
|
||||
header[0] = 2;
|
||||
header[1] = (uint8_t)(size >> 8);
|
||||
header[2] = (uint8_t)size;
|
||||
flv_metadata_bytes(w, header + (property ? 1 : 0), property ? 2 : 3);
|
||||
flv_metadata_bytes(w, name, size);
|
||||
}
|
||||
|
||||
static void flv_metadata_object(struct flv_metadata_writer *w, const char *name)
|
||||
{
|
||||
static const uint8_t marker = 3;
|
||||
flv_metadata_name(w, name, true);
|
||||
flv_metadata_bytes(w, &marker, 1);
|
||||
}
|
||||
|
||||
static void flv_metadata_end(struct flv_metadata_writer *w)
|
||||
{
|
||||
static const uint8_t end[] = {0, 0, 9};
|
||||
flv_metadata_bytes(w, end, sizeof(end));
|
||||
}
|
||||
|
||||
/* Encode the nonnegative rational as binary64 without host float assumptions. */
|
||||
static void flv_metadata_number(struct flv_metadata_writer *w, const char *name,
|
||||
uint32_t numerator, unsigned denominator)
|
||||
{
|
||||
uint64_t n = numerator, d = denominator, fraction = 0, bits = 0, remainder;
|
||||
int exponent = 0;
|
||||
unsigned i;
|
||||
if (n)
|
||||
{
|
||||
while (n < d)
|
||||
{
|
||||
n <<= 1;
|
||||
exponent--;
|
||||
}
|
||||
while (n >= d * 2)
|
||||
{
|
||||
d <<= 1;
|
||||
exponent++;
|
||||
}
|
||||
remainder = n - d;
|
||||
for (i = 0; i < 52; i++)
|
||||
{
|
||||
remainder <<= 1;
|
||||
fraction <<= 1;
|
||||
if (remainder >= d)
|
||||
{
|
||||
remainder -= d;
|
||||
fraction++;
|
||||
}
|
||||
}
|
||||
if (remainder * 2 > d || (remainder * 2 == d && (fraction & 1)))
|
||||
fraction++;
|
||||
if (fraction == ((uint64_t)1 << 52))
|
||||
{
|
||||
fraction = 0;
|
||||
exponent++;
|
||||
}
|
||||
bits = ((uint64_t)(exponent + 1023) << 52) | fraction;
|
||||
}
|
||||
flv_metadata_name(w, name, true);
|
||||
if (w->failed || 512 - w->used < 9)
|
||||
{
|
||||
w->failed = true;
|
||||
return;
|
||||
}
|
||||
w->data[w->used++] = 0;
|
||||
for (i = 0; i < 8; i++)
|
||||
w->data[w->used++] = (uint8_t)(bits >> (56 - i * 8));
|
||||
}
|
||||
|
||||
bool rflv_mux_set_color(rflv_mux_t *m, const video_color_metadata_t *c,
|
||||
unsigned depth)
|
||||
{
|
||||
static const char *const xy[] =
|
||||
{ "redX", "redY", "greenX", "greenY", "blueX", "blueY", "whitePointX", "whitePointY" };
|
||||
struct flv_metadata_writer w;
|
||||
static const uint8_t object = 3;
|
||||
unsigned i;
|
||||
if (!m || !c || (!m->hevc && !m->av1) || m->failed || m->metadata
|
||||
|| m->output != FLV_HEADER || !m->pending
|
||||
|| (depth != 8 && depth != 10 && depth != 12)
|
||||
|| (m->hevc && (depth != 8u + (m->config[17] & 7)
|
||||
|| ((m->config[16] & 3) && depth != 8u + (m->config[18] & 7))))
|
||||
|| (m->av1 && (depth != m->av1_sequence->bit_depth
|
||||
|| (c->primaries && c->primaries != m->av1_sequence->color_primaries)
|
||||
|| (c->transfer && c->transfer != m->av1_sequence->transfer_characteristics)
|
||||
|| (c->matrix && c->matrix != m->av1_sequence->matrix_coefficients)
|
||||
|| (c->range && c->range != m->av1_sequence->color_range + 1)))
|
||||
|| c->primaries > 255 || c->transfer > 255 || c->matrix > 255
|
||||
|| c->range > 2 || c->max_cll > 10000 || c->max_fall > 10000
|
||||
|| (c->max_cll && c->max_fall > c->max_cll))
|
||||
return false;
|
||||
if (c->mastering.present)
|
||||
{
|
||||
if (c->mastering.present != VIDEO_MASTERING_DISPLAY_COMPLETE
|
||||
|| c->mastering.luminance_max < 50000 || c->mastering.luminance_max > 100000000
|
||||
|| !c->mastering.luminance_min || c->mastering.luminance_min > 50000)
|
||||
return false;
|
||||
for (i = 0; i < 8; i++)
|
||||
if (c->mastering.chromaticity[i] < 5
|
||||
|| c->mastering.chromaticity[i] > (i & 1 ? 42000 : 37000))
|
||||
return false;
|
||||
}
|
||||
w.data = (uint8_t*)malloc(512);
|
||||
if (!w.data)
|
||||
return false;
|
||||
w.used = 0;
|
||||
w.failed = false;
|
||||
flv_metadata_name(&w, "colorInfo", false);
|
||||
flv_metadata_bytes(&w, &object, 1);
|
||||
flv_metadata_object(&w, "colorConfig");
|
||||
flv_metadata_number(&w, "bitDepth", depth, 1);
|
||||
if (c->primaries)
|
||||
flv_metadata_number(&w, "colorPrimaries", c->primaries, 1);
|
||||
if (c->transfer)
|
||||
flv_metadata_number(&w, "transferCharacteristics", c->transfer, 1);
|
||||
if (c->matrix)
|
||||
flv_metadata_number(&w, "matrixCoefficients", c->matrix, 1);
|
||||
flv_metadata_end(&w);
|
||||
if (c->max_cll || c->max_fall)
|
||||
{
|
||||
flv_metadata_object(&w, "hdrCll");
|
||||
if (c->max_cll)
|
||||
flv_metadata_number(&w, "maxCLL", c->max_cll, 1);
|
||||
if (c->max_fall)
|
||||
flv_metadata_number(&w, "maxFall", c->max_fall, 1);
|
||||
flv_metadata_end(&w);
|
||||
}
|
||||
if (c->mastering.present)
|
||||
{
|
||||
flv_metadata_object(&w, "hdrMdcv");
|
||||
for (i = 0; i < 8; i++)
|
||||
flv_metadata_number(&w, xy[i], (c->mastering.chromaticity[i] + 2u) / 5, 10000);
|
||||
flv_metadata_number(&w, "maxLuminance", c->mastering.luminance_max, 10000);
|
||||
flv_metadata_number(&w, "minLuminance", c->mastering.luminance_min, 10000);
|
||||
flv_metadata_end(&w);
|
||||
}
|
||||
flv_metadata_end(&w);
|
||||
if (w.failed)
|
||||
{
|
||||
free(w.data);
|
||||
return false;
|
||||
}
|
||||
m->metadata = w.data;
|
||||
m->metadata_size = w.used;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool flv_annexb(const uint8_t *data, size_t size, size_t *offset,
|
||||
const uint8_t **nal, size_t *length)
|
||||
{
|
||||
size_t start = *offset, at, zeros = 0, end;
|
||||
while (start < size && !data[start])
|
||||
start++;
|
||||
if (start - *offset < 2 || start == size || data[start] != 1)
|
||||
return false;
|
||||
start++;
|
||||
end = size;
|
||||
for (at = start; at < size; at++)
|
||||
{
|
||||
if (!data[at])
|
||||
zeros++;
|
||||
else
|
||||
{
|
||||
if (data[at] == 1 && zeros >= 2)
|
||||
{
|
||||
end = at - zeros;
|
||||
break;
|
||||
}
|
||||
zeros = 0;
|
||||
}
|
||||
}
|
||||
*offset = at < size ? end : size;
|
||||
if (at == size)
|
||||
end -= zeros;
|
||||
if (end <= start)
|
||||
return false;
|
||||
*nal = data + start;
|
||||
*length = end - start;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct flv_rbsp
|
||||
{
|
||||
const uint8_t *data;
|
||||
size_t size, at;
|
||||
unsigned byte, left, zeros;
|
||||
bool failed;
|
||||
};
|
||||
|
||||
static unsigned flv_rbsp_bits(struct flv_rbsp *b, unsigned count)
|
||||
{
|
||||
unsigned value = 0, next;
|
||||
while (count--)
|
||||
{
|
||||
if (!b->left)
|
||||
{
|
||||
if (b->at == b->size)
|
||||
goto failed;
|
||||
next = b->data[b->at++];
|
||||
if (b->zeros == 2 && next == 3)
|
||||
{
|
||||
if (b->at == b->size || b->data[b->at] > 3)
|
||||
goto failed;
|
||||
b->zeros = 0;
|
||||
next = b->data[b->at++];
|
||||
}
|
||||
b->zeros = next ? 0 : b->zeros < 2 ? b->zeros + 1 : 2;
|
||||
b->byte = next;
|
||||
b->left = 8;
|
||||
}
|
||||
value = (value << 1) | ((b->byte >> --b->left) & 1);
|
||||
}
|
||||
return value;
|
||||
failed:
|
||||
b->failed = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned flv_rbsp_ue(struct flv_rbsp *b)
|
||||
{
|
||||
unsigned zeros = 0;
|
||||
while (!b->failed && !flv_rbsp_bits(b, 1))
|
||||
if (++zeros == 32)
|
||||
b->failed = true;
|
||||
if (b->failed)
|
||||
return ~0u;
|
||||
return ((1u << zeros) - 1) + flv_rbsp_bits(b, zeros);
|
||||
}
|
||||
|
||||
static bool flv_hevc_info(const uint8_t *sps, size_t size, uint8_t *header)
|
||||
{
|
||||
struct flv_rbsp b;
|
||||
unsigned layers, nested, flags = 0, i, j, chroma, luma, chroma_depth;
|
||||
memset(&b, 0, sizeof(b));
|
||||
b.data = sps + 2;
|
||||
b.size = size - 2;
|
||||
flv_rbsp_bits(&b, 4);
|
||||
layers = flv_rbsp_bits(&b, 3);
|
||||
nested = flv_rbsp_bits(&b, 1);
|
||||
if (layers > 6)
|
||||
return false;
|
||||
for (i = 1; i <= 12; i++)
|
||||
header[i] = (uint8_t)flv_rbsp_bits(&b, 8);
|
||||
for (i = 0; i < layers; i++)
|
||||
flags |= flv_rbsp_bits(&b, 2) << (i * 2);
|
||||
if (layers)
|
||||
for (i = layers; i < 8; i++)
|
||||
if (flv_rbsp_bits(&b, 2))
|
||||
return false;
|
||||
for (i = 0; i < layers; i++)
|
||||
{
|
||||
if (flags & (2u << (i * 2)))
|
||||
for (j = 0; j < 11; j++)
|
||||
flv_rbsp_bits(&b, 8);
|
||||
if (flags & (1u << (i * 2)))
|
||||
flv_rbsp_bits(&b, 8);
|
||||
}
|
||||
if (flv_rbsp_ue(&b) > 15)
|
||||
return false;
|
||||
chroma = flv_rbsp_ue(&b);
|
||||
if (chroma > 3)
|
||||
return false;
|
||||
if (chroma == 3)
|
||||
flv_rbsp_bits(&b, 1);
|
||||
if (!flv_rbsp_ue(&b) || !flv_rbsp_ue(&b))
|
||||
return false;
|
||||
if (flv_rbsp_bits(&b, 1))
|
||||
for (i = 0; i < 4; i++)
|
||||
flv_rbsp_ue(&b);
|
||||
luma = flv_rbsp_ue(&b);
|
||||
chroma_depth = flv_rbsp_ue(&b);
|
||||
if (b.failed || luma > 6 || chroma_depth > 6)
|
||||
return false;
|
||||
header[0] = 1;
|
||||
header[13] = 0xf0;
|
||||
header[15] = 0xfc;
|
||||
header[16] = (uint8_t)(0xfc | chroma);
|
||||
header[17] = (uint8_t)(0xf8 | luma);
|
||||
header[18] = (uint8_t)(0xf8 | chroma_depth);
|
||||
header[21] = (uint8_t)(((layers + 1) << 3) | (nested << 2) | 3);
|
||||
header[22] = 3;
|
||||
return true;
|
||||
}
|
||||
|
||||
rflv_mux_t *rflv_mux_new_hevc_annexb(const rflv_config_t *c)
|
||||
{
|
||||
const uint8_t *sets[3] = {NULL, NULL, NULL}, *nal;
|
||||
size_t lengths[3] = {0, 0, 0}, at = 0, size, total = 38;
|
||||
unsigned type, i;
|
||||
uint8_t *hvcc;
|
||||
rflv_config_t config;
|
||||
rflv_mux_t *m;
|
||||
if (!c || !c->avcc || !c->avcc_size || c->avcc_size > 65536
|
||||
|| !c->max_packet_size || c->max_packet_size > 0xfffff7)
|
||||
return NULL;
|
||||
while (at < c->avcc_size)
|
||||
{
|
||||
if (!flv_annexb((const uint8_t*)c->avcc, c->avcc_size, &at, &nal, &size)
|
||||
|| size < 3 || size > 65535 || (nal[0] & 0x81) || nal[1] != 1)
|
||||
return NULL;
|
||||
type = (nal[0] >> 1) & 63;
|
||||
if (type < 32 || type > 34 || sets[type - 32] || size > 65536 - total)
|
||||
return NULL;
|
||||
sets[type - 32] = nal;
|
||||
lengths[type - 32] = size;
|
||||
total += size;
|
||||
}
|
||||
if (!sets[0] || !sets[1] || !sets[2])
|
||||
return NULL;
|
||||
hvcc = (uint8_t*)calloc(1, total);
|
||||
if (!hvcc)
|
||||
return NULL;
|
||||
if (!flv_hevc_info(sets[1], lengths[1], hvcc))
|
||||
{
|
||||
free(hvcc);
|
||||
return NULL;
|
||||
}
|
||||
at = 23;
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
hvcc[at++] = (uint8_t)(0xa0 + i);
|
||||
flv_uint(hvcc + at, 1, 2);
|
||||
flv_uint(hvcc + at + 2, (uint32_t)lengths[i], 2);
|
||||
memcpy(hvcc + at + 4, sets[i], lengths[i]);
|
||||
at += lengths[i] + 4;
|
||||
}
|
||||
config = *c;
|
||||
config.avcc = hvcc;
|
||||
config.avcc_size = total;
|
||||
m = rflv_mux_new_hevc(&config);
|
||||
free(hvcc);
|
||||
if (!m)
|
||||
return NULL;
|
||||
m->converted = (uint8_t*)malloc(m->limit);
|
||||
if (!m->converted)
|
||||
{
|
||||
rflv_mux_free(m);
|
||||
return NULL;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
rflv_mux_t *rflv_mux_new_annexb(const rflv_config_t *c)
|
||||
{
|
||||
rflv_config_t config;
|
||||
rflv_mux_t *m;
|
||||
const uint8_t *nal, *sps = NULL, *pps = NULL;
|
||||
uint8_t *avcc;
|
||||
size_t offset = 0, size, sps_size = 0, pps_size = 0;
|
||||
if (!c || !c->avcc || !c->avcc_size || c->avcc_size > 65536
|
||||
|| !c->max_packet_size || c->max_packet_size > 0xfffffa)
|
||||
return NULL;
|
||||
while (offset < c->avcc_size)
|
||||
{
|
||||
unsigned type;
|
||||
if (!flv_annexb((const uint8_t*)c->avcc, c->avcc_size, &offset, &nal, &size)
|
||||
|| size > 65535 || (nal[0] & 0x80))
|
||||
return NULL;
|
||||
type = nal[0] & 31;
|
||||
if (type == 7 && !sps && size >= 4)
|
||||
{
|
||||
sps = nal;
|
||||
sps_size = size;
|
||||
}
|
||||
else if (type == 8 && !pps)
|
||||
{
|
||||
pps = nal;
|
||||
pps_size = size;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
if (!sps || !pps || sps_size + pps_size > 65536 - 11)
|
||||
return NULL;
|
||||
size = sps_size + pps_size + 11;
|
||||
avcc = (uint8_t*)malloc(size);
|
||||
if (!avcc)
|
||||
return NULL;
|
||||
avcc[0] = 1;
|
||||
memcpy(avcc + 1, sps + 1, 3);
|
||||
avcc[4] = 255;
|
||||
avcc[5] = 225;
|
||||
flv_uint(avcc + 6, (uint32_t)sps_size, 2);
|
||||
memcpy(avcc + 8, sps, sps_size);
|
||||
avcc[8 + sps_size] = 1;
|
||||
flv_uint(avcc + 9 + sps_size, (uint32_t)pps_size, 2);
|
||||
memcpy(avcc + 11 + sps_size, pps, pps_size);
|
||||
config = *c;
|
||||
config.avcc = avcc;
|
||||
config.avcc_size = size;
|
||||
m = rflv_mux_new(&config);
|
||||
free(avcc);
|
||||
if (!m)
|
||||
return NULL;
|
||||
m->converted = (uint8_t*)malloc(m->limit);
|
||||
if (!m->converted)
|
||||
{
|
||||
rflv_mux_free(m);
|
||||
return NULL;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
static bool flv_milliseconds(uint64_t ticks, unsigned scale, uint32_t *result)
|
||||
{
|
||||
uint64_t seconds = ticks / scale;
|
||||
@@ -209,6 +785,7 @@ int rflv_mux_push(rflv_mux_t *m, unsigned track, const void *data,
|
||||
return RFLV_ERROR;
|
||||
composition = (int64_t)pts_ms - dts_ms;
|
||||
if ((track == 1 && (composition < -0x800000 || composition > 0x7fffff
|
||||
|| (m->av1 && pts != dts)
|
||||
|| (!m->seen[0] && !keyframe))) || (track == 2 && pts != dts))
|
||||
return RFLV_ERROR;
|
||||
m->track = track;
|
||||
@@ -220,6 +797,8 @@ int rflv_mux_push(rflv_mux_t *m, unsigned track, const void *data,
|
||||
m->composition = (int32_t)composition;
|
||||
m->keyframe = keyframe;
|
||||
m->vcl = m->idr = false;
|
||||
m->annexb = false;
|
||||
m->converted_size = 0;
|
||||
m->output = FLV_MEDIA;
|
||||
m->scanning = track == 1;
|
||||
if (track == 2)
|
||||
@@ -227,8 +806,22 @@ int rflv_mux_push(rflv_mux_t *m, unsigned track, const void *data,
|
||||
return RFLV_PROGRESS;
|
||||
}
|
||||
|
||||
int rflv_mux_push_annexb(rflv_mux_t *m, const void *data, size_t size,
|
||||
uint64_t dts, uint64_t pts, bool keyframe)
|
||||
{
|
||||
int result;
|
||||
if (!m || !m->converted)
|
||||
return RFLV_ERROR;
|
||||
result = rflv_mux_push(m, 1, data, size, dts, pts, keyframe);
|
||||
if (result == RFLV_PROGRESS)
|
||||
m->annexb = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
int rflv_mux_step(rflv_mux_t *m)
|
||||
{
|
||||
const uint8_t *nal;
|
||||
size_t size;
|
||||
uint32_t length;
|
||||
unsigned type;
|
||||
if (!m || m->failed)
|
||||
@@ -244,22 +837,70 @@ int rflv_mux_step(rflv_mux_t *m)
|
||||
if (!m->vcl || (!m->seen[0] && !m->idr))
|
||||
goto failed;
|
||||
m->scanning = false;
|
||||
flv_tag(m, 1, m->input, m->size, m->timestamp, m->composition, m->keyframe, false);
|
||||
flv_tag(m, 1, m->annexb ? m->converted : m->input,
|
||||
m->annexb ? m->converted_size : m->size,
|
||||
m->timestamp, m->composition, m->keyframe, false);
|
||||
return RFLV_PACKET;
|
||||
}
|
||||
if (m->size - m->offset < 4)
|
||||
if (m->av1)
|
||||
{
|
||||
rav1_obu_t obu;
|
||||
if (rav1_obu_next(&obu, m->input, m->size, &m->offset, false) != 1
|
||||
|| !obu.type || (obu.type >= 8 && obu.type != 15)
|
||||
|| obu.spatial_id)
|
||||
goto failed;
|
||||
if (obu.type == 1 && (obu.payload_size != m->av1_config.sequence.payload_size
|
||||
|| memcmp(obu.payload, m->av1_config.sequence.payload, obu.payload_size)))
|
||||
goto failed;
|
||||
if (obu.type == 3 || obu.type == 6)
|
||||
{
|
||||
if (!obu.payload_size)
|
||||
goto failed;
|
||||
m->vcl = true;
|
||||
m->idr = m->idr || m->av1_sequence->reduced_still_picture_header
|
||||
|| (obu.payload[0] & 0xe0) == 0;
|
||||
}
|
||||
return RFLV_PROGRESS;
|
||||
}
|
||||
if (m->annexb)
|
||||
{
|
||||
if (!flv_annexb(m->input, m->size, &m->offset, &nal, &size)
|
||||
|| m->limit - m->converted_size < 4
|
||||
|| size > m->limit - m->converted_size - 4)
|
||||
goto failed;
|
||||
flv_uint(m->converted + m->converted_size, (uint32_t)size, 4);
|
||||
memcpy(m->converted + m->converted_size + 4, nal, size);
|
||||
m->converted_size += size + 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m->size - m->offset < 4)
|
||||
goto failed;
|
||||
length = ((uint32_t)m->input[m->offset] << 24) | ((uint32_t)m->input[m->offset + 1] << 16)
|
||||
| ((uint32_t)m->input[m->offset + 2] << 8) | m->input[m->offset + 3];
|
||||
m->offset += 4;
|
||||
if (!length || length > m->size - m->offset)
|
||||
goto failed;
|
||||
nal = m->input + m->offset;
|
||||
size = length;
|
||||
m->offset += length;
|
||||
}
|
||||
if (nal[0] & 0x80)
|
||||
goto failed;
|
||||
length = ((uint32_t)m->input[m->offset] << 24) | ((uint32_t)m->input[m->offset + 1] << 16)
|
||||
| ((uint32_t)m->input[m->offset + 2] << 8) | m->input[m->offset + 3];
|
||||
m->offset += 4;
|
||||
if (!length || length > m->size - m->offset || (m->input[m->offset] & 0x80))
|
||||
goto failed;
|
||||
type = m->input[m->offset] & 31;
|
||||
if (m->hevc)
|
||||
{
|
||||
if (size < 2 || !(nal[1] & 7))
|
||||
goto failed;
|
||||
type = (nal[0] >> 1) & 63;
|
||||
m->vcl = m->vcl || type <= 31;
|
||||
m->idr = m->idr || (type >= 16 && type <= 23);
|
||||
return RFLV_PROGRESS;
|
||||
}
|
||||
type = nal[0] & 31;
|
||||
if (!type || type >= 24)
|
||||
goto failed;
|
||||
m->vcl = m->vcl || type <= 5;
|
||||
m->idr = m->idr || type == 5;
|
||||
m->offset += length;
|
||||
return RFLV_PROGRESS;
|
||||
failed:
|
||||
m->failed = true;
|
||||
@@ -277,12 +918,31 @@ bool rflv_mux_get(rflv_mux_t *m, const rflv_span_t **spans, size_t *count)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rflv_mux_get_tag(rflv_mux_t *m, rflv_tag_t *tag)
|
||||
{
|
||||
if (!m || !tag || !m->pending || m->output == FLV_HEADER)
|
||||
return false;
|
||||
tag->spans[0].data = m->prefix + 11;
|
||||
tag->spans[0].size = m->spans[0].size - 11;
|
||||
tag->spans[1] = m->spans[1];
|
||||
tag->timestamp = m->timestamp;
|
||||
tag->type = m->prefix[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rflv_mux_release(rflv_mux_t *m)
|
||||
{
|
||||
if (!m || !m->pending)
|
||||
return false;
|
||||
m->pending = false;
|
||||
if (m->output == FLV_HEADER && m->avcc_size)
|
||||
if (m->output == FLV_HEADER && m->metadata)
|
||||
{
|
||||
m->output = FLV_COLOR;
|
||||
flv_tag(m, 1, m->metadata, m->metadata_size, 0, 0, true, true);
|
||||
/* Information-frame flags preserve existing demuxer interoperability. */
|
||||
m->prefix[11] = 0xd4;
|
||||
}
|
||||
else if ((m->output == FLV_HEADER || m->output == FLV_COLOR) && m->avcc_size)
|
||||
{
|
||||
m->output = FLV_VIDEO_CONFIG;
|
||||
flv_tag(m, 1, m->config, m->avcc_size, 0, 0, true, true);
|
||||
@@ -319,5 +979,8 @@ void rflv_mux_free(rflv_mux_t *m)
|
||||
if (!m)
|
||||
return;
|
||||
free(m->config);
|
||||
free(m->converted);
|
||||
free(m->metadata);
|
||||
free(m->av1_sequence);
|
||||
free(m);
|
||||
}
|
||||
@@ -0,0 +1,463 @@
|
||||
/* Copyright (C) 2010-2026 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (rgif.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <retro_endianness.h>
|
||||
#include <formats/image.h>
|
||||
#include <formats/rgif.h>
|
||||
|
||||
#define RG_CODES 4096 /* 12-bit LZW codes */
|
||||
|
||||
struct rgif
|
||||
{
|
||||
/* the LZW table: each code is its prefix code and one last index */
|
||||
int16_t prefix[RG_CODES];
|
||||
uint8_t first[RG_CODES]; /* the first index of the code's string */
|
||||
uint8_t suffix[RG_CODES];
|
||||
uint8_t stack[RG_CODES]; /* a string, last index first */
|
||||
|
||||
uint8_t pal[256][4]; /* the global table: R, G, B, alpha */
|
||||
uint8_t lpal[256][4]; /* the image's own */
|
||||
uint8_t px[256][4]; /* each index as written: in @order, or
|
||||
0 where it is transparent */
|
||||
|
||||
/* the image_transfer interface's file */
|
||||
const uint8_t *buf;
|
||||
size_t len;
|
||||
size_t avail;
|
||||
};
|
||||
|
||||
/* The file, read as stb_image reads it: past the end, every byte is 0 */
|
||||
struct rg_in
|
||||
{
|
||||
const uint8_t *p;
|
||||
size_t at, len;
|
||||
};
|
||||
|
||||
static unsigned rg_get8(struct rg_in *in)
|
||||
{
|
||||
return in->at < in->len ? in->p[in->at++] : 0;
|
||||
}
|
||||
|
||||
static unsigned rg_get16(struct rg_in *in)
|
||||
{
|
||||
unsigned lo = rg_get8(in);
|
||||
return lo | (rg_get8(in) << 8);
|
||||
}
|
||||
|
||||
static void rg_skip(struct rg_in *in, size_t n)
|
||||
{
|
||||
in->at = n < in->len - in->at ? in->at + n : in->len;
|
||||
}
|
||||
|
||||
static void rg_put(uint8_t *d, unsigned order, unsigned r, unsigned g,
|
||||
unsigned b, unsigned a)
|
||||
{
|
||||
switch (order)
|
||||
{
|
||||
case RGIF_ARGB:
|
||||
d[0] = (uint8_t)a; d[1] = (uint8_t)r; d[2] = (uint8_t)g; d[3] = (uint8_t)b;
|
||||
break;
|
||||
case RGIF_BGRA:
|
||||
d[0] = (uint8_t)b; d[1] = (uint8_t)g; d[2] = (uint8_t)r; d[3] = (uint8_t)a;
|
||||
break;
|
||||
case RGIF_ABGR:
|
||||
d[0] = (uint8_t)a; d[1] = (uint8_t)b; d[2] = (uint8_t)g; d[3] = (uint8_t)r;
|
||||
break;
|
||||
default:
|
||||
d[0] = (uint8_t)r; d[1] = (uint8_t)g; d[2] = (uint8_t)b; d[3] = (uint8_t)a;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void rg_colours(struct rg_in *in, uint8_t pal[256][4], unsigned n,
|
||||
int transparent)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
pal[i][0] = (uint8_t)rg_get8(in);
|
||||
pal[i][1] = (uint8_t)rg_get8(in);
|
||||
pal[i][2] = (uint8_t)rg_get8(in);
|
||||
pal[i][3] = (int)i == transparent ? 0 : 255;
|
||||
}
|
||||
}
|
||||
|
||||
static int rg_header(struct rg_in *in, unsigned *w, unsigned *h)
|
||||
{
|
||||
unsigned v;
|
||||
if (rg_get8(in) != 'G' || rg_get8(in) != 'I' || rg_get8(in) != 'F'
|
||||
|| rg_get8(in) != '8')
|
||||
return 0;
|
||||
v = rg_get8(in);
|
||||
if ((v != '7' && v != '9') || rg_get8(in) != 'a')
|
||||
return 0;
|
||||
*w = rg_get16(in);
|
||||
*h = rg_get16(in);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool rgif_size(const uint8_t *data, size_t len,
|
||||
unsigned *width, unsigned *height)
|
||||
{
|
||||
struct rg_in in;
|
||||
in.p = data; in.at = 0; in.len = data ? len : 0;
|
||||
return rg_header(&in, width, height) != 0;
|
||||
}
|
||||
|
||||
rgif_t *rgif_new(void)
|
||||
{
|
||||
return (rgif_t*)calloc(1, sizeof(rgif_t));
|
||||
}
|
||||
|
||||
void rgif_free(rgif_t *g)
|
||||
{
|
||||
free(g);
|
||||
}
|
||||
|
||||
/* Where the image's pixels go, in the order its LZW stream gives them */
|
||||
struct rg_raster
|
||||
{
|
||||
uint8_t *out;
|
||||
size_t stride;
|
||||
unsigned x0, x1; /* the image's columns, x0 to x1 - 1 */
|
||||
unsigned y0, y1; /* and rows */
|
||||
unsigned x, y; /* the next pixel */
|
||||
unsigned step; /* rows from one to the next in this pass */
|
||||
unsigned parse; /* interlace passes still to come */
|
||||
uint8_t *row; /* out + y * stride */
|
||||
};
|
||||
|
||||
/* A code's string, out to the image; the rows of an interlaced image in
|
||||
* GIF's four passes */
|
||||
static void rg_emit(rgif_t *g, struct rg_raster *r, unsigned code)
|
||||
{
|
||||
unsigned n = 0;
|
||||
|
||||
do
|
||||
{
|
||||
g->stack[n++] = g->suffix[code];
|
||||
code = (unsigned)g->prefix[code];
|
||||
} while (code < RG_CODES);
|
||||
|
||||
while (n)
|
||||
{
|
||||
if (r->y >= r->y1)
|
||||
return; /* past the image: the rest of the stream is dropped */
|
||||
memcpy(r->row + (size_t)r->x * 4, g->px[g->stack[--n]], 4);
|
||||
if (++r->x >= r->x1)
|
||||
{
|
||||
r->x = r->x0;
|
||||
r->y += r->step;
|
||||
while (r->y >= r->y1 && r->parse)
|
||||
{
|
||||
r->step = 1u << r->parse; /* 8, 4, 2: from row 4, 2, 1 */
|
||||
r->y = r->y0 + r->step / 2;
|
||||
r->parse--;
|
||||
}
|
||||
if (r->y < r->y1)
|
||||
r->row = r->out + (size_t)r->y * r->stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The image's LZW stream, as stb_image reads it; 0 where it is broken */
|
||||
static int rg_raster(rgif_t *g, struct rg_in *in, struct rg_raster *r)
|
||||
{
|
||||
unsigned lzw_cs = rg_get8(in);
|
||||
unsigned clear, codesize, codemask, avail, bits = 0, valid = 0, len = 0;
|
||||
int oldcode = -1, first = 1;
|
||||
unsigned i;
|
||||
|
||||
if (lzw_cs > 12)
|
||||
return 0;
|
||||
clear = 1u << lzw_cs;
|
||||
codesize = lzw_cs + 1;
|
||||
codemask = (1u << codesize) - 1;
|
||||
for (i = 0; i < clear; i++)
|
||||
{
|
||||
g->prefix[i] = -1;
|
||||
g->first[i] = (uint8_t)i;
|
||||
g->suffix[i] = (uint8_t)i;
|
||||
}
|
||||
avail = clear + 2;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
unsigned code;
|
||||
if (valid < codesize)
|
||||
{
|
||||
if (!len)
|
||||
{
|
||||
len = rg_get8(in); /* the next sub-block */
|
||||
if (!len)
|
||||
return 1;
|
||||
}
|
||||
len--;
|
||||
bits |= rg_get8(in) << valid;
|
||||
valid += 8;
|
||||
continue;
|
||||
}
|
||||
code = bits & codemask;
|
||||
bits >>= codesize;
|
||||
valid -= codesize;
|
||||
|
||||
if (code == clear)
|
||||
{
|
||||
codesize = lzw_cs + 1;
|
||||
codemask = (1u << codesize) - 1;
|
||||
avail = clear + 2;
|
||||
oldcode = -1;
|
||||
first = 0;
|
||||
}
|
||||
else if (code == clear + 1)
|
||||
{
|
||||
/* the end: what is left of the sub-blocks is skipped */
|
||||
rg_skip(in, len);
|
||||
while ((len = rg_get8(in)) > 0)
|
||||
rg_skip(in, len);
|
||||
return 1;
|
||||
}
|
||||
else if (code <= avail)
|
||||
{
|
||||
if (first)
|
||||
return 0; /* stb_image wants a clear code first */
|
||||
if (oldcode >= 0)
|
||||
{
|
||||
/* past 4096 a code can never be named; stb_image still
|
||||
* counts them, up to 8192 */
|
||||
if (avail < RG_CODES)
|
||||
{
|
||||
g->prefix[avail] = (int16_t)oldcode;
|
||||
g->first[avail] = g->first[oldcode];
|
||||
g->suffix[avail] = code == avail ? g->first[oldcode]
|
||||
: g->first[code];
|
||||
}
|
||||
if (++avail > 8192)
|
||||
return 0;
|
||||
}
|
||||
else if (code == avail)
|
||||
return 0;
|
||||
|
||||
rg_emit(g, r, code);
|
||||
|
||||
if ((avail & codemask) == 0 && avail <= 0x0fff)
|
||||
{
|
||||
codesize++;
|
||||
codemask = (1u << codesize) - 1;
|
||||
}
|
||||
oldcode = (int)code;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool rgif_decode(rgif_t *g, const uint8_t *data, size_t len,
|
||||
uint8_t *out, size_t stride, unsigned order)
|
||||
{
|
||||
struct rg_in in;
|
||||
unsigned w, h, flags, bgindex, eflags = 0, i;
|
||||
int transparent = -1;
|
||||
uint8_t bg[4];
|
||||
|
||||
in.p = data; in.at = 0; in.len = data ? len : 0;
|
||||
if (!g || !rg_header(&in, &w, &h))
|
||||
return false;
|
||||
flags = rg_get8(&in);
|
||||
bgindex = rg_get8(&in);
|
||||
rg_get8(&in); /* aspect ratio */
|
||||
|
||||
memset(g->pal, 0, sizeof(g->pal));
|
||||
memset(g->lpal, 0, sizeof(g->lpal));
|
||||
if (flags & 0x80)
|
||||
rg_colours(&in, g->pal, 2u << (flags & 7), -1);
|
||||
|
||||
/* Where the image does not reach: the background, opaque, unless the
|
||||
* file names entry 0 (none of it, in stb_image's reading) */
|
||||
if (bgindex > 0)
|
||||
rg_put(bg, order, g->pal[bgindex][0], g->pal[bgindex][1],
|
||||
g->pal[bgindex][2], 255);
|
||||
else
|
||||
memset(bg, 0, sizeof(bg));
|
||||
{
|
||||
unsigned y, x;
|
||||
for (y = 0; y < h; y++)
|
||||
{
|
||||
uint8_t *row = out + (size_t)y * stride;
|
||||
if (!bgindex)
|
||||
memset(row, 0, (size_t)w * 4);
|
||||
else
|
||||
for (x = 0; x < w; x++)
|
||||
memcpy(row + (size_t)x * 4, bg, 4);
|
||||
}
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
unsigned tag = rg_get8(&in);
|
||||
|
||||
if (tag == 0x2c) /* an image */
|
||||
{
|
||||
struct rg_raster r;
|
||||
unsigned x = rg_get16(&in), y = rg_get16(&in);
|
||||
unsigned iw = rg_get16(&in), ih = rg_get16(&in);
|
||||
unsigned lflags;
|
||||
uint8_t (*table)[4];
|
||||
|
||||
if (x + iw > w || y + ih > h)
|
||||
return false;
|
||||
lflags = rg_get8(&in);
|
||||
if (lflags & 0x80)
|
||||
{
|
||||
rg_colours(&in, g->lpal, 2u << (lflags & 7),
|
||||
(eflags & 1) ? transparent : -1);
|
||||
table = g->lpal;
|
||||
}
|
||||
else if (flags & 0x80)
|
||||
table = g->pal;
|
||||
else
|
||||
return false;
|
||||
|
||||
/* a transparent index, or one past the table, leaves the pixel
|
||||
* as stb_image's first frame has it: transparent black */
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
if (table[i][3] > 128)
|
||||
rg_put(g->px[i], order, table[i][0], table[i][1], table[i][2],
|
||||
table[i][3]);
|
||||
else
|
||||
memset(g->px[i], 0, 4);
|
||||
}
|
||||
|
||||
r.out = out;
|
||||
r.stride = stride;
|
||||
r.x0 = x;
|
||||
r.x1 = x + iw;
|
||||
r.y0 = y;
|
||||
r.y1 = y + ih;
|
||||
r.x = x;
|
||||
r.y = iw ? y : r.y1; /* no columns: nothing to draw */
|
||||
if (lflags & 0x40)
|
||||
{
|
||||
r.step = 8;
|
||||
r.parse = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
r.step = 1;
|
||||
r.parse = 0;
|
||||
}
|
||||
r.row = out + (size_t)y * stride;
|
||||
return rg_raster(g, &in, &r) != 0;
|
||||
}
|
||||
else if (tag == 0x21) /* an extension */
|
||||
{
|
||||
unsigned n;
|
||||
if (rg_get8(&in) == 0xf9) /* graphic control */
|
||||
{
|
||||
n = rg_get8(&in);
|
||||
if (n != 4)
|
||||
{
|
||||
/* stb_image skips it and reads on from there */
|
||||
rg_skip(&in, n);
|
||||
continue;
|
||||
}
|
||||
eflags = rg_get8(&in);
|
||||
rg_get16(&in); /* delay */
|
||||
if (transparent >= 0)
|
||||
g->pal[transparent][3] = 255;
|
||||
if (eflags & 1)
|
||||
{
|
||||
transparent = (int)rg_get8(&in);
|
||||
g->pal[transparent][3] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rg_skip(&in, 1);
|
||||
transparent = -1;
|
||||
}
|
||||
}
|
||||
while ((n = rg_get8(&in)) != 0)
|
||||
rg_skip(&in, n);
|
||||
}
|
||||
else
|
||||
return false; /* the trailer before any image, or no GIF block */
|
||||
}
|
||||
}
|
||||
|
||||
bool rgif_header_ready(const uint8_t *data, size_t len)
|
||||
{
|
||||
unsigned w, h;
|
||||
return data && len >= 13 && rgif_size(data, len, &w, &h);
|
||||
}
|
||||
|
||||
bool rgif_set_buf_ptr(rgif_t *g, void *data, size_t len)
|
||||
{
|
||||
if (!g)
|
||||
return false;
|
||||
g->buf = (const uint8_t*)data;
|
||||
g->len = len;
|
||||
g->avail = len;
|
||||
return true;
|
||||
}
|
||||
|
||||
void rgif_set_avail(rgif_t *g, size_t avail)
|
||||
{
|
||||
if (g)
|
||||
g->avail = avail < g->len ? avail : g->len;
|
||||
}
|
||||
|
||||
int rgif_process_image(rgif_t *g, void **buf, size_t size,
|
||||
unsigned *width, unsigned *height, bool supports_rgba)
|
||||
{
|
||||
unsigned w, h, order;
|
||||
size_t len;
|
||||
uint8_t *px;
|
||||
|
||||
if (!g || !g->buf || !buf)
|
||||
return IMAGE_PROCESS_ERROR;
|
||||
len = g->len ? g->len : size;
|
||||
if (g->avail < len)
|
||||
return IMAGE_PROCESS_WAIT; /* nothing taken: the whole file first */
|
||||
if (!rgif_size(g->buf, len, &w, &h) || !w || !h)
|
||||
return IMAGE_PROCESS_ERROR;
|
||||
if (!(px = (uint8_t*)malloc((size_t)w * h * 4)))
|
||||
return IMAGE_PROCESS_ERROR;
|
||||
/* the 32-bit pixel, ARGB or ABGR from the high byte, as it lies in
|
||||
* memory */
|
||||
if (is_little_endian())
|
||||
order = supports_rgba ? RGIF_RGBA : RGIF_BGRA;
|
||||
else
|
||||
order = supports_rgba ? RGIF_ABGR : RGIF_ARGB;
|
||||
if (!rgif_decode(g, g->buf, len, px, (size_t)w * 4, order))
|
||||
{
|
||||
free(px);
|
||||
return IMAGE_PROCESS_ERROR;
|
||||
}
|
||||
*buf = px;
|
||||
*width = w;
|
||||
*height = h;
|
||||
return IMAGE_PROCESS_END;
|
||||
}
|
||||
@@ -9,7 +9,8 @@ was explicitly authorized by the maintainer on 2026-10-13.
|
||||
|
||||
OpenH264 data
|
||||
------------
|
||||
The CAVLC tables in rh264.c and the generated CABAC initialization data in
|
||||
The CAVLC tables in rh264_cavlc_tables.h (shared by rh264.c and
|
||||
rh264_encode.c) and the generated CABAC initialization data in
|
||||
rh264_cabac_tables.h contain data adapted from Cisco OpenH264. These portions
|
||||
remain BSD-2-Clause, with the Cisco copyright, conditions and disclaimer
|
||||
retained in the source and COPYING.OpenH264. The MIT permission applies to
|
||||
|
||||
Loaded 100 of 573 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user