[FFmpeg-devel] [PATCH 6/7] lavu: add a JSON writer API.
Nicolas George
george at nsup.org
Wed Apr 21 15:27:05 EEST 2021
Signed-off-by: Nicolas George <george at nsup.org>
---
libavutil/Makefile | 1 +
libavutil/json.c | 368 +++++++++++++++++++++++++++++++++++
libavutil/json.h | 467 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 836 insertions(+)
create mode 100644 libavutil/json.c
create mode 100644 libavutil/json.h
diff --git a/libavutil/Makefile b/libavutil/Makefile
index 80d0580289..6ad31426e5 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -133,6 +133,7 @@ OBJS = adler32.o \
imgutils.o \
integer.o \
intmath.o \
+ json.o \
lfg.o \
lls.o \
log.o \
diff --git a/libavutil/json.c b/libavutil/json.c
new file mode 100644
index 0000000000..7ee68aaa4a
--- /dev/null
+++ b/libavutil/json.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2021 Nicolas George
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avassert.h"
+#include "common.h"
+#include "json.h"
+#include "opt.h"
+
+#define FIELDOK(st, f) ((char *)(&(st)->f + 1) <= (char *)(st) + (st)->self_size)
+
+#define json_assert_abi(jwr) av_assert1(FIELDOK(jwr, padding))
+#define json_escape_writer_assert_abi(jwr) av_assert1(FIELDOK(jwr, padding))
+
+AVClass *av_json_get_class(void)
+{
+ return NULL;
+}
+
+int av_json_alloc(AVJson **jc, unsigned max_depth)
+{
+ return AVERROR_BUG;
+}
+
+void av_json_free(AVJson **jc)
+{
+}
+
+AVJson *av_json_preinit(AVJson *jc, AVJsonEscapeWriter *jwr)
+{
+ json_assert_abi(jc);
+ json_escape_writer_assert_abi(jwr);
+ jc->av_class = av_json_get_class();
+ jc->escape_writer = jwr;
+ av_opt_set_defaults(jc);
+ return jc;
+}
+
+void av_json_init(AVJson *jc, AVWriter wr, unsigned flags, AVDictionary *options)
+{
+ jc->out = wr;
+ jc->flags = flags;
+ jc->in_string = 0;
+ jc->in_object = 0;
+ jc->first_element = 1;
+ jc->depth = 0;
+ jc->stack = NULL;
+}
+
+static inline int check_value_must_be_string(AVJson *jc, int string)
+{
+ return !jc->object_key || string;
+}
+
+static inline int check_stack_clean(AVJsonStack *stack)
+{
+ return !stack->prev;
+}
+
+static inline int check_begin_end_balanced(AVJson *jc, int obj)
+{
+ return jc->in_object == obj && jc->stack;
+}
+
+static inline int flag_pretty_print(AVJson *jc)
+{
+ return !!(jc->flags & AV_JSON_FLAG_PRETTY_PRINT);
+}
+
+static void end_value(AVJson *jc)
+{
+ if (!jc->stack && flag_pretty_print(jc))
+ av_writer_print(jc->out, "\n");
+}
+
+static void auto_end_string(AVJson *jc)
+{
+ if (jc->in_string) {
+ av_writer_print(jc->out, "\"");
+ jc->in_string = 0;
+ end_value(jc);
+ }
+}
+
+static void auto_add_separator(AVJson *jc)
+{
+ int indent = flag_pretty_print(jc);
+
+ auto_end_string(jc);
+ if (!jc->first_element) {
+ if (jc->object_key) {
+ av_writer_print(jc->out, flag_pretty_print(jc) ? " : " : ":");
+ indent = jc->object_key = 0;
+ } else {
+ av_writer_print(jc->out, ",");
+ jc->object_key = jc->in_object;
+ }
+ }
+ if (indent) {
+ if (jc->stack)
+ av_writer_print(jc->out, "\n");
+ av_writer_add_chars(jc->out, ' ', 3 * jc->depth);
+ }
+ jc->first_element = 0;
+}
+
+static void begin_value(AVJson *jc, int string)
+{
+ auto_add_separator(jc);
+ av_assert1(check_value_must_be_string(jc, string));
+}
+
+static void begin_compound(AVJson *jc, AVJsonStack *stack, unsigned obj)
+{
+ av_assert1(FIELDOK(stack, in_object));
+ av_assert1(check_stack_clean(stack));
+ stack->prev = jc->stack;
+ stack->in_object = jc->in_object;
+ jc->stack = stack;
+ jc->first_element = 1;
+ jc->in_object = jc->object_key = obj;
+ jc->depth++;
+}
+
+static void end_compound(AVJson *jc, unsigned obj)
+{
+ AVJsonStack *stack = jc->stack;
+
+ av_assert1(check_begin_end_balanced(jc, obj));
+ auto_end_string(jc);
+ jc->depth--;
+ if (!jc->first_element && flag_pretty_print(jc)) {
+ av_writer_print(jc->out, "\n");
+ av_writer_add_chars(jc->out, ' ', 3 * jc->depth);
+ }
+ jc->in_object = stack->in_object;
+ jc->object_key = 0;
+ jc->first_element = 0;
+ jc->stack = stack->prev;
+ stack->prev = NULL;
+}
+
+void av_json_begin_object_with_stack(AVJson *jc, AVJsonStack *stack)
+{
+ begin_value(jc, 0);
+ begin_compound(jc, stack, 1);
+ av_writer_print(jc->out, "{");
+}
+
+void av_json_end_object(AVJson *jc)
+{
+ end_compound(jc, 1);
+ av_writer_print(jc->out, "}");
+ end_value(jc);
+}
+
+void av_json_begin_array_with_stack(AVJson *jc, AVJsonStack *stack)
+{
+ begin_value(jc, 0);
+ begin_compound(jc, stack, 0);
+ av_writer_print(jc->out, "[");
+}
+
+void av_json_end_array(AVJson *jc)
+{
+ end_compound(jc, 0);
+ av_writer_print(jc->out, "]");
+ end_value(jc);
+}
+
+AVWriter av_json_begin_string(AVJson *jc)
+{
+ begin_value(jc, 1);
+ jc->in_string = 1;
+ av_writer_print(jc->out, "\"");
+ av_json_escape_writer_init(jc->escape_writer, jc->out, jc->flags);
+ return av_json_escape_writer_wrap(jc->escape_writer);
+}
+
+void av_json_end_string(AVJson *jc)
+{
+ av_assert1(jc->in_string);
+ auto_end_string(jc);
+}
+
+void av_json_add_string(AVJson *jc, const char *str)
+{
+ AVWriter wr = av_json_begin_string(jc);
+ av_writer_print(wr, str);
+}
+
+void av_json_add_string_vprintf(AVJson *jc, const char *fmt, va_list va)
+{
+ AVWriter wr = av_json_begin_string(jc);
+ av_writer_vprintf(wr, fmt, va);
+ av_json_end_string(jc);
+}
+
+void av_json_add_string_printf(AVJson *jc, const char *fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+ av_json_add_string_vprintf(jc, fmt, va);
+ va_end(va);
+}
+
+void av_json_add_int(AVJson *jc, intmax_t val)
+{
+ begin_value(jc, 0);
+ av_writer_printf(jc->out, "%jd", val);
+ end_value(jc);
+}
+
+void av_json_add_double(AVJson *jc, double val)
+{
+ begin_value(jc, 0);
+ av_writer_printf(jc->out, "%.15g", val);
+ end_value(jc);
+}
+
+void av_json_add_bool(AVJson *jc, int val)
+{
+ begin_value(jc, 0);
+ av_writer_print(jc->out, val ? "true" : "false");
+ end_value(jc);
+}
+
+void av_json_add_null(AVJson *jc)
+{
+ begin_value(jc, 0);
+ av_writer_print(jc->out, "null");
+ end_value(jc);
+}
+
+void av_json_add_raw_vprintf(AVJson *jc, const char *fmt, va_list va)
+{
+ begin_value(jc, 1);
+ av_writer_vprintf(jc->out, fmt, va);
+ end_value(jc);
+}
+
+void av_json_add_raw_printf(AVJson *jc, const char *fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+ av_json_add_raw_vprintf(jc, fmt, va);
+ va_end(va);
+}
+
+/***************************************************************************
+ * AVJsonEscapeWriter - escpae JSON strings
+ ***************************************************************************/
+
+static void json_escape_writer_write(AVWriter wr, const char *data, size_t size)
+{
+ AVJsonEscapeWriter *jwr = wr.obj;
+ const uint8_t *end = data + size;
+ const uint8_t *cur = data;
+ const uint8_t *written = data;
+ const uint8_t *raw = data;
+ unsigned char buf[13];
+ const char *escape;
+ int32_t c;
+ int ret;
+
+ av_assert1(av_json_escape_writer_check(wr));
+ json_escape_writer_assert_abi(jwr);
+ if (jwr->error)
+ return;
+ while (cur < end) {
+ raw = cur;
+ ret = av_utf8_decode(&c, &cur, end, 0);
+ if (ret < 0) {
+ if ((jwr->flags & AV_JSON_FLAG_BAD_ENCODING_EXPLODE)) {
+ av_log(NULL, AV_LOG_PANIC, "Bad UTF-8 in JSON\n");
+ abort();
+ }
+ if ((jwr->flags & AV_JSON_FLAG_BAD_ENCODING_REPLACE)) {
+ c = 0xFFFD;
+ } else {
+ jwr->error = ret;
+ return;
+ }
+ }
+ av_assert1(c >= 0 && c <= 0x10FFFF);
+ if ((unsigned)(c - ' ') < 127 - ' ' && c != '"' && c != '\\')
+ continue;
+ if ((unsigned)(c - 0x0080) <= (0xFFFF - 0x0080)) /* TODO flag */
+ continue;
+ if (c == '"') {
+ escape = "\\\"";
+ } else if (c == '\\') {
+ escape = "\\\\";
+ } else if (c == '\n') {
+ escape = "\\n";
+ } else if (c == '\r') {
+ escape = "\\r";
+ } else if (c == '\t') {
+ escape = "\\t";
+ } else if (c == '\f') {
+ escape = "\\f";
+ } else if (c == '\b') {
+ escape = "\\b";
+ } else {
+ if (c < 0x10000)
+ snprintf(buf, sizeof(buf), "\\u%04X", c);
+ else /* JSON sucks: UTF-16 */
+ snprintf(buf, sizeof(buf), "\\u%04X\\u%04X",
+ 0xD800 + (((c - 0x10000) >> 10) & 0x3FF),
+ 0xDC00 + (((c - 0x10000) >> 0) & 0x3FF));
+ escape = buf;
+ }
+ if (raw > written)
+ av_writer_write(jwr->owr, written, raw - written);
+ av_writer_print(jwr->owr, escape);
+ written = raw = cur;
+ }
+ if (cur > written)
+ av_writer_write(jwr->owr, written, cur - written);
+}
+
+static int json_escape_writer_get_error(AVWriter wr, int self_only)
+{
+ AVJsonEscapeWriter *jwr = wr.obj;
+
+ av_assert1(av_json_escape_writer_check(wr));
+ return jwr->error ? jwr->error :
+ self_only ? 0 : av_writer_get_error(jwr->owr, 0);
+}
+
+AV_WRITER_DEFINE_METHODS(/*public*/, AVJsonEscapeWriter, av_json_escape_writer) {
+ .self_size = sizeof(AVWriterMethods),
+ .name = "AVJsonEscapeWriter",
+ .write = json_escape_writer_write,
+ .get_error = json_escape_writer_get_error,
+};
+
+AVJsonEscapeWriter *av_json_escape_writer_init(AVJsonEscapeWriter *jwr, AVWriter owr, unsigned flags)
+{
+ json_escape_writer_assert_abi(jwr);
+ jwr->owr = owr;
+ jwr->flags = flags;
+ return jwr;
+}
+
+AVWriter av_json_escape_writer_wrap(AVJsonEscapeWriter *jwr)
+{
+ AVWriter r = { av_json_escape_writer_get_methods(), jwr };
+ json_escape_writer_assert_abi(jwr);
+ return r;
+}
+
diff --git a/libavutil/json.h b/libavutil/json.h
new file mode 100644
index 0000000000..8048305c11
--- /dev/null
+++ b/libavutil/json.h
@@ -0,0 +1,467 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_JSON
+#define AVUTIL_JSON
+
+#include <stddef.h>
+#include "dict.h"
+#include "extendable.h"
+#include "log.h"
+#include "writer.h"
+
+/**
+ * @defgroup av_json AVJson
+ *
+ * API to serialize data to JSON.
+ *
+ * API summary and quick HOWTO:
+ *
+ * AVWriter out = av_dynbuf_writer();
+ * AVJson *jc = AV_JSON_DEFINE();
+ * av_json_init(jc, out, AV_JSON_FLAG_PRETTY_PRINT, NULL);
+ * av_json_begin_object(jc);
+ * av_json_add_string("user");
+ * av_json_add_string(user_name);
+ * av_json_add_string("score");
+ * av_json_add_int("%d", score);
+ * av_json_end_object(jc);
+ * av_json_finish(jc);
+ * ret = av_writer_get_error(out, 0);
+ * if (ret < 0) ...
+ * data = av_dynbuf_writer_get_data(wr, &size);
+ *
+ * @{
+ */
+
+typedef struct AVJson AVJson;
+typedef struct AVJsonStack AVJsonStack;
+typedef struct AVJsonEscapeWriter AVJsonEscapeWriter;
+typedef struct AVJsonValue AVJsonValue;
+typedef enum AVJsonValueType AVJsonValueType;
+
+/**
+ * Produce ASCII output by escaping non-ASCII characters
+ */
+#define AV_JSON_FLAG_ASCII 0x0001
+
+/**
+ * Abort if the input is not valid UTF-8.
+ */
+#define AV_JSON_FLAG_BAD_ENCODING_EXPLODE 0x0002
+
+/**
+ * If the input is not valid UTF-8, replace the offending partis with a
+ * replacement character.
+ */
+#define AV_JSON_FLAG_BAD_ENCODING_REPLACE 0x0004
+
+/**
+ * Pretty-print the output with spaces and indentation.
+ * XXX
+ */
+#define AV_JSON_FLAG_PRETTY_PRINT 0x0008
+
+/**
+ * Consider strings to be pseudo-binary instead of UTF-8.
+ *
+ * Warning: without AV_JSON_FLAG_ASCII, it will probably produce
+ * non-standard JSON.
+ * XXX
+ */
+#define AV_JSON_FLAG_PSEUDO_BINARY 0x0010
+
+/**
+ * Define a JSON context by allocating it as compound literals
+ * (hidden local variables).
+ * The context will be valid in the current scope and no further.
+ */
+#define AV_JSON_DEFINE(max_depth) \
+ av_json_preinit(&FF_NEW_SZ(AVJson), &FF_NEW_SZ(AVJsonEscapeWriter))
+
+/**
+ * Get the AVClass for a JSON context.
+ */
+AVClass *av_json_get_class(void);
+
+/**
+ * Pre-initialize a JSON context with its escape writer.
+ * @return jc itself
+ */
+AVJson *av_json_preinit(AVJson *jc, AVJsonEscapeWriter *jwr);
+
+/**
+ * Allocate a new JSON context.
+ * Only use this if AV_JSON_DEFINE() is not suitable.
+ * @return 0 or an AVERROR code, including AVERROR(ENOMEM).
+ */
+int av_json_alloc(AVJson **jc, unsigned max_depth);
+
+/**
+ * Free a JSON context allocated with av_json_alloc().
+ */
+void av_json_free(AVJson **jc);
+
+/**
+ * Initialize a JSON context with output, flags an options.
+ * This function can be called several times on the same context to reuse
+ * it.
+ */
+void av_json_init(AVJson *jc, AVWriter wr, unsigned flags, AVDictionary *options);
+
+/**
+ * Begin an object, i.e. a { key : value... } dictionary.
+ * After this, every other value must be a string.
+ * The behavior is undefined if a key is not a string.
+ * The stack object must be allocated and inited, and valid until the
+ * corresponding av_json_end_object().
+ * See av_json_begin_object() for a more convenient version.
+ */
+void av_json_begin_object_with_stack(AVJson *jc, AVJsonStack *stack);
+
+/**
+ * End an object.
+ */
+void av_json_end_object(AVJson *jc);
+
+/**
+ * Begin an array, i.e. a [ value, value... ] list.
+ * The stack object must be allocated and inited, and valid until the
+ * corresponding av_json_end_object().
+ * See av_json_begin_array() for a more convenient version.
+ */
+void av_json_begin_array_with_stack(AVJson *jc, AVJsonStack *stack);
+
+/**
+ * End an array.
+ */
+void av_json_end_array(AVJson *jc);
+
+/**
+ * Begin a string and a return an AVWriter to write its contents.
+ */
+AVWriter av_json_begin_string(AVJson *jc);
+
+/**
+ * End a string. Optional.
+ */
+void av_json_end_string(AVJson *jc);
+
+/**
+ * Add a string all at once.
+ */
+void av_json_add_string(AVJson *jc, const char *str);
+
+/**
+ * Add a string all at once from a format string and a va_list.
+ */
+void av_json_add_string_vprintf(AVJson *jc, const char *fmt, va_list va);
+
+/**
+ * Add a sring all at once from a format string and arguments.
+ */
+void av_json_add_string_printf(AVJson *jc, const char *fmt, ...) av_printf_format(2, 3);
+
+/**
+ * Add an integer number.
+ */
+void av_json_add_int(AVJson *jc, intmax_t val);
+
+/**
+ * Add a floating-point number.
+ */
+void av_json_add_double(AVJson *jc, double val);
+
+/**
+ * Add a boolean value (true/false).
+ */
+void av_json_add_bool(AVJson *jc, int val);
+
+/**
+ * Add a null value.
+ */
+void av_json_add_null(AVJson *jc);
+
+/**
+ * Add an arbitrary value from a format string and a va_list.
+ * Useful for adding a floating point number and controlling the format.
+ * Warning: the validity of the output cannot be guaranteed.
+ */
+void av_json_add_raw_vprintf(AVJson *jc, const char *fmt, va_list va);
+
+/**
+ * Add an arbitrary value from a format string and arguments.
+ * Useful for adding a floating point number and controlling the format.
+ * Warning: the validity of the output cannot be guaranteed.
+ */
+void av_json_add_raw_printf(AVJson *jc, const char *fmt, ...) av_printf_format(2, 3);
+
+/**
+ * Define and init a stack element as a compound literal
+ * (hidden local variable).
+ * Using this directly is not recommended.
+ */
+#define AV_JSON_STACK() (&FF_NEW_SZ(AVJsonStack))
+
+/**
+ * Allocate a stack element.
+ * Only use this if av_json_begin_object() / av_json_begin_array() cannot be
+ * used.
+ * @return 0 or an AVERROR code, including AVERROR(ENOMEM).
+ */
+int av_json_stack_alloc(AVJsonStack **stack);
+
+/**
+ * Free a stack element allocated with av_json_stack_alloc().
+ */
+void av_json_stack_free(AVJsonStack **stack);
+
+/**
+ * Begin an object with a stack element as a compound literal
+ * (hidden local variable).
+ * The corresponding av_json_end_object() must be in the same scope.
+ * After this, every other value must be a string.
+ * The behavior is undefined if a key is not a string.
+ */
+#define av_json_begin_object(jc) av_json_begin_object_with_stack((jc), AV_JSON_STACK())
+
+/**
+ * Begin an array with a stack element as a compound literal
+ * (hidden local variable).
+ * The corresponding av_json_end_array() must be in the same scope.
+ */
+#define av_json_begin_array(jc) av_json_begin_array_with_stack((jc), AV_JSON_STACK())
+
+/**
+ * An AVWriter object to escape JSON strings.
+ *
+ * Can be allocated on the stack.
+ *
+ * Should be inited with one of the utility functions.
+ */
+struct AVJsonEscapeWriter {
+ size_t self_size; /**< Size of the structure itself */
+ AVWriter owr; /**< AVWriter to send the output */
+ unsigned flags; /**< Escaping flags, see AV_JSON_FLAG_* */
+ int error; /**< Error status */
+ unsigned replacement_char; /**< Replacement character for bad UTF-8 */
+ FFReservedPadding padding[2];
+};
+
+/**
+ * Get the methods for a JSON escape writer.
+ * Probably not useful to use directly.
+ */
+const AVWriterMethods *av_json_escape_writer_get_methods(void);
+
+/**
+ * Check if a writer is a JSON escape writer.
+ */
+int av_json_escape_writer_check(AVWriter wr);
+
+/**
+ * Initialize an AVJsonEscapeWriter to an already-allocated memory buffer.
+ *
+ * @return jwr itself
+ * jwr->self_size must be set.
+ */
+AVJsonEscapeWriter *av_json_escape_writer_init(AVJsonEscapeWriter *jwr, AVWriter owr, unsigned flags);
+
+/**
+ * Create an AVWriter from an AVJsonEscapeWriter structure.
+ */
+AVWriter av_json_escape_writer_wrap(AVJsonEscapeWriter *jwr);
+
+/**
+ * Create an AVWriter to escape JSON strings.
+ *
+ * Note: as it relies on a compound statement, the AVJsonEscapeWriter object has
+ * a scope limited to the block where this macro is called.
+ */
+#define av_json_escape_writer(owr, flags) \
+ av_json_escape_writer_wrap(av_json_escape_writer_init(&FF_NEW_SZ(AVJsonEscapeWriter), (owr), (flags)))
+
+/**
+ * JSON encoding context.
+ *
+ * This structure must be allocated with AV_JSON_DEFINE() or equivalent
+ * code that will set av_class, self_size and escape_writer.
+ *
+ * It then must be initialized using av_json_init().
+ */
+struct AVJson {
+
+ /**
+ * Class; must be initialized to av_json_get_class().
+ */
+ const AVClass *av_class;
+
+ /**
+ * Size of the structure, must be initialized at allocation.
+ */
+ size_t self_size;
+
+ /**
+ * Encoding flags, see AV_JSON_FLAG_*.
+ */
+ unsigned flags;
+
+ /**
+ * Indentation shift.
+ */
+ unsigned indentation;
+
+ /**
+ * Output writer.
+ */
+ AVWriter out;
+
+ /****************************************************************
+ * The fields below this limit are private.
+ ****************************************************************/
+
+ /**
+ * Stack of states (object/array)
+ */
+ AVJsonStack *stack;
+
+ /**
+ * Pre-allocated writer for escaping strings.
+ *
+ * Must be allocated before init.
+ */
+ AVJsonEscapeWriter *escape_writer;
+
+ /**
+ * Depth of nested structures, for indentation.
+ */
+ unsigned depth;
+
+ /**
+ * True if a string is being constructed.
+ */
+ unsigned in_string : 1;
+
+ /**
+ * True if we currently are directly in an object.
+ */
+ unsigned in_object : 1;
+
+ /**
+ * True if we are about to write the first element of a structure.
+ */
+ unsigned first_element : 1;
+
+ /**
+ * True if we are about to write the key in an object.
+ */
+ unsigned object_key : 1;
+
+ FFReservedPadding padding[8];
+};
+
+/**
+ * Stack element for the JSON context.
+ */
+struct AVJsonStack {
+ size_t self_size;
+ AVJsonStack *prev;
+ unsigned short in_object;
+ FFReservedPadding padding;
+};
+
+/**
+ * Type of a JSON value.
+ *
+ * Note that JSON does not distinguish int and float values.
+ */
+enum AVJsonValueType {
+ AV_JSON_TYPE_NULL,
+ AV_JSON_TYPE_BOOL,
+ AV_JSON_TYPE_STRING,
+ AV_JSON_TYPE_INT,
+ AV_JSON_TYPE_DOUBLE,
+ AV_JSON_TYPE_OBJECT,
+ AV_JSON_TYPE_ARRAY,
+};
+
+/**
+ * Typed atomic JSON values.
+ * Objects and arrays cannot be represented.
+ * This structure is meant to be passed by value.
+ */
+struct AVJsonValue {
+ AVJsonValueType type;
+ union AVJsonValueValue {
+ intmax_t i;
+ double d;
+ const char *s;
+ } val;
+};
+
+/**
+ * Build an AVJsonValue for null.
+ */
+static inline AVJsonValue av_json_value_null(void)
+{
+ AVJsonValue ret = { .type = AV_JSON_TYPE_NULL };
+ return ret;
+}
+
+/**
+ * Build an AVJsonValue for a boolean.
+ */
+static inline AVJsonValue av_json_value_bool(int val)
+{
+ AVJsonValue ret = { .type = AV_JSON_TYPE_BOOL, .val.i = val };
+ return ret;
+}
+
+/**
+ * Build an AVJsonValue for a string.
+ * The pointer must stay valid while the value is used.
+ */
+static inline AVJsonValue av_json_value_string(const char *val)
+{
+ AVJsonValue ret = { .type = AV_JSON_TYPE_STRING, .val.s = val };
+ return ret;
+}
+
+/**
+ * Build an AVJsonValue for an integer.
+ */
+static inline AVJsonValue av_json_value_int(intmax_t val)
+{
+ AVJsonValue ret = { .type = AV_JSON_TYPE_INT, .val.i = val };
+ return ret;
+}
+
+/**
+ * Build an AVJsonValue for an integer.
+ */
+static inline AVJsonValue av_json_value_double(double val)
+{
+ AVJsonValue ret = { .type = AV_JSON_TYPE_INT, .val.d = val };
+ return ret;
+}
+
+/**
+ * @}
+ */
+
+#endif /* AVUTIL_JSON */
--
2.30.2
More information about the ffmpeg-devel
mailing list