char-fork/llama.cpp

git clone https://git.t4t.associates/char-fork/llama.cpp

Mads Marquartmtmd : add `const` in various places (#28307)f45576aa8

char/aliceai-t5-moe
21.9 KiB538 linesraw
1#ifndef MTMD_H
2#define MTMD_H
3
4#include "ggml.h"
5#include "llama.h"
6
7#include <stddef.h>
8#include <stdint.h>
9#include <stdbool.h>
10
11#ifdef __cplusplus
12#include <map>
13#include <string>
14#include <vector>
15#include <cinttypes>
16#include <memory>
17#endif
18
19/**
20 * libmtmd: A library for multimodal support in llama.cpp.
21 *
22 * WARNING: This API is experimental and subject to many BREAKING CHANGES.
23 *          Issues related to API usage may receive lower priority support.
24 *
25 * For the usage, see an example in mtmd-cli.cpp
26 *
27 * For contributors:
28 * - Make sure the C API is aligned with the libllama C API (as in llama.h)
29 * - Do not include model name (e.g., qwen, gemma) in the API, use generic terms instead
30 * - Keep the API minimal, do not expose internal details unless necessary
31 *
32 * IMPORTANT: The mtmd module does NOT accept pull requests that are fully or predominantly AI-generated.
33 * We encourage human contributors to ensure the quality and reliability of the codebase.
34 */
35
36#ifdef LLAMA_SHARED
37#    if defined(_WIN32) && !defined(__MINGW32__)
38#        ifdef LLAMA_BUILD
39#            define MTMD_API __declspec(dllexport)
40#        else
41#            define MTMD_API __declspec(dllimport)
42#        endif
43#    else
44#        define MTMD_API __attribute__ ((visibility ("default")))
45#    endif
46#else
47#    define MTMD_API
48#endif
49
50#ifdef __cplusplus
51extern "C" {
52#endif
53
54enum mtmd_input_chunk_type {
55    MTMD_INPUT_CHUNK_TYPE_TEXT,
56    MTMD_INPUT_CHUNK_TYPE_IMAGE,
57    MTMD_INPUT_CHUNK_TYPE_AUDIO,
58    MTMD_INPUT_CHUNK_TYPE_COUNT, // for validation
59};
60
61// opaque types
62struct mtmd_context;
63struct mtmd_bitmap;
64struct mtmd_image_tokens;
65struct mtmd_input_chunk;
66struct mtmd_input_chunks;
67struct mtmd_batch;
68
69struct mtmd_input_text {
70    const char * text;
71    size_t text_len;
72    bool add_special;
73    bool parse_special;
74};
75
76struct mtmd_input_part {
77    // only text or bitmap can be set, not both
78    const struct mtmd_input_text * text;
79    const struct mtmd_bitmap * bitmap;
80};
81
82//
83// C API
84//
85
86typedef struct mtmd_context      mtmd_context;
87typedef struct mtmd_bitmap       mtmd_bitmap;
88typedef struct mtmd_image_tokens mtmd_image_tokens;
89typedef struct mtmd_input_chunk  mtmd_input_chunk;
90typedef struct mtmd_input_chunks mtmd_input_chunks;
91typedef struct mtmd_input_text   mtmd_input_text;
92typedef struct mtmd_input_part   mtmd_input_part;
93typedef struct mtmd_batch        mtmd_batch;
94
95typedef bool (*mtmd_progress_callback)(float progress, void * user_data);
96
97struct mtmd_context_params {
98    bool use_gpu;
99    ggml_backend_dev_t device;
100    bool print_timings;
101    int n_threads;
102    const char * image_marker; // deprecated, use media_marker instead
103    const char * media_marker;
104    enum llama_flash_attn_type flash_attn_type;
105    bool warmup; // whether to run a warmup encode pass after initialization
106
107    // limit number of image tokens, only for vision models with dynamic resolution
108    int image_min_tokens; // minimum number of tokens for image input (default: read from metadata)
109    int image_max_tokens; // maximum number of tokens for image input (default: read from metadata)
110
111    // callback function passed over to mtmd proper
112    ggml_backend_sched_eval_callback cb_eval;
113    void * cb_eval_user_data;
114
115    // batching params
116    int32_t batch_max_tokens; // maximum number of output tokens in a batch
117                              // (note: this is not a hard-limit, the first image will always be added even if it exceeds this limit)
118                              // (default: 1024)
119
120    // Called with a progress value between 0.0 and 1.0. Pass NULL to disable.
121    // If the provided progress_callback returns true, model loading continues.
122    // If it returns false, model loading is immediately aborted.
123    mtmd_progress_callback progress_callback;
124    void * progress_callback_user_data;
125};
126
127MTMD_API const char * mtmd_default_marker(void);
128
129MTMD_API struct mtmd_context_params mtmd_context_params_default(void);
130
131// initialize the mtmd context
132// return nullptr on failure
133MTMD_API mtmd_context * mtmd_init_from_file(const char * mmproj_fname,
134                                            const struct llama_model * text_model,
135                                            const struct mtmd_context_params ctx_params);
136
137MTMD_API void mtmd_free(mtmd_context * ctx);
138
139// whether we need to set non-causal mask before llama_decode
140// if chunk is nullptr, we assume the default case where chunk is an image chunk
141MTMD_API bool mtmd_decode_use_non_causal(const mtmd_context * ctx, const mtmd_input_chunk * chunk);
142
143// whether the current model use M-RoPE for llama_decode
144MTMD_API bool mtmd_decode_use_mrope(const mtmd_context * ctx);
145
146// whether the current model supports vision input
147MTMD_API bool mtmd_support_vision(const mtmd_context * ctx);
148
149// whether the current model supports audio input
150MTMD_API bool mtmd_support_audio(const mtmd_context * ctx);
151
152// get audio sample rate in Hz, for example 16000 for Whisper
153// return -1 if audio is not supported
154MTMD_API int mtmd_get_audio_sample_rate(const mtmd_context * ctx);
155
156// get the current marker string
157MTMD_API const char * mtmd_get_marker(const mtmd_context * ctx);
158
159// mtmd_bitmap
160//
161// if bitmap is image:
162//     length of data must be nx * ny * 3
163//     the data is in RGBRGBRGB... format
164//     note: some video-capable models (i.e. qwen-vl) can merge consecutive bitmaps
165//           into one chunk; mtmd_tokenize() handles this, but remember to set
166//           mtmd_bitmap_set_mergeable(true) for every frame
167// if bitmap is audio:
168//     length of data must be n_samples * sizeof(float)
169//     the data is in float format (PCM F32)
170//
171// if data == nullptr:
172//     the bitmap is considered "empty", and will be treated as a placeholder for counting tokens
173//     you can pass the bitmap via mtmd_tokenize(), then call mtmd_*_get_n_tokens() to count the tokens
174//     note: passing a placeholder bitmap to mtmd_encode() will return an error
175MTMD_API mtmd_bitmap *         mtmd_bitmap_init           (uint32_t nx, uint32_t ny, const unsigned char * data);
176MTMD_API mtmd_bitmap *         mtmd_bitmap_init_from_audio(size_t n_samples,         const float         * data);
177MTMD_API uint32_t              mtmd_bitmap_get_nx     (const mtmd_bitmap * bitmap);
178MTMD_API uint32_t              mtmd_bitmap_get_ny     (const mtmd_bitmap * bitmap);
179MTMD_API const unsigned char * mtmd_bitmap_get_data   (const mtmd_bitmap * bitmap);
180MTMD_API size_t                mtmd_bitmap_get_n_bytes(const mtmd_bitmap * bitmap);
181MTMD_API bool                  mtmd_bitmap_is_audio   (const mtmd_bitmap * bitmap);
182MTMD_API void                  mtmd_bitmap_free       (mtmd_bitmap * bitmap);
183// bitmap ID is optional, but useful for KV cache tracking
184// these getters/setters are dedicated functions, so you can for example calculate the hash of the image based on mtmd_bitmap_get_data()
185MTMD_API const char * mtmd_bitmap_get_id(const mtmd_bitmap * bitmap);
186MTMD_API void         mtmd_bitmap_set_id(mtmd_bitmap * bitmap, const char * id);
187// if true, this bitmap can be merged (temporal merge) with an adjacent mergeable bitmap by certain video input models
188MTMD_API void         mtmd_bitmap_set_mergeable(mtmd_bitmap * bitmap, bool mergeable);
189
190// mtmd_bitmap lazy
191//
192// this is a special bitmap that:
193// - does not hold the actual data
194// - can be expanded into one or more chunks (either media to text chunks)
195// user must provide a callback to fill in the data when mtmd_tokenize() is called
196// this is useful for large video inputs:
197// - allow reading video frame by frame, without loading the entire video into memory
198// - allow tracking the whole video with a single ID (for example, the file hash)
199
200// set (*out_bitmap) to non-nullptr to emit a bitmap chunk; it will be freed automatically
201// set (*out_text) to non-nullptr to emit a text chunk; it must be heap-allocated, null-terminated and will be freed automatically
202// either out_bitmap or out_text can be set, but not both
203// out_bitmap cannot be another lazy bitmap (no nested lazy allowed)
204// return value:
205//    0 on success
206//   -1 on EOF (signal to mtmd_tokenize to move on)
207//   -2 on error (signal to mtmd_tokenize to abort)
208typedef int(* mtmd_bitmap_lazy_callback)(
209    size_t chunk_idx,
210    void * user_data,
211    mtmd_bitmap ** out_bitmap,
212    char ** out_text);
213
214MTMD_API mtmd_bitmap * mtmd_bitmap_init_lazy(const mtmd_context * ctx,
215                                             const char * id, // usually set to file hash
216                                             void * user_data,
217                                             mtmd_bitmap_lazy_callback callback);
218
219// mtmd_input_chunks
220//
221// this is simply a list of mtmd_input_chunk
222// the elements can only be populated via mtmd_tokenize()
223MTMD_API mtmd_input_chunks *      mtmd_input_chunks_init(void);
224MTMD_API size_t                   mtmd_input_chunks_size(const mtmd_input_chunks * chunks);
225MTMD_API const mtmd_input_chunk * mtmd_input_chunks_get (const mtmd_input_chunks * chunks, size_t idx);
226MTMD_API void                     mtmd_input_chunks_free(mtmd_input_chunks * chunks);
227
228// mtmd_input_chunk
229//
230// the instance will be constructed via mtmd_tokenize()
231// it will be freed along with mtmd_input_chunks
232MTMD_API enum mtmd_input_chunk_type mtmd_input_chunk_get_type        (const mtmd_input_chunk * chunk);
233MTMD_API const llama_token *        mtmd_input_chunk_get_tokens_text (const mtmd_input_chunk * chunk, size_t * n_tokens_output);
234MTMD_API const mtmd_image_tokens *  mtmd_input_chunk_get_tokens_image(const mtmd_input_chunk * chunk);
235MTMD_API size_t                     mtmd_input_chunk_get_n_tokens    (const mtmd_input_chunk * chunk);
236// returns nullptr for ID on text chunk
237MTMD_API const char *               mtmd_input_chunk_get_id          (const mtmd_input_chunk * chunk);
238// number of temporal positions (equals to max(t,h,w) for M-RoPE; equals to n_tokens otherwise)
239MTMD_API llama_pos                  mtmd_input_chunk_get_n_pos       (const mtmd_input_chunk * chunk);
240
241// in case you want to use custom logic to handle the chunk (i.e. KV cache management)
242// you can move the chunk ownership to your own code by copying it
243// remember to free the chunk when you are done with it
244MTMD_API mtmd_input_chunk * mtmd_input_chunk_copy(const mtmd_input_chunk * chunk);
245MTMD_API void               mtmd_input_chunk_free(mtmd_input_chunk * chunk);
246
247// similar to mtmd_input_chunk_copy, but returns a placeholder chunk
248MTMD_API mtmd_input_chunk * mtmd_input_chunk_get_placeholder(const mtmd_input_chunk * chunk);
249
250// save/load an input chunk to/from a buffer (useful for KV save/load)
251// important: only chunk's metadata will be saved, the actual image/audio data will not be saved
252// the loaded chunk will always be a placeholder, cannot be used for mtmd_encode() or mtmd_batch_encode()
253// out_buf can be nullptr (to query expected_out_len)
254// returns 0 on success, non-zero on failure
255MTMD_API int32_t            mtmd_input_chunk_save(const mtmd_input_chunk * chunk, char * out_buf, size_t out_len, size_t * expected_out_len);
256// returns nullptr on failure
257MTMD_API mtmd_input_chunk * mtmd_input_chunk_load(const char * buf, size_t len);
258
259
260// mtmd_image_tokens
261//
262// the instance will be constructed via mtmd_tokenize()
263// it will be freed along with mtmd_input_chunk
264MTMD_API size_t       mtmd_image_tokens_get_n_tokens(const mtmd_image_tokens * image_tokens); // TODO: deprecate
265MTMD_API const char * mtmd_image_tokens_get_id      (const mtmd_image_tokens * image_tokens); // TODO: deprecate
266// number of temporal positions (equals to max(t,h,w) for M-RoPE; equals to n_tokens otherwise)
267MTMD_API llama_pos    mtmd_image_tokens_get_n_pos   (const mtmd_image_tokens * image_tokens); // TODO: deprecate
268
269DEPRECATED(MTMD_API size_t mtmd_image_tokens_get_nx(const mtmd_image_tokens * image_tokens),
270           "use mtmd_image_tokens_get_decoder_pos() instead");
271DEPRECATED(MTMD_API size_t mtmd_image_tokens_get_ny(const mtmd_image_tokens * image_tokens),
272           "use mtmd_image_tokens_get_decoder_pos() instead");
273
274struct mtmd_decoder_pos {
275    uint32_t t;
276    uint32_t x;
277    uint32_t y;
278    uint32_t z; // unused for now, reserved for future use
279};
280// get position for decoder attention, to be used by M-RoPE models
281// i is the index of the embedding token, ranging from 0 to mtmd_image_tokens_get_n_tokens() - 1
282// pos_0 is the absolute position of the first token
283// return relative position (for example, embedding 0 will have position (0, 0, 0); remember to adjust it to the current absolute position)
284MTMD_API struct mtmd_decoder_pos mtmd_image_tokens_get_decoder_pos(const mtmd_image_tokens * image_tokens, llama_pos pos_0, size_t i);
285
286// tokenize an input text prompt and a list of bitmaps (image/audio)
287// the prompt must have the input media marker (default: "<__media__>") in it
288// the default marker is defined by mtmd_default_marker()
289// the marker will be replaced with the media chunk
290// for example:
291//   "here is an image: <__media__>\ndescribe it in detail."
292//   this will gives 3 chunks:
293//   1. "here is an image: <start_of_image>"
294//   2. (image/audio tokens)
295//   3. "<end_of_image>\ndescribe it in detail."
296// number of bitmaps must be equal to the number of markers in the prompt
297// this function is thread-safe (shared ctx)
298// return values:
299//   0 on success
300//   1 on number of bitmaps not matching the number of markers
301//   2 on media preprocessing error
302MTMD_API int32_t mtmd_tokenize(const mtmd_context * ctx,
303                               mtmd_input_chunks * output,
304                               const mtmd_input_text * text,
305                               const mtmd_bitmap * const * bitmaps,
306                               size_t n_bitmaps);
307
308// same as mtmd_tokenize(), but takes an array of mtmd_input_part
309// use cases:
310// - when you don't want to use media markers (they will be tokenized as normal text)
311// - when you want to control parse_special for each text part
312// note: per-part add_special will be ignored
313// return 1 if a part has both text and bitmap set (or neither)
314MTMD_API int32_t mtmd_tokenize_from_parts(const mtmd_context * ctx,
315                                          mtmd_input_chunks * output,
316                                          const mtmd_input_part * const * parts,
317                                          size_t n_parts,
318                                          bool add_special);
319
320DEPRECATED(MTMD_API int32_t mtmd_encode(mtmd_context * ctx, const mtmd_image_tokens * image_tokens),
321           "use mtmd_encode_chunk() instead");
322
323// text chunk will be ignored silently, only media chunk will be encoded
324// returns 0 on success
325// returns 1 on generic error
326MTMD_API int32_t mtmd_encode_chunk(mtmd_context * ctx,
327                                   const mtmd_input_chunk * chunk);
328
329// get output embeddings from the last encode pass
330// the reading size (in bytes) is equal to:
331// llama_model_n_embd_inp(model) * mtmd_input_chunk_get_n_tokens(chunk) * sizeof(float)
332MTMD_API float * mtmd_get_output_embd(mtmd_context * ctx);
333
334
335// batch encoding API
336// chunks are not owned by the batch, they will not be freed by mtmd_batch_free()
337// batch is valid for a given context, cannot be shared across contexts
338MTMD_API mtmd_batch * mtmd_batch_init(mtmd_context * ctx);
339MTMD_API void         mtmd_batch_free(mtmd_batch * batch);
340
341// only media chunks are allowed, text chunks will be rejected
342// returns 0 on success
343// returns 1 on generic error
344// returns 2 if the batch is too large (chunk won't be added)
345// returns 3 if it cannot be batched with the existing chunks in the batch
346MTMD_API int32_t mtmd_batch_add_chunk(mtmd_batch * batch, const mtmd_input_chunk * chunk);
347
348// returns 0 on success
349// returns 1 on generic error
350MTMD_API int32_t mtmd_batch_encode(mtmd_batch * batch);
351MTMD_API float * mtmd_batch_get_output_embd(mtmd_batch * batch, const mtmd_input_chunk * chunk);
352
353
354// Set callback for all future logging events.
355// If this is not called, or NULL is supplied, everything is output on stderr.
356MTMD_API void mtmd_log_set(ggml_log_callback log_callback, void * user_data);
357
358// EXPERIMENTAL API to get mmproj's capabilities without initializing the full context
359// This is only intended to be used by llama-server, breaking changes is expected
360struct mtmd_caps {
361    bool inp_vision;
362    bool inp_audio;
363};
364MTMD_API struct mtmd_caps mtmd_get_cap_from_file(const char * mmproj_fname);
365
366/////////////////////////////////////////
367// EXPERIMENTAL API for audio generation, subjected to breaking changes
368
369// represent the pipeline type
370enum mtmd_gen_audio_type {
371    MTMD_GEN_AUDIO_TYPE_NONE, // not supported
372    MTMD_GEN_AUDIO_TYPE_QWEN3TTS,
373    MTMD_GEN_AUDIO_TYPE_POCKETTTS,
374};
375
376struct mtmd_gen_audio_info {
377    enum mtmd_gen_audio_type type;
378    int32_t sample_rate; // in Hz, for example 24000 for qwen3tts
379    const char * model_variant; // name of the weight variant, can be nullptr if not applicable
380};
381
382MTMD_API struct mtmd_gen_audio_info mtmd_gen_audio_get_info(const mtmd_context * ctx);
383
384
385enum mtmd_gen_process_type {
386    MTMD_GEN_PROCESS_TYPE_GEN_CODE, // h_state to semantic (codes, mel-spectrogram, etc.)
387    MTMD_GEN_PROCESS_TYPE_GEN_WAV,  // convert semantic to PCM audio
388                                    // for qwen3tts, this is code2wav
389                                    // for pocket-tts, this is mimi decoder
390};
391
392struct mtmd_gen_inp {
393    enum mtmd_gen_process_type type;
394
395    // for MTMD_GEN_PROCESS_TYPE_GEN_CODE
396    int32_t code0;  // the sampled codebook 0 entry from backbone
397    float * embd;   // the hidden state from backbone, must have n_text_embd elements
398    int32_t top_k;
399    float   top_p;
400    uint32_t seed; // UINT32_MAX for random
401    float    temp; // sampling temperature, or noise scale for flow-matching decoders
402
403    // for MTMD_GEN_PROCESS_TYPE_GEN_WAV
404    // pass either codes (discrete) or feats (continuous), depending on the pipeline
405    int32_t * codes;
406    size_t    n_codes;
407    const float * feats;
408    size_t        n_feats;
409    const char * state_data;
410    size_t       state_size;
411};
412
413struct mtmd_gen_out {
414    // note: output memory is allocated by the context, valid until next process() call
415
416    // for MTMD_GEN_PROCESS_TYPE_GEN_CODE
417    const int32_t * codes;
418    size_t          n_codes;
419    const float * feats; // continuous counterpart of codes
420    size_t        n_feats;
421    const float * embd; // the generated hidden state, to be fed back to backbone
422                        // it must have n_text_embd elements
423    bool is_eos; // only set by pipelines having the EOS head inside mmproj
424
425    // for MTMD_GEN_PROCESS_TYPE_GEN_WAV
426    const float * audio;
427    size_t        n_samples;
428    const char * state_data;
429    size_t       state_size;
430};
431
432// defaults tuned for the loaded pipeline, callers override only what they care about
433MTMD_API struct mtmd_gen_inp mtmd_gen_inp_default(const mtmd_context * ctx);
434
435// note: this API is stateless, caller must handle state management and audio frame accumulation
436MTMD_API int32_t mtmd_gen_audio_process(mtmd_context * ctx,
437                                const struct mtmd_gen_inp * inp,
438                                struct mtmd_gen_out * out);
439
440/////////////////////////////////////////
441
442// test function, to be used in test-mtmd-c-api.c
443MTMD_API mtmd_input_chunks * mtmd_test_create_input_chunks(void);
444
445#ifdef __cplusplus
446} // extern "C"
447#endif
448
449// Get memory usage of the current model in bytes, per backend device
450// Note: this is an unstable API, used internally by fit_params; it WILL be removed or changed without deprecation
451#ifdef __cplusplus
452MTMD_API std::map<ggml_backend_dev_t, size_t> mtmd_get_memory_usage(
453    const char * mmproj_fname,
454    struct mtmd_context_params ctx_params);
455#endif
456
457//
458// C++ wrappers
459//
460
461#ifdef __cplusplus
462
463namespace mtmd {
464
465struct mtmd_context_deleter {
466    void operator()(mtmd_context * val) { mtmd_free(val); }
467};
468using context_ptr = std::unique_ptr<mtmd_context, mtmd_context_deleter>;
469
470struct mtmd_bitmap_deleter {
471    void operator()(mtmd_bitmap * val) { mtmd_bitmap_free(val); }
472};
473using bitmap_ptr = std::unique_ptr<mtmd_bitmap, mtmd_bitmap_deleter>;
474
475struct mtmd_input_chunks_deleter {
476    void operator()(mtmd_input_chunks * val) { mtmd_input_chunks_free(val); }
477};
478using input_chunks_ptr = std::unique_ptr<mtmd_input_chunks, mtmd_input_chunks_deleter>;
479
480struct mtmd_input_chunk_deleter {
481    void operator()(mtmd_input_chunk * val) { mtmd_input_chunk_free(val); }
482};
483using input_chunk_ptr = std::unique_ptr<mtmd_input_chunk, mtmd_input_chunk_deleter>;
484
485struct mtmd_batch_deleter {
486    void operator()(mtmd_batch * val) { mtmd_batch_free(val); }
487};
488using batch_ptr = std::unique_ptr<mtmd_batch, mtmd_batch_deleter>;
489
490struct bitmap {
491    bitmap_ptr ptr;
492    bitmap() : ptr(nullptr) {}
493    bitmap(mtmd_bitmap * bitmap) : ptr(bitmap) {}
494    bitmap(bitmap && other) noexcept : ptr(std::move(other.ptr)) {}
495    bitmap(uint32_t nx, uint32_t ny, const unsigned char * data) {
496        ptr.reset(mtmd_bitmap_init(nx, ny, data));
497    }
498    ~bitmap() = default;
499    uint32_t nx() const { return mtmd_bitmap_get_nx(ptr.get()); }
500    uint32_t ny() const { return mtmd_bitmap_get_ny(ptr.get()); }
501    const unsigned char * data() const { return mtmd_bitmap_get_data(ptr.get()); }
502    size_t n_bytes() const { return mtmd_bitmap_get_n_bytes(ptr.get()); }
503    std::string id() const { return mtmd_bitmap_get_id(ptr.get()); }
504    void set_id(const char * id) const { mtmd_bitmap_set_id(ptr.get(), id); }
505};
506
507struct bitmaps {
508    std::vector<bitmap> entries;
509    ~bitmaps() = default;
510    // return list of pointers to mtmd_bitmap
511    // example:
512    //   auto bitmaps_c_ptr = bitmaps.c_ptr();
513    //   int32_t res = mtmd_tokenize(... bitmaps_c_ptr.data(), bitmaps_c_ptr.size());
514    std::vector<const mtmd_bitmap *> c_ptr() {
515        std::vector<const mtmd_bitmap *> res(entries.size());
516        for (size_t i = 0; i < entries.size(); i++) {
517            res[i] = entries[i].ptr.get();
518        }
519        return res;
520    }
521};
522
523struct input_chunks {
524    input_chunks_ptr ptr;
525    input_chunks() = default;
526    input_chunks(mtmd_input_chunks * chunks) : ptr(chunks) {}
527    ~input_chunks() = default;
528    size_t size() const { return mtmd_input_chunks_size(ptr.get()); }
529    const mtmd_input_chunk * operator[](size_t idx) const {
530        return mtmd_input_chunks_get(ptr.get(), idx);
531    }
532};
533
534} // namespace mtmd
535
536#endif
537
538#endif