From: Stefano Sabatini <stefasab@gmail.com> To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org> Subject: Re: [FFmpeg-devel] [PATCH] lavu: header and documentation for AVWriter Date: Thu, 1 Sep 2022 01:03:58 +0200 Message-ID: <20220831230358.GA3557@mariano> (raw) In-Reply-To: <20220824151828.24218-1-george@nsup.org> On date Wednesday 2022-08-24 17:18:28 +0200, Nicolas George wrote: > The actual implementation, tests and uses in the rest of > FFmpeg code will be committed separately once the API is > settled. > > Signed-off-by: Nicolas George <george@nsup.org> > --- > doc/avwriter_intro.md | 109 ++++++++++ > libavutil/writer.h | 484 ++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 593 insertions(+) > create mode 100644 doc/avwriter_intro.md > create mode 100644 libavutil/writer.h > [...] > diff --git a/libavutil/writer.h b/libavutil/writer.h > new file mode 100644 > index 0000000000..55e2cf3ea6 > --- /dev/null > +++ b/libavutil/writer.h > @@ -0,0 +1,484 @@ > +/* > + * Copyright (c) 2022 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. > + * > + * AVWriter is meant to allow to build and return strings (and blocks of > + * binary data) efficiently between functions. > + * For example, a function that serialize something into a string will serializeS > + * actually write into an AVWriter, and the caller will choose the way the > + * data will be stored or processed on the fly. > + * > + * For a quick introduction on how to use AVWriter in simple cases, see > + * doc/avwriter_intro.md. > + * > + * There are various pre-defined types of AVWriter, see below: > + * > + * - av_dynbuf_writer() writes the data into a buffer that is grown with > + * av_realloc() if it does not fit in the initial buffer; it is the > + * recommended choice. > + * > + * - av_buf_writer() writes the data into a pre-existing finite buffer. > + * > + * - av_stdio_writer() writes the data into a FILE*. > + * > + * - av_log_writer() writes the data to av_log(). > + * > + * 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. > + */ > +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. > + * Note: do not use libc-specific extensions to the format string. > + */ > +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 This "something" is vague and can be confused with the "something" in "av_something_write", maybe something as: when presented with invalid arguments, if the flag is not set the called method should leave... > + * the writer unchanged; if the flag is present they should print a sane > + * fallback string. > + */ > +#define AV_WRITER_FALLBACK 0x10000 > + > +/***************************************************************************/ > + > +/** > + * @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 what variable? => in the AVWriter data? > + * 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 */ > + unsigned flags; > + 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. > + */ > +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 without checking for error first. > + */ > +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 > + * (unsafe version). > + * > + * 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 (unsafe version). > + * > + * @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(). what is *rsize? > + * > + * Undefined behavior if called with another type of AVWriter. > + * Undefined behavior is called not directly after is called => if called > + * av_dynbuf_writer_get_buffer(). > + */ > +void av_dynbuf_writer_advance_buffer(AVWriter wr, size_t size); > + > +/** > + * @} > + */ > + > +/***************************************************************************/ > + > +/** > + * @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)) av_buf_writer_from_array? > + > +/** > + * @} > + */ > + > +/***************************************************************************/ > + > +/** > + * @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); av_file_writer() ? > + > +/** > + * @} > + */ > + > +/***************************************************************************/ > + > +/** > + * @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. > + * > + * 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. > + * > + * A macro to define the structure and functions is provided below. > + * > + * 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. > + */ > +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); I'd use a verb for consistency/clarify. notify_impossibility or notify_impossible_op? > + > + /** > + * 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. If the returned *size is < min_size... ? > + * 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(). size is or should be guaranteed? > + */ > + void (*advance_buffer)(AVWriter wr, size_t size); > + [...] _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next prev parent reply other threads:[~2022-08-31 23:04 UTC|newest] Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top 2022-08-24 15:18 Nicolas George 2022-08-24 15:45 ` Soft Works 2022-08-24 15:59 ` Andreas Rheinhardt 2022-08-24 16:01 ` Nicolas George 2022-08-30 17:08 ` Nicolas George 2022-08-30 19:33 ` Leo Izen 2022-08-30 19:37 ` Nicolas George 2022-08-31 3:13 ` Leo Izen 2022-08-31 3:23 ` Andreas Rheinhardt 2022-08-31 19:28 ` Nicolas George 2022-08-31 23:03 ` Stefano Sabatini [this message] 2022-09-01 13:01 ` Nicolas George 2022-09-01 21:33 ` Stefano Sabatini 2022-09-02 6:41 ` Anton Khirnov 2022-09-07 13:30 ` Nicolas George 2022-09-07 20:05 ` Jean-Baptiste Kempf 2022-09-07 21:13 ` Nicolas George 2022-09-08 16:18 ` Anton Khirnov 2022-09-14 21:29 ` Michael Niedermayer 2023-04-25 17:11 ` Nicolas George 2023-04-25 17:20 ` James Almer 2023-04-28 10:00 ` Nicolas George 2023-04-26 9:05 ` Anton Khirnov 2023-04-28 9:58 ` Nicolas George
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20220831230358.GA3557@mariano \ --to=stefasab@gmail.com \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git