Files
ppsspp/libretro/libretro-common/include/formats/image.h
T
libretroadmin cf9d102864 libretro: vendor libretro-common from RetroArch in-tree
The libretro-common submodule pinned the standalone repository at
76a3d54. It is replaced by an in-tree copy of RetroArch master
(b655a20) holding only what the core uses: the VFS, file, string,
encoding, compat and time sources it already built, the headers they and
the core include, the threading set - rthreads, retro_atomic, retro_spsc
and retro_waitable_spsc, mpsc_stack, retro_triple_buffer,
retro_eventcount, retro_asym_eventcount, retro_procbarrier and tpool,
with features_cpu and rstrtod, which they need - and the codecs that
replace the bundled zlib, zstd, libchdr, libzip and libpng: rinflate and
rdeflate, rzstd, rchd with its LZMA and FLAC decoders, rzip_archive,
rpng and crc32.

stdstring.c, which nothing calls, is no longer built. The threading sources are always built, by both the static Makefile and
CMake; the VFS set stays behind HAVE_LIBRETRO_VFS as before. The codecs
are built by the change that switches the core over to them.
2026-10-08 14:14:37 +02:00

629 lines
29 KiB
C

/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (image.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.
*/
#ifndef __RARCH_IMAGE_CONTEXT_H
#define __RARCH_IMAGE_CONTEXT_H
#include <stdint.h>
#include <stddef.h>
#include <retro_common_api.h>
#include <boolean.h>
RETRO_BEGIN_DECLS
enum image_process_code
{
IMAGE_PROCESS_ERROR = -2,
IMAGE_PROCESS_ERROR_END = -1,
IMAGE_PROCESS_NEXT = 0,
IMAGE_PROCESS_END = 1,
/* The transfer cannot advance until more of the file has been read
* into the buffer (see image_transfer_set_avail); nothing was
* consumed. Only the video still decoders (WEBM, MP4) return
* this, and only after the caller opts in by setting an avail
* short of the full length. */
IMAGE_PROCESS_WAIT = 2
};
struct texture_compressed; /* defined below, after enum image_type_enum */
struct texture_image
{
uint32_t *pixels;
unsigned width;
unsigned height;
bool supports_rgba;
/* When true, ->pixels holds packed XRGB2101010 (10-bit per channel,
* bits [29:20]=R [19:10]=G [9:0]=B) rather than 8-bit RGBA/BGRA. Only
* uploaded as such by drivers that answer TEXTURE_GPU_FORMAT_RGB10A2;
* others get an 8-bit copy via image_texture_narrow_10bit(). */
bool pix10;
/* When true, ->pixels holds RGBA half floats, eight bytes a pixel in
* memory order R,G,B,A - linear light, which no 8-bit encoding
* covers - rather than 32-bit texels. Only uploaded by drivers that
* answer TEXTURE_GPU_FORMAT_RGBA16F; exclusive with ->pix10. */
bool fp16;
/* Optional GPU-native compressed payload (BCn). When non-NULL a
* capable driver may upload it directly and leave ->pixels NULL;
* image_texture_realize_rgba() decodes to ->pixels on demand for
* drivers that cannot sample the format. */
struct texture_compressed *compressed;
};
enum image_type_enum
{
IMAGE_TYPE_NONE = 0,
IMAGE_TYPE_PNG,
IMAGE_TYPE_JPEG,
IMAGE_TYPE_BMP,
IMAGE_TYPE_TGA,
IMAGE_TYPE_WEBP,
IMAGE_TYPE_DDS,
IMAGE_TYPE_WEBM,
IMAGE_TYPE_MP4
};
#define IMAGE_MAX_MIPS 16
/* Several MIPS toolchains (RS90/Dingux, PSP, PS2, ...) predefine the bare
* macro `mips` as 1 in GNU mode, which collides with the `mips` field of
* struct texture_compressed below (and every `->mips` access downstream).
* RA never uses the legacy macro (it uses __mips__), so drop it here. */
#ifdef mips
#undef mips
#endif
/* GPU-native compressed texture formats (block-compressed). Producers
* (currently the DDS loader) report one of these when a texture can be
* uploaded to the GPU as-is; capable drivers skip the CPU decode to
* RGBA8 entirely. Extend with ETC2 or ASTC entries later. */
enum texture_gpu_format
{
TEXTURE_GPU_FORMAT_NONE = 0,
TEXTURE_GPU_FORMAT_BC1, /* DXT1 */
TEXTURE_GPU_FORMAT_BC2, /* DXT3 */
TEXTURE_GPU_FORMAT_BC3, /* DXT5 */
TEXTURE_GPU_FORMAT_BC4, /* RGTC1 (1 channel) */
TEXTURE_GPU_FORMAT_BC5, /* RGTC2 (2 channel) */
TEXTURE_GPU_FORMAT_BC6H_UF, /* BPTC unsigned HDR */
TEXTURE_GPU_FORMAT_BC6H_SF, /* BPTC signed HDR */
TEXTURE_GPU_FORMAT_BC7, /* BPTC LDR */
/* Not a compressed payload and never on a texture_compressed:
* packed XRGB2101010 in ->pixels, flagged by ->pix10. Asked of
* supports_texture_format to learn whether the driver's load and
* in-place update sample it as 10-bit rather than reading its words
* as 8-bit texels. */
TEXTURE_GPU_FORMAT_RGB10A2,
/* Likewise uncompressed: RGBA half floats in ->pixels, flagged by
* ->fp16, eight bytes a pixel in memory order R,G,B,A. Asked of
* supports_texture_format to learn whether the driver's load and
* in-place update keep them as floats. */
TEXTURE_GPU_FORMAT_RGBA16F,
/* Asked of supports_texture_format to learn whether an RGBA16F
* texture drawn in the menu or over content is shown as linear
* scRGB - 1.0 at 80 nits, the 709 primaries - rather than as an
* SDR-encoded one: true only while the output is HDR. */
TEXTURE_GPU_FORMAT_SCRGB
};
/* Numeric mip layout reported by a loader without decoding. Offsets are
* byte offsets from the start of the source file buffer. */
struct image_gpu_layout
{
enum texture_gpu_format format;
unsigned num_mips;
unsigned width[IMAGE_MAX_MIPS];
unsigned height[IMAGE_MAX_MIPS];
size_t offset[IMAGE_MAX_MIPS];
size_t size[IMAGE_MAX_MIPS];
};
struct texture_mip
{
const void *data;
unsigned width;
unsigned height;
size_t size;
};
/* Owned, self-contained compressed payload carried on a texture_image.
* storage holds a private copy of the source file (so the mip pointers
* outlive the loader's buffer) and doubles as the input for the CPU
* decode fallback in image_texture_realize_rgba(). */
struct texture_compressed
{
void *storage;
size_t storage_len;
struct texture_mip *mips;
unsigned num_mips;
enum texture_gpu_format format;
enum image_type_enum type; /* for the CPU-decode fallback */
};
enum image_type_enum image_texture_get_type(const char *path);
/* ---- The still loader ----------------------------------------------
* One decoder for every still the frontend or a core takes from a
* file: the bytes are the caller's, read whole or still arriving, and
* the decode runs in steps that stop at a time budget, at an abort
* hook, or at the byte frontier. image_texture_load() is this loader
* run to completion in one call. */
/* What the caller takes of a still, asked of it once by whoever knows
* (the video driver, a core's own renderer) and handed down. Zero is
* the ordinary 8-bit image, ARGB words. */
typedef struct
{
/* Memory-order R,G,B,A rather than ARGB words */
bool rgba;
/* XRGB2101010 where the file has more than 8 bits a channel */
bool want_10bit;
/* Linear scRGB half floats where the source is HDR (video stills) */
bool want_fp16;
/* A GPU-native compressed payload (BCn) as it lies in the file,
* rather than its CPU decode; the caller then samples it as such or
* decodes it later with image_texture_realize_rgba() */
bool want_compressed;
} image_texture_request_t;
typedef struct image_loader image_loader_t;
enum image_loader_state
{
IMAGE_LOADER_ERROR = -1,
IMAGE_LOADER_RUNNING, /* more steps to take */
IMAGE_LOADER_WAIT, /* needs bytes not yet available */
IMAGE_LOADER_DONE /* image_loader_finish() has the image */
};
/* Whether a decode of @type may start on the first @avail bytes of
* a file still being read: the header is resident for the decoders
* that paint from a prefix (PNG, JPEG, TGA, BMP, the video stills),
* the still's chunk is whole for WEBP. False means wait for the whole
* file. */
bool image_loader_ready(enum image_type_enum type,
const void *buf, size_t avail);
/* A loader for a still of @type. @req may be NULL for the ordinary
* image. NULL when out of memory. */
image_loader_t *image_loader_new(enum image_type_enum type,
const image_texture_request_t *req);
/* The file's bytes: @buf of @len bytes once fully read, of which
* @avail are resident now (@len for a whole file). The buffer is the
* caller's and stays where it is until the loader is freed. False
* when the decoder refused the start. */
bool image_loader_start(image_loader_t *l, const void *buf, size_t len,
size_t avail);
/* More of the file has arrived: the first @avail bytes are resident
* ((size_t)-1: all of them). */
void image_loader_set_avail(image_loader_t *l, size_t avail);
/* Asked between steps of the decode: true abandons it, and the loader
* reports IMAGE_LOADER_ERROR. For decodes that must stop promptly at
* shutdown or once their result is no longer wanted. */
void image_loader_set_abort(image_loader_t *l,
bool (*should_abort)(void *ud), void *ud);
/* Decode until @now's clock reaches @deadline, at least one iteration
* and, between a transfer and its pixels, never both in one step;
* @now NULL runs until the decode is done, aborts, or wants bytes. */
enum image_loader_state image_loader_step(image_loader_t *l,
int64_t (*now)(void), int64_t deadline);
/* The decoded image, the loader's no more: @img's pixels or compressed
* payload are the caller's to free with image_texture_free(). Only
* after IMAGE_LOADER_DONE. */
bool image_loader_finish(image_loader_t *l, struct texture_image *img);
/* Whether the loader's PNG is animated: 1 yes, 0 a still, -1 unknown
* (not a PNG, or the file is not wholly resident). */
int image_loader_png_probe(const image_loader_t *l);
/* The animation stream a video still's decode opened, detached for
* the caller to play on; NULL when there is none. The stream borrows
* the loader's buffer, which the caller keeps alive for it. */
void *image_loader_detach_anim_stream(image_loader_t *l);
void image_loader_free(image_loader_t *l);
/* Resample a decoded still in place: a whole-factor upscale when an
* edge is under @upscale_threshold, then a box reduction to keep the
* longer edge within @downscale_cap; 0 skips either. Half-float
* images are left as they are. In formats/image_texture_scale.c,
* which brings the scaler with it. */
bool image_texture_scale(struct texture_image *img,
unsigned upscale_threshold, unsigned downscale_cap);
bool image_texture_load_buffer(struct texture_image *img,
enum image_type_enum type, void *s, size_t len);
/* The loader run to completion over a whole buffer or a file, with
* @req naming what the caller takes (NULL: the ordinary image). The
* abort hook is asked between steps; it may be NULL. False leaves
* @img empty. */
bool image_texture_load_buffer_request(struct texture_image *img,
enum image_type_enum type, const void *buf, size_t len,
const image_texture_request_t *req,
bool (*should_abort)(void *ud), void *ud);
bool image_texture_load_request(struct texture_image *img,
const char *path, const image_texture_request_t *req,
bool (*should_abort)(void *ud), void *ud);
/* image_texture_load_request answering, from the bytes it read, whether
* the file is an animated PNG: 1 yes, 0 a still, -1 not a PNG or no
* decode. Spares a caller that keeps an animation's bytes a second
* read of every still to ask. @png_probe may be NULL. */
bool image_texture_load_request_ex(struct texture_image *img,
const char *path, const image_texture_request_t *req,
bool (*should_abort)(void *ud), void *ud, int *png_probe);
/* Run @fn for every index below @n, across the cores at once where
* there are threads: on Apple over the dispatch pool, elsewhere on
* threads of its own with the caller working alongside, and in order
* on one thread where there is only one. Returns once every call has.
* In formats/image_texture_set.c. */
void image_texture_set_run(unsigned n,
void (*fn)(unsigned i, void *ud), void *ud);
/* image_texture_set_run with @thread_done called on each thread of
* the set's own as it finishes, for state it kept per thread - the
* data_transfer pool above all, which a thread that exits with it
* full would leave resident for good. Not called on the caller's
* thread, nor on a dispatch pool's, which live on. May be NULL. */
void image_texture_set_run_ex(unsigned n,
void (*fn)(unsigned i, void *ud), void *ud,
void (*thread_done)(void));
/* Decode the @n files @paths name into @imgs together, each as
* image_texture_load_request does with @req; a path that is NULL,
* empty or unreadable leaves its image empty. Returns how many
* decoded. In formats/image_texture_set.c. */
unsigned image_texture_load_set(const char *const *paths,
struct texture_image *imgs, unsigned n,
const image_texture_request_t *req);
/* ->pix10 is an ask on the way in and an answer on the way out: set
* it before the call to have a decoder that can emit XRGB2101010 do
* so, and read it after to find out whether it did. Clear on entry
* means the ordinary 8-bit image, as before. */
bool image_texture_load(struct texture_image *img, const char *path);
/* image_texture_load with an abort hook: both decode stages are
* incremental (one chunk / one pass per step) and @should_abort is
* asked between steps; returning true abandons the decode, which then
* fails cleanly. For decodes on worker threads that must stop promptly
* at shutdown or when their result is no longer wanted. @should_abort
* may be NULL. */
bool image_texture_load_ex(struct texture_image *img, const char *path,
bool (*should_abort)(void *ud), void *ud);
void image_texture_free(struct texture_image *img);
/* Force a CPU decode of a compressed texture_image into ->pixels (RGBA8).
* No-op returning true if ->pixels is already present. The fallback when
* a driver cannot sample img->compressed->format. */
bool image_texture_realize_rgba(struct texture_image *img);
/* Narrow a texture_image whose ->pixels hold packed XRGB2101010 down to
* 8 bits a channel in place (and clear ->pix10), for drivers that cannot
* sample a 10-bit texture: ARGB8888 words, or memory-order R,G,B,A when
* ->supports_rgba is set, so ->supports_rgba stays true of the result.
* No-op unless ->pix10 is set. */
void image_texture_narrow_10bit(struct texture_image *img);
/* Rewrite ->pixels, linear 32-bit texels, in place as GX RGBA8 tiles:
* the layout the GameCube/Wii GPU samples straight from memory, 4x4
* tiles of 64 bytes holding the AR halves of a tile's sixteen texels
* and then their GB halves. ->width and ->height are rounded down to
* multiples of 4, which the layout requires. Decoders always emit
* linear images; only a consumer that hands the pixels to the GX
* itself asks for this. False, with @img untouched, when the four-row
* scratch cannot be allocated. */
bool image_texture_tile_gx(struct texture_image *img);
/* Write @width x @height linear 32-bit texels, @src (ARGB8888 words,
* or memory-order R,G,B,A when @rgba), to @dst as GX RGBA8 tiles of a
* texture rounded up to multiples of 4 a side, the padding clear: the
* layout image_texture_tile_gx() makes, but in a buffer of its own and
* keeping every texel. @dst holds image_texture_tile_gx_size() bytes. */
void image_texture_tile_gx_copy(uint16_t *dst, const uint32_t *src,
unsigned width, unsigned height, bool rgba);
/* The bytes image_texture_tile_gx_copy() writes for @width x @height */
size_t image_texture_tile_gx_size(unsigned width, unsigned height);
/* Image transfer */
void image_transfer_free(void *data, enum image_type_enum type);
void *image_transfer_new(enum image_type_enum type);
bool image_transfer_start(void *data, enum image_type_enum type);
void image_transfer_set_buffer_ptr(
void *data,
enum image_type_enum type,
void *ptr,
size_t len);
int image_transfer_process(
void *data,
enum image_type_enum type,
uint32_t **buf,
size_t len,
unsigned *width,
unsigned *height,
bool supports_rgba);
/* Report the GPU-native compressed mip layout of an already-started
* transfer without decoding. Returns false for formats that must be
* CPU-decoded (non-DDS, uncompressed DDS, premultiplied, BC4/5/6H). */
bool image_transfer_get_gpu_layout(
void *data,
enum image_type_enum type,
size_t len,
struct image_gpu_layout *out);
bool image_transfer_iterate(void *data, enum image_type_enum type);
/* True when the last image_transfer_iterate stopped because the decoder
* reached the resident byte frontier declared by
* image_transfer_set_avail, rather than because the image finished.
* Both cases return false from iterate, so a caller feeding a growing
* read MUST consult this before concluding the transfer is complete -
* treating a wall as completion decodes a partially-gathered image and
* fails. Always false for types without an avail wall. */
bool image_transfer_need_more(void *data, enum image_type_enum type);
/* Video-to-image transfers (WEBM, MP4) keep their decoder stream open
* after a successful image_transfer_process, positioned just past the
* first displayed frame. This takes ownership of that stream so the
* caller can continue the video as an animation without re-opening the
* file; the returned handle is the same opaque stream the
* image_transfer_anim_stream_* helpers operate on (free it with
* image_transfer_anim_stream_free). It BORROWS the buffer given via
* image_transfer_set_buffer_ptr, which must outlive it. Returns NULL
* for other types, when no stream is held, or if it was already
* detached; an undetached stream is closed by image_transfer_free. */
void *image_transfer_detach_anim_stream(void *data,
enum image_type_enum type);
bool image_transfer_is_valid(void *data, enum image_type_enum type);
/* True if the last processed frame was written as packed XRGB2101010
* (10-bit) rather than 8-bit RGBA: 10-bit was requested and the source
* could supply it. Only PNG, WEBM and MP4 can report this; false for
* every other type. */
bool image_transfer_is_10bit(void *data, enum image_type_enum type);
/* Ask a video still (WEBM, MP4) for linear scRGB half floats from an
* HDR (PQ or HLG) source - RGBA half floats, 8 bytes a pixel, in the
* frame image_transfer_process hands out - and whether the last frame
* came out so. A no-op and false for every other type and source. Only
* for a caller that can take them: nothing narrows half floats. */
void image_transfer_set_want_fp16(void *data, enum image_type_enum type,
bool want);
bool image_transfer_is_fp16(void *data, enum image_type_enum type);
/* Ask a decoder to emit packed XRGB2101010 instead of 8-bit RGBA.
* Honoured by PNG (16-bit-per-channel RGB sources) and by the video
* types (10-bit HDR sources); ignored by every other type, and by an
* 8-bit source of an honouring type. */
void image_transfer_set_want_10bit(void *data, enum image_type_enum type,
int want);
/* Animation. The whole-buffer form below is animated WEBP only; the
* streaming form further down also covers APNG, WEBM and MP4.
*
* image_transfer_anim_new returns an opaque animation handle, or NULL
* for still images / unsupported types, so a caller can try it first and
* fall back to the single-frame image_transfer_* path. Frames are fully
* composited RGBA canvases (memory order R,G,B,A); the caller advances
* frames on its own clock using each frame's duration in milliseconds. */
void *image_transfer_anim_new(void *buf, size_t len,
enum image_type_enum type);
void image_transfer_anim_free(void *anim, enum image_type_enum type);
int image_transfer_anim_num_frames(void *anim, enum image_type_enum type);
void image_transfer_anim_get_info(void *anim, enum image_type_enum type,
unsigned *width, unsigned *height, int *loop_count);
const uint32_t *image_transfer_anim_get_frame(void *anim,
enum image_type_enum type, int index, int *duration_ms);
/* Streaming animation: memory use independent of frame count. The
* buffer passed to image_transfer_anim_stream_new is BORROWED and must
* outlive the stream. next() returns the stream's internal canvas
* (valid until the next call, do not free); NULL means end of one
* pass - rewind to loop. */
void *image_transfer_anim_stream_new(void *buf, size_t len,
enum image_type_enum type);
/* Progressive open over a partially-resident buffer: only the first
* 'avail' bytes are guaranteed present. On success the stream decodes
* forward as far as 'avail' allows; move the bound with
* image_transfer_anim_stream_set_avail as more arrives. need_more (may
* be NULL) is set when the header/index needed to open is not yet
* resident and a larger prefix should be retried; NULL with it clear
* is conclusive (a still, or malformed). Every streaming type (APNG,
* animated WEBP, WEBM, MP4) has a partial open; a type compiled out
* returns NULL with need_more clear. */
/* need_lo/need_hi (optional): a precise byte range that unblocks a
* stalled progressive open, when the container can name one (MP4's
* box headers and moov body). 0/0 otherwise; the caller then grows
* the available prefix instead. */
void *image_transfer_anim_stream_new_avail(void *buf, size_t len,
size_t avail, enum image_type_enum type, int *need_more,
size_t *need_lo, size_t *need_hi);
void image_transfer_anim_stream_free(void *stream,
enum image_type_enum type);
void image_transfer_anim_stream_get_info(void *stream,
enum image_type_enum type,
unsigned *width, unsigned *height, int *num_frames, int *loop_count);
const uint32_t *image_transfer_anim_stream_next(void *stream,
enum image_type_enum type, int *duration_ms);
/* Ask the stream to emit ARGB words (non-zero) or the default R,G,B,A
* memory order (zero) from the next frame on. Returns true when the
* stream type honours the request (WEBM, MP4, and animated WEBP - the
* video streams bake the order in their blit, WEBP in its sub-frame
* decode stores, converting its persistent canvas once if the order
* changes mid-animation) so the caller can skip its own R/B swizzle
* pass; false for types that always emit the default order, where the
* caller must keep converting. */
bool image_transfer_anim_stream_set_argb(void *stream,
enum image_type_enum type, int argb);
/* Ask the stream to decode its frames straight into @out (width *
* height words of the caller's), which image_transfer_anim_stream_next
* then returns, instead of into a frame of its own that the caller
* would copy from. NULL restores the stream's own frame. Returns true
* when the stream type does so (WEBM, MP4: the blit out of the
* decoder's planes has one destination either way); false for APNG
* and WEBP, whose frames are composed on a persistent canvas, where
* the caller keeps copying. @out must stay valid until the next call
* that decodes has returned. */
/* Behind the clock: while @behind is set, pictures nothing references
* are consumed without being decoded and their presentation slots
* pass, so the stream catches up; what is shown is decoded exactly as
* before. Only the MP4 codecs (H.264, HEVC) have such pictures; for
* the rest this is a no-op. Clear it once caught up. */
/* The stream's H.264 decoder (an rh264_video*), for a bench to ask
* what its pipeline did; NULL for any other type. */
void *image_transfer_anim_stream_h264(void *stream, enum image_type_enum type);
void *image_transfer_anim_stream_h265(void *stream, enum image_type_enum type);
void image_transfer_anim_stream_set_catchup(void *stream,
enum image_type_enum type, int behind);
/* HDR video sources: whether the stream's source is PQ or HLG; asking
* for linear scRGB half floats for it, which the video streams honour
* when they decode into the caller's frame
* (image_transfer_anim_stream_set_output) - 8 bytes a pixel then; and
* whether the last frame came out so. False and a no-op for every type
* without such a source. */
bool image_transfer_anim_stream_is_hdr(const void *stream,
enum image_type_enum type);
void image_transfer_anim_stream_set_want_fp16(void *stream,
enum image_type_enum type, bool want);
bool image_transfer_anim_stream_is_fp16(const void *stream,
enum image_type_enum type);
bool image_transfer_anim_stream_set_output(void *stream,
enum image_type_enum type, uint32_t *out);
/* Have the stream convert each decoded frame to pixels in @bands row
* bands on @pool (an rthreads tpool_t with at least bands - 1 threads;
* the decoding thread takes one band and joins the rest), so a large
* frame's colour conversion is spread over cores, and decode a VP9
* frame's tile columns on the same threads where the stream carries
* more than one. NULL or bands <= 1 keeps all of it on the decoding
* thread as before. Returns true for the
* stream types that convert this way (WEBM, MP4); APNG and WEBP
* compose their frames and have no such pass. The pool is the
* caller's and must outlive every decode made while it is set. */
bool image_transfer_anim_stream_set_blit_pool(void *stream,
enum image_type_enum type, void *pool, unsigned bands);
/* For decoding a still from a file whose read is still in progress:
* declare how many leading bytes of the buffer are valid. Monotonic.
* Honoured by PNG, JPEG, WEBM and MP4, which report the wall two
* different ways: the video types return IMAGE_PROCESS_WAIT from their
* process step, while PNG and JPEG stop iterating with
* image_transfer_need_more() true. A no-op for BMP, TGA, WEBP and
* DDS, whose transfers must keep seeing fully-resident buffers. */
void image_transfer_set_avail(void *data, enum image_type_enum type,
size_t avail);
/* Declare the output byte order before the transfer starts, so
* decoders that emit final pixels during transfer (JPEG's fused
* iterate+resample) can use the caller's order directly. */
void image_transfer_set_rgba(void *data, enum image_type_enum type,
bool rgba);
/* The stream-level counterpart, for an animation stream adopted from
* a still whose file read was still in flight: the demuxer's byte
* wall was captured at open, and nothing else raises it once the
* still's task is gone - without this, a stream adopted at N bytes
* read treats N as the end of the file and loops the animation
* there, forever. Call with the full length once the read
* completes (or progressively, should a streaming consumer appear).
* An exact store for every streaming type: a windowing feeder lowers
* it when it takes pages back, and the stream then refuses (NULL from
* next(), nothing consumed) a frame whose bytes lie past it. */
void image_transfer_anim_stream_set_avail(void *stream,
enum image_type_enum type, size_t avail);
/* Bounded-memory streaming: media_floor is the fixed byte offset
* where media data begins; consumed is the byte offset the decoder's
* next read lands on, rising through a pass and dropping back to the
* floor on rewind. A feeder keeps [consumed - margin, consumed +
* lookahead) resident and can free below that. Every streaming type
* carries the cursor; 0 means the stream has not indexed anything
* yet (anchor at the floor).
*
* next_span names the byte range [lo, hi) the next frame occupies
* when the container indexes its frames (APNG, animated WEBP), so a
* feeder can make a frame larger than its lookahead resident before
* asking for it - without this a lossless 4K frame past the lookahead
* would never become readable and the stream would sit at the wall
* forever. 0/0 for the video types (packet-sized reads well inside
* any lookahead) and for a frame not indexed yet. */
size_t image_transfer_anim_stream_media_floor(void *stream,
enum image_type_enum type);
/* Container duration in nanoseconds for the video types, 0 for the
* frame-indexed ones (WEBP, APNG carry per-frame delays only) and
* when the file does not say. Lets a windowed reader size its
* lookahead to the bitrate instead of a fixed byte count. */
int64_t image_transfer_anim_stream_duration_ns(void *stream,
enum image_type_enum type);
size_t image_transfer_anim_stream_consumed(void *stream,
enum image_type_enum type);
void image_transfer_anim_stream_next_span(void *stream,
enum image_type_enum type, size_t *lo, size_t *hi);
/* Companion to the above for WEBM, whose timestamp pre-scan is
* truncated by the wall (timestamps live in the block headers): once
* the buffer is complete, finish the scan so per-frame durations
* match a stream opened over the whole file. No-op for MP4 (its
* scan reads the moov tables and is never truncated) and for types
* without a scan. */
void image_transfer_anim_stream_complete_scan(void *stream,
enum image_type_enum type, const void *buf, size_t len);
void image_transfer_anim_stream_rewind(void *stream,
enum image_type_enum type);
RETRO_END_DECLS
#endif