From: Andrew Sayers <ffmpeg-devel@pileofstuff.org>
To: ffmpeg-devel@ffmpeg.org
Cc: Andrew Sayers <ffmpeg-devel@pileofstuff.org>
Subject: [FFmpeg-devel] [PATCH v3 1/3] doc: Explain what "context" means
Date: Mon, 22 Apr 2024 16:56:48 +0100
Message-ID: <20240422155836.385333-2-ffmpeg-devel@pileofstuff.org> (raw)
In-Reply-To: <20240422155836.385333-1-ffmpeg-devel@pileofstuff.org>
Derived from detailed explanations kindly provided by Stefano Sabatini:
https://ffmpeg.org/pipermail/ffmpeg-devel/2024-April/325903.html
---
doc/context.md | 276 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 276 insertions(+)
create mode 100644 doc/context.md
diff --git a/doc/context.md b/doc/context.md
new file mode 100644
index 0000000000..73caacf54f
--- /dev/null
+++ b/doc/context.md
@@ -0,0 +1,276 @@
+# Context-oriented programming
+
+Like many C projects, FFmpeg has adopted the subset of object-oriented techniques
+that help solve its problems. Object-like structures are called "contexts",
+and this document provides a general introduction to how they work.
+
+Object-oriented programming usually focusses on *access* as a primary concern.
+For example, members of an object are visibly designated "private", "constant"
+etc. to control how they are accessed. *Reflection* is a secondary concern,
+where it is provided at all. For example, C++ has no built-in way to get a
+string containing the name of a variable.
+
+Reflection is extremely important for FFmpeg, because user-facing options are
+implemented by reflecting state at runtime. Limiting access is a secondary
+concern, mainly important for ensuring implementation details can change
+between versions.
+
+An object-oriented programmer learning FFmpeg should be careful not to fixate on
+FFmpeg's access control features, nor to overlook its reflection capabilities.
+Both are present, but have been given the level of focus appropriate for the task.
+
+## Example: modify text then print it
+
+The example below shows a context structure that receives input strings,
+modifies them in some context-dependant way, then prints them to a specified
+filehandle.
+
+```c
+/**
+ * Type information, accessible at runtime.
+ *
+ * Useful when configuring objects.
+ */
+enum ModifyThenPrintDialect {
+ MODIFY_THEN_PRINT_PLAIN_TEXT = 0,
+ MODIFY_THEN_PRINT_REGEX = 1,
+ MODIFY_THEN_PRINT_REGEX_PCRE = 2
+};
+
+/**
+ * User-facing information about types
+ *
+ * Useful for describing contexts to the user.
+ */
+static const char* ModifyThenPrintDialectName[] = {
+ "plain text",
+ "regular expression",
+ "Perl-compatible regular expression"
+};
+
+/**
+ * Context for functions that modify strings before printing them
+ */
+struct ModifyThenPrintContext {
+
+ /**
+ * Information about the type of this particular instance
+ *
+ * Object-oriented programs would probably represent this example
+ * as a sub-class, but some instance-specific functionality
+ * behaves more like a mixin.
+ */
+ enum ModifyThenPrintDialect dialect;
+
+ /**
+ * Internal context
+ *
+ * Object-oriented programs would put private members in here,
+ * but could also use it to store a virtual function table
+ * or other "invisible" information.
+ */
+ void* priv_data;
+
+ /**
+ * User-configurable options
+ *
+ * Best set through an API, but can be set directly if necessary
+ *
+ * Data from users needs to be validated before it's set, and the API
+ * might e.g. want to update some internal buffer when these change.
+ * Setting this directly is always less robust than using an API,
+ * but might be worthwhile if you're willing to spend the time checking
+ * for edge cases, and don't mind your code misbehaving if future
+ * versions change the API but not the structure.
+ *
+ * Object-oriented programs would likely make these protected members,
+ * initialised in a constructor and accessed with getters and setters.
+ * Making them user-configurable would be left to the programmer.
+ */
+ char *replace_this;
+ char *with_this;
+
+ /**
+ * Programmer-configurable variable
+ *
+ * Object-oriented programs would represent this as a public member.
+ */
+ FILE *out;
+
+};
+
+/**
+ * Allocate and initialize a ModifyThenPrintContext
+ *
+ * This creates a new pointer, then fills in some sensible defaults.
+ *
+ * We can reasonably assume this function will initialise `priv_data`
+ * with a dialect-specific object, but shouldn't make any assumptions
+ * about what that object is.
+ *
+ * Object-oriented programs would likely represent this as an
+ * allocator function and a constructor.
+ */
+int ModifyThenPrintContext_alloc_context(struct ModifyThenPrintContext **ctx,
+ enum ModifyThenPrintDialect dialect,
+ FILE *out);
+
+/**
+ * Uninitialize and deallocate a ModifyThenPrintContext
+ *
+ * This does any work required by the internal context (e.g. deallocating
+ * `priv_data`), then deallocates the main context itself.
+ *
+ * Object-oriented programs would likely represent this as a
+ * destructor and a deallocator.
+ */
+int ModifyThenPrintContext_free(struct ModifyThenPrintContext *ctx);
+
+/**
+ * Configure a ModifyThenPrintContext
+ *
+ * This checks the arguments are valid in the context's dialect,
+ * then updates the options as necessary
+ *
+ * Object-oriented programs would likely represent this as a
+ * collection of setter functions.
+ */
+int ModifyThenPrintContext_configure(struct ModifyThenPrintContext *ctx,
+ char* replace_this,
+ char* with_this);
+
+/**
+ * Print the contents of a ModifyThenPrintContext to a filehandle
+ *
+ * Provides human-readable information about keys and values.
+ *
+ * Object-oriented programs would likely represent this with some kind of
+ * `serialise` operation.
+ */
+int ModifyThenPrintContext_dump(struct ModifyThenPrintContext **ctx,
+ FILE *dump_fh);
+
+/**
+ * Print a single message
+ *
+ * Object-oriented programs would likely represent this with a member function.
+ */
+int ModifyThenPrintContext_print(struct ModifyThenPrintContext *ctx,
+ char *msg);
+
+/**
+ * How this context might be used in practice
+ */
+int print_hello_world()
+{
+
+ int ret = 0;
+
+ struct ModifyThenPrintContext *ctx;
+
+ if ( ModifyThenPrintContext_alloc_context( &ctx, MODIFY_THEN_PRINT_REGEX, stdout ) < 0 ) {
+ ret = -1;
+ goto EXIT_WITHOUT_CLEANUP;
+ }
+
+ if ( ModifyThenPrintContext_configure(ctx, "Hi|Hullo", "Hello") < 0 ) {
+ ret = -1;
+ goto FINISH;
+ }
+
+ if ( ModifyThenPrintContext_print( ctx, "Hi, world!\n" ) < 0 ) {
+ ret = -1;
+ goto FINISH;
+ }
+
+ if ( ModifyThenPrintContext_print( ctx, "Hullo, world!\n" ) < 0 ) {
+ ret = -1;
+ goto FINISH;
+ }
+
+ FINISH:
+ if ( ModifyThenPrintContext_free( ctx ) ) {
+ ret = -1;
+ goto EXIT_WITHOUT_CLEANUP;
+ }
+
+ EXIT_WITHOUT_CLEANUP:
+ return ret;
+
+}
+```
+
+## FFmpeg context structures
+
+The example above is a generic example of a context structure and its
+associated functions. Some FFmpeg contexts are no more complex than
+that example, just as some objects are just key/value stores with some
+functions attached. But here are some examples to show the variety of
+contexts available in FFmpeg.
+
+AVHashContext presents a generic API for hashing data. @ref hash.h
+"Its associated functions" show how to create, use and destroy a hash.
+The exact algorithm is specified by passing a string to av_hash_alloc(),
+and the list of strings can be retrieved from av_hash_names().
+Algorithm-specific internal context is stored in AVHashContext::ctx.
+
+AVCodecContext is a complex member representing data about an encoding or
+decoding session. @ref avcodec.h "Its associated functions" provide an
+abstract interface to encode and decode data. Like most widely-used contexts,
+its first member is an AVClass pointer containing instance-specific information.
+That means it's an *AVClass context structure* (discussed in more detail below).
+
+X264Context contains the internal context for an AVCodecContext that uses
+the x264 library. @ref libx264.c "Its associated functions" provide a concrete
+implementation for interacting with libx264. This class is not directly
+accessible through FFmpeg's public interface, so unlike AVCodecContext it can
+change significantly between releases.
+
+## Reflection with AVClass and AVOptions
+
+An *AVClass context structure* is a context whose first member is an AVClass
+that reflects its contents. An *@ref avoptions "AVOptions"-enabled struct*
+is a structure which reflects its contents using the @ref avoptions "AVOptions"
+API. These terms have become synonymous in modern usage, but you might notice
+some distinction when looking at code written after AVClass was developed but
+before @ref avoptions "AVOptions" was added.
+
+At first glance, an object-oriented programmer might be tempted to look at AVClass
+as a base class that contexts inherit from. But unlike a base class, an AVClass
+doesn't imply any theoretical relationship between objects, and contexts of the
+same type will often have different AVClass values. It's even theoretically possible
+for a single AVClass to be shared between contexts of different types. A better
+analogy would be to [C++ concepts](https://en.wikipedia.org/wiki/Concepts_(C%2B%2B))
+or [Java interfaces](https://en.wikipedia.org/wiki/Interface_(Java)).
+
+To understand how AVClass and @ref avoptions "AVOptions" work,
+consider the requirements for a `libx264` encoder:
+
+- it has to support common encoder options like "bitrate"
+- it has to support encoder-specific options like "profile"
+ - the exact options could change quickly if a legal ruling forces a change of backend
+- it has to provide useful feedback to users about unsupported options
+
+Common encoder options like "bitrate" need to be stored in AVCodecContext itself
+to avoid duplicating code, while encoder-specific options like "profile" have to
+be stored in the X264Context instance stored in AVCodecContext::priv_data.
+But both need to be presented to users (along with help text, default values etc.)
+in a way that makes it easy to build user interfaces to get and set those options.
+
+A context's AVClass member contains a list of AVOption objects, describing
+the user-configurable members of the class. It also contains functions to
+iterate through a tree of AVClass objects representing internal context either
+for the current object or for any class that could potentially exist in the
+current version of FFmpeg.
+
+The @ref avoptions "AVOptions" API accepts any AVClass context structure,
+looks through its AVOption data, and uses that to examine, introspect, and modify
+the structure. Because the API doesn't contain any type-specific information,
+it can be used to create a general user interface that adapts automatically
+when e.g. a new version of FFmpeg adds a new configuration option.
+
+## Summary
+
+FFmpeg uses "contexts" in ways that are often resemble object-oriented programming.
+But it focuses less on encapsulation within arbitrarily complex systems,
+and more on providing reflectivity to make pleasant user interfaces.
--
2.43.0
_______________________________________________
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:[~2024-04-22 15:59 UTC|newest]
Thread overview: 84+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-04-18 15:06 [FFmpeg-devel] [PATCH " Andrew Sayers
2024-04-18 15:06 ` [FFmpeg-devel] [PATCH 2/3] lavu: Clarify relationship between AVClass, AVOption and context Andrew Sayers
2024-04-18 15:06 ` [FFmpeg-devel] [PATCH 3/3] all: Link to "context" from all contexts with documentation Andrew Sayers
2024-04-20 7:25 ` [FFmpeg-devel] [PATCH 1/3] doc: Explain what "context" means Stefano Sabatini
2024-04-20 12:18 ` Andrew Sayers
2024-04-20 16:13 ` Stefano Sabatini
2024-04-20 12:19 ` [FFmpeg-devel] [PATCH v2 " Andrew Sayers
2024-04-20 12:19 ` [FFmpeg-devel] [PATCH v2 2/3] lavu: Clarify relationship between AVClass, AVOption and context Andrew Sayers
2024-04-20 12:19 ` [FFmpeg-devel] [PATCH v2 3/3] all: Link to "context" from all contexts with documentation Andrew Sayers
2024-04-20 16:48 ` [FFmpeg-devel] [PATCH v2 1/3] doc: Explain what "context" means Stefano Sabatini
2024-04-20 22:17 ` Andrew Sayers
2024-04-22 8:02 ` Stefano Sabatini
2024-04-22 15:56 ` [FFmpeg-devel] [PATCH v3 0/3] all: Link to "context" from all contexts with documentation Andrew Sayers
2024-04-22 15:56 ` Andrew Sayers [this message]
2024-04-22 17:05 ` [FFmpeg-devel] [PATCH v3 1/3] doc: Explain what "context" means Stefano Sabatini
2024-04-29 9:10 ` Andrew Sayers
2024-05-02 10:03 ` Andrew Sayers
2024-05-05 7:29 ` Stefano Sabatini
2024-05-05 21:04 ` Andrew Sayers
2024-05-22 10:37 ` Stefano Sabatini
2024-05-22 12:47 ` Andrew Sayers
2024-05-25 9:00 ` Stefano Sabatini
2024-04-29 9:24 ` [FFmpeg-devel] [PATCH v4 1/4] " Andrew Sayers
2024-04-29 9:24 ` [FFmpeg-devel] [PATCH v4 2/4] lavu: Clarify relationship between AVClass, AVOption and context Andrew Sayers
2024-04-29 9:24 ` [FFmpeg-devel] [PATCH v4 3/4] all: Link to "context" from all contexts with documentation Andrew Sayers
2024-05-02 11:01 ` Lynne
2024-05-02 11:14 ` Andrew Sayers
2024-05-02 13:00 ` Zhao Zhili
2024-05-02 13:27 ` Andrew Sayers
2024-05-02 13:39 ` Zhao Zhili
2024-04-29 9:24 ` [FFmpeg-devel] [PATCH v4 4/4] lavf: Add documentation for private "Context" classes Andrew Sayers
2024-05-05 8:31 ` [FFmpeg-devel] [PATCH v4 1/4] doc: Explain what "context" means Andreas Rheinhardt
2024-05-05 10:34 ` Andrew Sayers
2024-04-22 15:56 ` [FFmpeg-devel] [PATCH v3 2/3] lavu: Clarify relationship between AVClass, AVOption and context Andrew Sayers
2024-04-22 15:56 ` [FFmpeg-devel] [PATCH v3 3/3] all: Link to "context" from all contexts with documentation Andrew Sayers
2024-05-15 15:54 ` [FFmpeg-devel] [PATCH v4 0/4] Explain what "context" means Andrew Sayers
2024-05-15 15:54 ` [FFmpeg-devel] [PATCH v4 1/4] doc: " Andrew Sayers
2024-05-22 9:31 ` Stefano Sabatini
2024-05-22 16:07 ` Andrew Sayers
2024-05-25 9:49 ` Stefano Sabatini
2024-05-26 12:06 ` Andrew Sayers
2024-05-28 17:24 ` Stefano Sabatini
2024-05-29 10:10 ` Andrew Sayers
2024-05-29 10:50 ` Andrew Sayers
2024-05-29 11:06 ` Paul B Mahol
2024-05-29 14:18 ` Andrew Sayers
2024-05-29 16:06 ` Stefano Sabatini
2024-05-23 20:00 ` [FFmpeg-devel] [PATCH v5 0/4] " Andrew Sayers
2024-05-23 20:00 ` [FFmpeg-devel] [PATCH v5 1/4] doc: " Andrew Sayers
2024-05-25 11:00 ` Stefano Sabatini
2024-05-23 20:00 ` [FFmpeg-devel] [PATCH v5 2/4] lavu: Clarify relationship between AVClass, AVOption and context Andrew Sayers
2024-05-25 9:57 ` Stefano Sabatini
2024-05-23 20:00 ` [FFmpeg-devel] [PATCH v5 3/4] all: Link to "context" from all public contexts with documentation Andrew Sayers
2024-05-23 20:00 ` [FFmpeg-devel] [PATCH v5 4/4] all: Rewrite documentation for contexts Andrew Sayers
2024-05-24 1:50 ` [FFmpeg-devel] [PATCH v5 0/4] Explain what "context" means Michael Niedermayer
2024-05-24 9:43 ` Andrew Sayers
2024-05-15 15:54 ` [FFmpeg-devel] [PATCH v4 2/4] lavu: Clarify relationship between AVClass, AVOption and context Andrew Sayers
2024-05-22 10:04 ` Stefano Sabatini
2024-05-15 15:54 ` [FFmpeg-devel] [PATCH v4 3/4] all: Link to "context" from all contexts with documentation Andrew Sayers
2024-05-15 16:46 ` Lynne via ffmpeg-devel
2024-05-16 11:25 ` Andrew Sayers
2024-05-15 15:54 ` [FFmpeg-devel] [PATCH v4 4/4] lavf: Add documentation for private "Context" classes Andrew Sayers
2024-05-22 10:08 ` Stefano Sabatini
2024-05-22 14:47 ` Andrew Sayers
2024-05-22 15:24 ` Andreas Rheinhardt
2024-05-22 16:54 ` Andrew Sayers
2024-06-04 14:47 ` [FFmpeg-devel] [PATCH v6 0/4] doc: Explain what "context" means Andrew Sayers
2024-06-04 14:47 ` [FFmpeg-devel] [PATCH v6 1/4] " Andrew Sayers
2024-06-05 8:15 ` Anton Khirnov
2024-06-12 20:52 ` Stefano Sabatini
2024-06-13 14:20 ` Andrew Sayers
2024-06-15 9:17 ` Stefano Sabatini
2024-06-16 18:02 ` [FFmpeg-devel] Development process for explaining contexts (was Re: [PATCH v6 1/4] doc: Explain what "context" means) Andrew Sayers
2024-06-16 21:20 ` Paul B Mahol
2024-07-01 22:16 ` Stefano Sabatini
2024-07-02 9:56 ` Andrew Sayers
2024-07-06 11:33 ` Stefano Sabatini
2024-06-04 14:47 ` [FFmpeg-devel] [PATCH v6 2/4] lavu: Clarify relationship between AVClass, AVOption and context Andrew Sayers
2024-06-05 10:34 ` Stefano Sabatini
2024-06-05 12:46 ` Andrew Sayers
2024-06-04 14:47 ` [FFmpeg-devel] [PATCH v6 3/4] all: Link to "context" from all public contexts with documentation Andrew Sayers
2024-06-05 8:12 ` Anton Khirnov
2024-06-05 12:51 ` Andrew Sayers
2024-06-04 14:47 ` [FFmpeg-devel] [PATCH v6 4/4] all: Rewrite documentation for contexts Andrew Sayers
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=20240422155836.385333-2-ffmpeg-devel@pileofstuff.org \
--to=ffmpeg-devel@pileofstuff.org \
--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 http://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/ http://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