[FFmpeg-devel] [PATCH 2/7] lavu: new AVWriter API.
Nicolas George
george at nsup.org
Wed Apr 21 15:27:01 EEST 2021
Signed-off-by: Nicolas George <george at nsup.org>
---
libavutil/Makefile | 2 +-
libavutil/writer.c | 443 +++++++++++++++++++++++++++++++++++++++++
libavutil/writer.h | 487 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 931 insertions(+), 1 deletion(-)
create mode 100644 libavutil/writer.c
create mode 100644 libavutil/writer.h
diff --git a/libavutil/Makefile b/libavutil/Makefile
index 27bafe9e12..d92872e296 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -172,7 +172,7 @@ OBJS = adler32.o \
tx_int32.o \
video_enc_params.o \
film_grain_params.o \
-
+ writer.o \
OBJS-$(CONFIG_CUDA) += hwcontext_cuda.o
OBJS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.o
diff --git a/libavutil/writer.c b/libavutil/writer.c
new file mode 100644
index 0000000000..89159ceaa2
--- /dev/null
+++ b/libavutil/writer.c
@@ -0,0 +1,443 @@
+/*
+ * 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 "log.h"
+#include "writer.h"
+
+/***************************************************************************
+ * Generic API
+ ***************************************************************************/
+
+#define FIELDOK(st, f) ((char *)(&(st)->f + 1) <= (char *)(st) + (st)->self_size)
+
+#define methods_assert_abi(methods) av_assert1(FIELDOK(methods, flush))
+
+static void printf_unchecked(AVWriter wr, const char *fmt, ...)
+{
+ va_list va;
+
+ va_start(va, fmt);
+ wr.methods->vprintf(wr, fmt, va);
+ va_end(va);
+}
+
+static void write_or_discard(AVWriter wr, size_t buf_size, size_t write_size)
+{
+ av_assert1(wr.methods->advance_buffer);
+ wr.methods->advance_buffer(wr, FFMIN(buf_size, write_size));
+ if (write_size > buf_size && wr.methods->notify_discard)
+ wr.methods->notify_discard(wr, write_size - buf_size);
+}
+
+static void av_writer_impossible(AVWriter wr, const char *message)
+{
+ methods_assert_abi(wr.methods);
+ if (wr.methods->impossible)
+ wr.methods->impossible(wr, message);
+ else
+ av_log(NULL, AV_LOG_ERROR, "Operation impossible with %s: %s\n",
+ wr.methods->name, message);
+}
+
+void av_writer_write(AVWriter wr, const char *data, size_t size)
+{
+ methods_assert_abi(wr.methods);
+ if (wr.methods->write) {
+ wr.methods->write(wr, data, size);
+ } else if (wr.methods->get_buffer) {
+ size_t buf_size;
+ char *buf = wr.methods->get_buffer(wr, size, &buf_size);
+ if (buf_size > 0)
+ memcpy(buf, data, FFMIN(size, buf_size));
+ write_or_discard(wr, buf_size, size);
+ } else if (wr.methods->vprintf) {
+ size_t i;
+ for (i = 0; i < size; i++)
+ printf_unchecked(wr, "%c", data[i]);
+ } else {
+ av_writer_impossible(wr, "av_writer_write()");
+ }
+}
+
+void av_writer_print(AVWriter wr, const char *str)
+{
+ av_writer_write(wr, str, strlen(str));
+}
+
+void av_writer_printf(AVWriter wr, const char *fmt, ...)
+{
+ va_list va;
+
+ va_start(va, fmt);
+ av_writer_vprintf(wr, fmt, va);
+ va_end(va);
+}
+
+void av_writer_vprintf(AVWriter wr, const char *fmt, va_list va)
+{
+ methods_assert_abi(wr.methods);
+ if (wr.methods->vprintf) {
+ wr.methods->vprintf(wr, fmt, va);
+ } else if (wr.methods->get_buffer) {
+ size_t buf_size;
+ char *buf = wr.methods->get_buffer(wr, 128, &buf_size);
+ va_list va2;
+ int ret;
+ va_copy(va2, va);
+ ret = vsnprintf(buf, buf_size, fmt, va2);
+ va_end(va2);
+ if (ret < 0)
+ return;
+ if ((size_t)ret + 1 > buf_size) {
+ buf = wr.methods->get_buffer(wr, ret + 1, &buf_size);
+ ret = vsnprintf(buf, buf_size, fmt, va);
+ if (ret < 0)
+ return;
+ }
+ write_or_discard(wr, buf_size, ret);
+ } else if (wr.methods->write) {
+ AVBPrint bp;
+ av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
+ av_vbprintf(&bp, fmt, va);
+ if (av_bprint_is_complete(&bp)) {
+ wr.methods->write(wr, bp.str, bp.len);
+ } else {
+ wr.methods->write(wr, bp.str, bp.size - 1);
+ if (wr.methods->notify_discard)
+ wr.methods->notify_discard(wr, bp.len - bp.size + 1);
+ }
+ av_bprint_finalize(&bp, NULL);
+ } else {
+ av_writer_impossible(wr, "av_writer_vprintf()");
+ }
+}
+
+void av_writer_add_chars(AVWriter wr, char c, size_t n)
+{
+ char buf[512];
+ size_t m;
+
+ m = FFMIN(n, sizeof(buf) - 1);
+ memset(buf, c, m);
+ while (n) {
+ av_writer_write(wr, buf, m);
+ n -= m;
+ m = FFMIN(n, sizeof(buf) - 1);
+ }
+}
+
+void av_writer_flush(AVWriter wr)
+{
+ methods_assert_abi(wr.methods);
+ if (wr.methods->flush)
+ wr.methods->flush(wr);
+}
+
+int av_writer_get_error(AVWriter wr, int self_only)
+{
+ methods_assert_abi(wr.methods);
+ if (wr.methods->get_error)
+ return wr.methods->get_error(wr, self_only);
+ return 0;
+}
+
+/***************************************************************************
+ * AVBufWriter - write to pre-allocated memory
+ ***************************************************************************/
+
+#define buf_writer_assert_abi(bwr) av_assert1(FIELDOK(bwr, pos))
+
+static size_t buf_writer_room(AVBufWriter *bwr)
+{
+ return bwr->pos < bwr->size ? bwr->size - bwr->pos - 1 : 0;
+}
+
+static void buf_writer_write(AVWriter wr, const char *data, size_t size)
+{
+ AVBufWriter *bwr = wr.obj;
+
+ av_assert1(av_buf_writer_check(wr));
+ buf_writer_assert_abi(bwr);
+ size = FFMIN(buf_writer_room(bwr), size);
+ memcpy(bwr->buf + bwr->pos, data, size);
+ bwr->pos += size;
+ bwr->buf[bwr->pos] = 0;
+}
+
+static void buf_writer_vprintf(AVWriter wr, const char *fmt, va_list va)
+{
+ AVBufWriter *bwr = wr.obj;
+ int ret;
+
+ av_assert1(av_buf_writer_check(wr));
+ buf_writer_assert_abi(bwr);
+ ret = vsnprintf(bwr->buf + bwr->pos, buf_writer_room(bwr) + 1, fmt, va);
+ if (ret > 0)
+ bwr->pos += ret;
+}
+
+static char *buf_writer_get_buffer(AVWriter wr, size_t min_size, size_t *size)
+{
+ AVBufWriter *bwr = wr.obj;
+
+ av_assert1(av_buf_writer_check(wr));
+ buf_writer_assert_abi(bwr);
+ *size = bwr->size - 1 - bwr->pos;
+ return bwr->buf + bwr->pos;
+}
+
+static void buf_writer_advance_buffer(AVWriter wr, size_t size)
+{
+ AVBufWriter *bwr = wr.obj;
+
+ av_assert1(av_buf_writer_check(wr));
+ buf_writer_assert_abi(bwr);
+ bwr->pos += size;
+ bwr->buf[bwr->pos] = 0;
+}
+
+AV_WRITER_DEFINE_METHODS(/*public*/, AVBufWriter, av_buf_writer) {
+ .self_size = sizeof(AVWriterMethods),
+ .name = "AVBufWriter",
+ .write = buf_writer_write,
+ .vprintf = buf_writer_vprintf,
+ .get_buffer = buf_writer_get_buffer,
+ .advance_buffer = buf_writer_advance_buffer,
+};
+
+AVBufWriter *av_buf_writer_init(AVBufWriter *bwr, char *buf, size_t size)
+{
+ buf_writer_assert_abi(bwr);
+ bwr->buf = buf;
+ bwr->size = size;
+ bwr->pos = 0;
+ buf[0] = 0;
+ return bwr;
+}
+
+AVWriter av_buf_writer_wrap(AVBufWriter *bwr)
+{
+ AVWriter r = { av_buf_writer_get_methods(), bwr };
+ buf_writer_assert_abi(bwr);
+ return r;
+}
+
+/***************************************************************************
+ * AVDynbufWriter - write to a dynamic buffer
+ ***************************************************************************/
+
+#define dynbuf_writer_assert_abi(dwr) av_assert1(FIELDOK(dwr, bp))
+
+static void dynbuf_writer_write(AVWriter wr, const char *data, size_t size)
+{
+ AVDynbufWriter *dwr = wr.obj;
+ unsigned char *buf;
+ unsigned buf_size;
+ size_t copy;
+
+ av_assert1(av_dynbuf_writer_check(wr));
+ dynbuf_writer_assert_abi(dwr);
+ av_bprint_get_buffer(&dwr->bp, FFMIN(size, UINT_MAX - 5), &buf, &buf_size);
+ if (buf_size >= 1) {
+ copy = FFMIN(buf_size - 1, size);
+ memcpy(buf, data, copy);
+ buf[copy] = 0;
+ }
+ dwr->bp.len += size;
+}
+
+static void dynbuf_writer_vprintf(AVWriter wr, const char *fmt, va_list va)
+{
+ AVDynbufWriter *dwr = wr.obj;
+
+ av_assert1(av_dynbuf_writer_check(wr));
+ dynbuf_writer_assert_abi(dwr);
+ av_vbprintf(&dwr->bp, fmt, va);
+}
+
+char *av_dynbuf_writer_get_buffer(AVWriter wr, size_t size, size_t *rsize)
+{
+ AVDynbufWriter *dwr = wr.obj;
+ unsigned char *buf;
+ unsigned isize;
+
+ av_assert1(av_dynbuf_writer_check(wr));
+ dynbuf_writer_assert_abi(dwr);
+ av_bprint_get_buffer(&dwr->bp, FFMIN(size, UINT_MAX - 5), &buf, &isize);
+ *rsize = isize ? isize - 1 : 0;
+ return buf;
+}
+
+void av_dynbuf_writer_advance_buffer(AVWriter wr, size_t size)
+{
+ AVDynbufWriter *dwr = wr.obj;
+
+ av_assert1(av_dynbuf_writer_check(wr));
+ dynbuf_writer_assert_abi(dwr);
+ dwr->bp.len += size;
+ dwr->bp.str[FFMIN(dwr->bp.len, dwr->bp.size - 1)] = 0;
+}
+
+static int dynbuf_writer_get_error(AVWriter wr, int self_only)
+{
+ AVDynbufWriter *dwr = wr.obj;
+
+ av_assert1(av_dynbuf_writer_check(wr));
+ dynbuf_writer_assert_abi(dwr);
+ return av_bprint_is_complete(&dwr->bp) ? 0 : AVERROR(ENOMEM);
+}
+
+AV_WRITER_DEFINE_METHODS(/*public*/, AVDynbufWriter, av_dynbuf_writer) {
+ .self_size = sizeof(AVWriterMethods),
+ .name = "AVDynbufWriter",
+ .write = dynbuf_writer_write,
+ .vprintf = dynbuf_writer_vprintf,
+ .get_buffer = av_dynbuf_writer_get_buffer,
+ .advance_buffer = av_dynbuf_writer_advance_buffer,
+ .get_error = dynbuf_writer_get_error,
+};
+
+AVDynbufWriter *av_dynbuf_writer_init(AVDynbufWriter *dwr)
+{
+ dynbuf_writer_assert_abi(dwr);
+ av_bprint_init(&dwr->bp, 0, AV_BPRINT_SIZE_UNLIMITED);
+ return dwr;
+}
+
+AVWriter av_dynbuf_writer_wrap(AVDynbufWriter *dwr)
+{
+ AVWriter r = { av_dynbuf_writer_get_methods(), dwr };
+ dynbuf_writer_assert_abi(dwr);
+ return r;
+}
+
+char *av_dynbuf_writer_get_data(AVWriter wr, size_t *size)
+{
+ av_assert1(!dynbuf_writer_get_error(wr, 0));
+ return av_dynbuf_writer_get_data_unsafe(wr, size);
+}
+
+char *av_dynbuf_writer_get_data_unsafe(AVWriter wr, size_t *size)
+{
+ AVDynbufWriter *dwr = wr.obj;
+
+ av_assert1(av_dynbuf_writer_check(wr));
+ dynbuf_writer_assert_abi(dwr);
+ if (size)
+ *size = dwr->bp.len;
+ return dwr->bp.str;
+}
+
+int av_dynbuf_writer_finalize(AVWriter wr, char **buf, size_t *size)
+{
+ int ret;
+
+ ret = dynbuf_writer_get_error(wr, 0);
+ if (ret < 0) {
+ *buf = NULL;
+ *size = 0;
+ av_dynbuf_writer_finalize_unsafe(wr, NULL, NULL);
+ return ret;
+ } else {
+ return av_dynbuf_writer_finalize_unsafe(wr, buf, size);
+ }
+}
+
+int av_dynbuf_writer_finalize_unsafe(AVWriter wr, char **buf, size_t *size)
+{
+ AVDynbufWriter *dwr = wr.obj;
+
+ av_assert1(av_dynbuf_writer_check(wr));
+ dynbuf_writer_assert_abi(dwr);
+ if (size)
+ *size = dwr->bp.len;
+ return av_bprint_finalize(&dwr->bp, buf);
+}
+
+/***************************************************************************
+ * AVLogWriter - write to av_log()
+ ***************************************************************************/
+
+static void log_writer_vprintf(AVWriter wr, const char *fmt, va_list va)
+{
+ av_assert1(av_log_writer_check(wr));
+ av_vlog(wr.obj, AV_LOG_INFO, fmt, va);
+}
+
+AV_WRITER_DEFINE_METHODS(/*public*/, AVLogWriter, av_log_writer) {
+ .self_size = sizeof(AVWriterMethods),
+ .name = "AVLogWriter",
+ .vprintf = log_writer_vprintf,
+};
+
+AVWriter av_log_writer(void *obj)
+{
+ AVWriter wr = {
+ .methods = av_log_writer_get_methods(),
+ .obj = obj,
+ };
+ return wr;
+}
+
+void av_log_writer_log(AVWriter wr, int level, const char *fmt, ...)
+{
+ va_list va;
+
+ va_start(va, fmt);
+ if (av_log_writer_check(wr)) {
+ av_vlog(wr.obj, level, fmt, va);
+ } else {
+ av_writer_vprintf(wr, fmt, va);
+ }
+ va_end(va);
+}
+
+/***************************************************************************
+ * AVStdioWriter - write to stdio
+ ***************************************************************************/
+
+static void stdio_writer_vprintf(AVWriter wr, const char *fmt, va_list va)
+{
+ av_assert1(av_stdio_writer_check(wr));
+ vfprintf(wr.obj, fmt, va);
+}
+
+static int stdio_writer_get_error(AVWriter wr, int self_only)
+{
+ av_assert1(av_stdio_writer_check(wr));
+ return AVERROR(ferror(wr.obj));
+}
+
+AV_WRITER_DEFINE_METHODS(/*public*/, AVStdioWriter, av_stdio_writer) {
+ .self_size = sizeof(AVWriterMethods),
+ .name = "AVStdioWriter",
+ .vprintf = stdio_writer_vprintf,
+ .get_error = stdio_writer_get_error,
+};
+
+AVWriter av_stdio_writer(FILE *out)
+{
+ AVWriter wr = {
+ .methods = av_stdio_writer_get_methods(),
+ .obj = out,
+ };
+ return wr;
+}
diff --git a/libavutil/writer.h b/libavutil/writer.h
new file mode 100644
index 0000000000..661da381c2
--- /dev/null
+++ b/libavutil/writer.h
@@ -0,0 +1,487 @@
+/*
+ * Copyright (c) 2021 The FFmpeg project
+ *
+ * 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_WRITER_H
+#define AVUTIL_WRITER_H
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdarg.h>
+
+#include "extendable.h"
+#include "bprint.h"
+
+/**
+ * @defgroup av_writer AVWriter
+ *
+ * Object-oriented API to write strings and binary data.
+ *
+ * @{
+ */
+
+typedef struct AVWriterMethods AVWriterMethods;
+
+/**
+ * Opaque object to write strings and binary data.
+ *
+ * An AVWriter is meant to allow to build and return string (and blocks of
+ * binary data) efficiently between functions.
+ * For example, a function that serialize something into a string will
+ * actually write into an AVWriter.
+ *
+ * To emulate idiomatic practices of writing into a buffer, you can write:
+ * char buf[4096];
+ * AVWriter wr = av_buf_writer_array(buf);
+ * which is a macro equivalent (using modern C magic) to:
+ * AVWriterBuf bwr;
+ * av_buf_writer_init(&bwr, buf, sizeof(buf));
+ * AVWriter wr = av_buf_writer_wrap(&bwr);
+ * so you can write into any already allocated memory.
+ * The string will be 0-terminated, so you can omit len.
+ *
+ * To avoid the problems of size limits, you should use a dynamic buffer.
+ * AVDynbufWriter provides an implementation that uses the stack for small
+ * strings and the heap for longer ones.
+ *
+ * AVWriter wr = av_dynbuf_writer();
+ * write_something(wr);
+ * if (!av_writer_get_error(wr)) {
+ * output(av_dynbuf_writer_get_data(wr, &size));
+ * av_dynbuf_finish(wr, NULL, NULL);
+ *
+ * It is possible to create an AVWriter to av_log() and to implement new
+ * kinds of AVWriter.
+ *
+ * AVWriter objects are passed by value. It allows creating a writer on the
+ * fly, without extra variable or error checking. The structure can never
+ * change.
+ *
+ * Every type of AVWriter is supposed to have a pair of functions:
+ * av_something_writer_get_methods() returns the methods for that type.
+ * av_something_writer_checks() returns 1 if the writer is of that type.
+ * When a type of AVWriter defines specific functions, it is usually the
+ * responsibility of the caller to ensure that they are called only with a
+ * compatible AVWriter; otherwise the behavior is undefined.
+ */
+typedef struct AVWriter {
+ const AVWriterMethods *methods;
+ void *obj;
+} AVWriter;
+
+/**
+ * Write a data buffer to an AVWriter.
+ */
+void av_writer_write(AVWriter wr, const char *buf, size_t size);
+
+/**
+ * Write a 0-terminated string to an AVWriter.
+ */
+void av_writer_print(AVWriter wr, const char *str);
+
+/**
+ * Write a formatted string to an AVWriter.
+ */
+void av_writer_printf(AVWriter wr, const char *fmt, ...);
+
+/**
+ * Write a formatted to string an AVWriter using a va_list.
+ */
+void av_writer_vprintf(AVWriter wr, const char *fmt, va_list va);
+
+/**
+ * Write a sequence of identical chars to an AVWriter.
+ */
+void av_writer_add_chars(AVWriter wr, char c, size_t n);
+
+/**
+ * Flush data that may be buffered in the writer.
+ */
+void av_writer_flush(AVWriter wr);
+
+/**
+ * Return the error status of the writer, an AVERROR code.
+ *
+ * If self_only is non-zero, return errors only on this writer and not on
+ * possible other writers that it got from the caller. If in doubt, use 0.
+ */
+int av_writer_get_error(AVWriter wr, int self_only);
+
+/**
+ * Print a sane value for invalid input.
+ *
+ * This is a flag for all av_something_write() functions: when presented
+ * with an invalid "something", if the flag is not present they should leave
+ * the writer unchanged; if the flag is present they should print a sane
+ * fallback string. In both case they should return an error code.
+ */
+#define AV_WRITER_FALLBACK 0x10000
+
+/***************************************************************************/
+
+/**
+ * @defgroup av_buf_writer AVBufWriter
+ *
+ * An implementtion of AVWriter that writes into an already-allocated buffer
+ * of memory.
+ *
+ * The buffer is kept 0-terminated. If the buffer is too small, the data is
+ * discarded, but the total size is computed.
+ *
+ * @{
+ */
+
+/**
+ * An AVWriter object for pre-allocated memory buffers.
+ *
+ * Can be allocated on the stack.
+ *
+ * Should be inited with one of the utility functions.
+ */
+typedef struct AVBufWriter {
+ size_t self_size; /**< Size of the structure itself */
+ char *buf; /**< Memory buffer. Must not be NULL nor empty. */
+ size_t size; /**< Size of the memory buffer. Must not be 0. */
+ size_t pos; /**< Position in the memory buffer. */
+} AVBufWriter;
+
+const AVWriterMethods *av_buf_writer_get_methods(void);
+int av_buf_writer_check(AVWriter wr);
+
+/**
+ * Initialize an AVBufWriter to an already-allocated memory buffer.
+ *
+ * @return bwr itself
+ * bwr->self_size must be set.
+ */
+AVBufWriter *av_buf_writer_init(AVBufWriter *bwr, char *buf, size_t size);
+
+/**
+ * Create an AVWriter from an AVBufWriter structure.
+ */
+AVWriter av_buf_writer_wrap(AVBufWriter *bwr);
+
+/**
+ * Create an AVWriter to a buffer.
+ *
+ * Note: as it relies on a compound statement, the AVBufWriter object has
+ * a scope limited to the block where this macro is called.
+ */
+#define av_buf_writer(buf, size) \
+ av_buf_writer_wrap(av_buf_writer_init(&FF_NEW_SZ(AVBufWriter), (buf), (size)))
+
+/**
+ * Create an AVWriter to a char[] or equivalent.
+ *
+ * Note: as it relies on a compound statement, the AVBufWriter object has
+ * a scope limited to the block where this macro is called.
+ */
+#define av_buf_writer_array(array) \
+ av_buf_writer(array, sizeof (array))
+
+/**
+ * @}
+ */
+
+/***************************************************************************/
+
+/**
+ * @defgroup av_dynbuf_writer AVDynbufWriter
+ *
+ * An implementation of AVWriter that writes to a dynamic buffer.
+ *
+ * The buffer is kept 0-terminated.
+ *
+ * The buffer is initially kept in the variable itself, it switches to heap
+ * allocation if it grows too large. In that case, av_writer_get_error() can
+ * return AVERROR(ENOMEM) if the allocation fails.
+ *
+ * @{
+ */
+
+/**
+ * An AVWriter object for pre-allocated memory buffers.
+ *
+ * Can be allocated on the stack.
+ *
+ * Should be inited with one of the utility functions.
+ */
+typedef struct AVDynbufWriter {
+ size_t self_size; /**< Size of the structure itself */
+ AVBPrint bp;
+} AVDynbufWriter;
+
+const AVWriterMethods *av_dynbuf_writer_get_methods(void);
+int av_dynbuf_writer_check(AVWriter wr);
+
+/**
+ * Initialize an AVDynbufWriter.
+ *
+ * @return dwr itself
+ * dwr->self_size must be set.
+ */
+/* XXX do we need to expose size_init and max_size from AVBPrint? */
+AVDynbufWriter *av_dynbuf_writer_init(AVDynbufWriter *dwr);
+
+/**
+ * Create an AVWriter from an AVDynbufWriter structure.
+ */
+AVWriter av_dynbuf_writer_wrap(AVDynbufWriter *dwr);
+
+/**
+ * Create an AVWriter to a dynamic buffer.
+ *
+ * Note: as it relies on a compound statement, the AVDynbufWriter object has
+ * a scope limited to the block where this macro is called.
+ */
+#define av_dynbuf_writer() \
+ av_dynbuf_writer_wrap(av_dynbuf_writer_init(&FF_NEW_SZ(AVDynbufWriter)))
+
+/**
+ * Get a pointer to the buffer data of an AVWriter to a dynamic buffer.
+ *
+ * If not null, size will be set to the size of the data in the buffer.
+ *
+ * Undefined behavior if called with another type of AVWriter.
+ * Undefined behavior if called with a writer in error.
+ */
+char *av_dynbuf_writer_get_data(AVWriter wr, size_t *size);
+
+/**
+ * Get a pointer to the buffer data of an AVWriter to a dynamic buffer.
+ *
+ * If not null, size will be set to the size of the data in the buffer.
+ *
+ * If the writer is in error, the data may be truncated.
+ *
+ * Undefined behavior if called with another type of AVWriter.
+ */
+char *av_dynbuf_writer_get_data_unsafe(AVWriter wr, size_t *size);
+
+/**
+ * Finalize an AVWriter to a dynamic buffer.
+ *
+ * @arg[out] buf if not NULL, used to return the buffer contents
+ * @arg[out] size if not NULL, used to return the size of the data
+ * @return 0 for success or error code (probably AVERROR(ENOMEM))
+ *
+ * In case of error, the buffer will not be duplicated but still freed.
+ * Same if the writer is already in error.
+ *
+ * Undefined behavior if called with another type of AVWriter.
+ */
+int av_dynbuf_writer_finalize(AVWriter wr, char **buf, size_t *size);
+
+/**
+ * Finalize an AVWriter to a dynamic buffer.
+ *
+ * @arg[out] buf if not NULL, used to return the buffer contents
+ * @arg[out] size if not NULL, used to return the size of the data
+ * @return 0 for success or error code (probably AVERROR(ENOMEM))
+ *
+ * If the writer is in error, the returned data may be truncated.
+ *
+ * In case of error, the buffer will not be duplicated but still freed.
+ *
+ * Undefined behavior if called with another type of AVWriter.
+ */
+int av_dynbuf_writer_finalize_unsafe(AVWriter wr, char **buf, size_t *size);
+
+/**
+ * Allocate chars in the buffer for external use.
+ *
+ * Undefined behavior if called with another type of AVWriter.
+ */
+char *av_dynbuf_writer_get_buffer(AVWriter wr, size_t size, size_t *rsize);
+
+/**
+ * Advance the position in the buffer.
+ *
+ * size must be <= *rsize on a previous call to
+ * av_dynbuf_writer_get_buffer().
+ *
+ * Undefined behavior if called with another type of AVWriter.
+ */
+void av_dynbuf_writer_advance_buffer(AVWriter wr, size_t size);
+
+/**
+ * @}
+ */
+
+/***************************************************************************/
+
+/**
+ * @defgroup av_stdio_writer AVStdioWriter
+ *
+ * An implementation of AVWriter that writes to stdio.
+ *
+ * @{
+ */
+
+const AVWriterMethods *av_stdio_writer_get_methods(void);
+int av_stdio_writer_check(AVWriter wr);
+
+/**
+ * Create an AVWriter that goes to a stdio FILE.
+ */
+AVWriter av_stdio_writer(FILE *out);
+
+/**
+ * @}
+ */
+
+/***************************************************************************/
+
+/**
+ * @defgroup av_log_writer AVLogWriter
+ *
+ * An implementation of AVWriter that writes to av_log().
+ *
+ * @{
+ */
+
+const AVWriterMethods *av_log_writer_get_methods(void);
+int av_log_writer_check(AVWriter wr);
+
+/**
+ * Create an AVWriter that goes to av_log(obj).
+ */
+AVWriter av_log_writer(void *obj);
+
+/**
+ * Log to a writer.
+ * If wr does not go to av_log(), level is ignored.
+ */
+void av_log_writer_log(AVWriter wr, int level, const char *fmt, ...);
+
+/**
+ * @}
+ */
+
+/***************************************************************************/
+
+/**
+ * @defgroup av_writer_methods AVWriterMethods
+ *
+ * Structures and utility needed to define new types of AVWriter.
+ *
+ * @{
+ */
+
+/**
+ * Set of methods for implementing an AVWriter.
+ *
+ * Applications that want to implement other kinds of AVWriter
+ * need to create a structure with some of these methods implemented.
+ *
+ * There is no error report.
+ * Implementations must provide their own way of reporting errors.
+ */
+struct AVWriterMethods {
+
+ /**
+ * Size of the structure itself.
+ * Must normally be set to sizeof(AVWriterMethods).
+ */
+ size_t self_size;
+
+ /**
+ * Name of the object type.
+ */
+ const char *name;
+
+ /**
+ * Warn that an operation was impossible even with fallbacks.
+ */
+ void (*impossible)(AVWriter wr, const char *message);
+
+ /**
+ * Notify that size chars have been discarded
+ */
+ void (*notify_discard)(AVWriter wr, size_t size);
+
+ /**
+ * Get the error status of the writer
+ * If self_only is non-zero, return errors only on this writer and not on
+ * possible other writers that it got from the caller. Errors from
+ * writers created internally should always be checked.
+ */
+ int (*get_error)(AVWriter wr, int self_only);
+
+ /**
+ * Write chars directly.
+ */
+ void (*write)(AVWriter wr, const char *buf, size_t size);
+
+ /**
+ * Write a formatted string.
+ */
+ void (*vprintf)(AVWriter wr, const char *fmt, va_list ap);
+
+ /**
+ * Get a buffer to write data.
+ * If *size is returned < min_size, data may get discarded.
+ * A writer that implements this method must implement advance_buffer too.
+ * If vprintf is not implemented, av_write_printf() will use
+ * get_buffer() and vsnprintf(): it will need an extra char in the
+ * buffer for the 0 that vsnprintf() adds.
+ */
+ char *(*get_buffer)(AVWriter wr, size_t min_size, size_t *size);
+
+ /**
+ * Acknowledge chars written in a buffer obtained with get_buffer().
+ * size is guaranteed <= the size value returned by get_buffer().
+ */
+ void (*advance_buffer)(AVWriter wr, size_t size);
+
+ /**
+ * Flush immediately data that may be buffered in the writer.
+ */
+ void (*flush)(AVWriter wr);
+
+};
+
+/**
+ * Convenience macro for the boilerplate necessary to define a writer class.
+ *
+ * @arg qual type qualifier for for the symbols, for example "static"
+ * @arg type class name for the type of writer,
+ * for example "AVBufWriter" or "MyWriter"
+ * @arg prefix prefix for the symbols,
+ * for example "av_buf_writer" or "my_writer"
+ */
+#define AV_WRITER_DEFINE_METHODS(qual, type, prefix) \
+static const AVWriterMethods prefix##_methods; \
+qual const AVWriterMethods *prefix##_get_methods(void) { \
+ return &prefix##_methods; \
+} \
+qual int prefix##_check(AVWriter wr) { \
+ return wr.methods == prefix##_get_methods(); \
+} \
+static const AVWriterMethods prefix##_methods =
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* AVUTIL_WRITER_H */
--
2.30.2
More information about the ffmpeg-devel
mailing list