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 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