Based largely on the explanation by Stefano Sabatini: https://ffmpeg.org/pipermail/ffmpeg-devel/2024-April/325854.html --- doc/jargon.md | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 doc/jargon.md
diff --git a/doc/jargon.md b/doc/jargon.md new file mode 100644 index 0000000000..f967b5c8bc --- /dev/null +++ b/doc/jargon.md @@ -0,0 +1,169 @@ +# Jargon + +Terms used throughout the code that developers may need to know. + +@anchor context + +## Context + +A design pattern that stores the context (e.g. configuration) for a series +of operations in a "context" structure, and moves other information with +a longer or shorter lifetime elsewhere. + +Consider a code snippet to modify text then print it: + +```c +/** + * Contextual information about printing a series of messages + */ +struct ModifyThenPrintContext { + + /** + * Members of the context usually are usually part of its public API... + */ + FILE *out; + + /** + * ... but check the documentation just in case + */ + [[deprecated]] + int no_longer_part_of_the_public_api; + + /** + * The "internal context" is private to the context itself. + * + * Unlike the members above, the private context is not guaranteed + * and can change arbitrarily between versions. + */ + void* priv_data; +}; + +/** + * Long-lifetime information, reused by many contexts + */ +enum ModifyThenPrintDialect { + MODIFY_THEN_PRINT_PLAIN_TEXT, + MODIFY_THEN_PRINT_REGEX, + MODIFY_THEN_PRINT_REGEX_PCRE +}; + +/** + * Short-lifetime information, used repeatedly in a single context + */ +struct ModifyThenPrintMessage { + char *str; + char *replace_this; + char *with_this; +}; + +/** + * 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. + * + */ +int ModifyThenPrintContext_alloc_context(struct ModifyThenPrintContext **ctx, + FILE *out, + enum ModifyThenPrintDialect dialect); + +/** + * Uninitialize and deallocate a ModifyThenPrintContext + * + * This does any work required by the private context in `priv_data` + * (e.g. deallocating it), then deallocates the main context itself. + * + */ +int ModifyThenPrintContext_free(struct ModifyThenPrintContext *ctx); + +/** + * Print a single message + */ +int ModifyThenPrintContext_print(struct ModifyThenPrintContext *ctx, + struct ModifyThenPrintMessage *msg); + +int print_hello_world() +{ + + int ret = 0; + + struct ModifyThenPrintContext *ctx; + + struct ModifyThenPrintMessage hello_world; + + if ( ModifyThenPrintContext_alloc_context( &ctx, stdout, MODIFY_THEN_PRINT_REGEX ) < 0 ) { + ret = -1; + goto EXIT_WITHOUT_CLEANUP; + } + + hello_world.replace_this = "Hi|Hullo"; + hello_world.with_this = "Hello"; + + hello_world.str = "Hi, world!\n"; + if ( ModifyThenPrintContext_print( ctx, &hello_world ) < 0 ) { + ret = -1; + goto FINISH; + } + + hello_world.str = "Hullo, world!\n"; + if ( ModifyThenPrintContext_print( ctx, &hello_world ) < 0 ) { + ret = -1; + goto FINISH; + } + + FINISH: + if ( ModifyThenPrintContext_free( ctx ) ) { + ret = -1; + goto EXIT_WITHOUT_CLEANUP; + } + + EXIT_WITHOUT_CLEANUP: + return ret; + +} +``` + +In the example above, the `ModifyThenPrintContext` object contains information +that's needed for exactly the lifetime of the current job (i.e. how to modify +and where to print). Information with a longer or shorter lifetime is moved +to `ModifyThenPrintDialect` and `ModifyThenPrintMessage`. + +FFmpeg uses the context pattern to solve a variety of problems. But the most +common contexts (AVCodecContext, AVFormatContext etc.) tend to have a lot of +requirements in common: + +- need to query, set and get options + - including options whose implementation is not part of the public API +- need to configure log message verbosity and content + +FFmpeg gradually converged on the AVClass struct to store that information, +then converged on the @ref avoptions "AVOptions" system to manipulate it. +So the terms "context", "AVClass context structure" and "AVOptions-enabled +struct" are often used interchangeably when it's not important to emphasise +the difference. But for example, AVMediaCodecContext uses the context +pattern, but is not an AVClass context structure, so cannot be manipulated +with AVOptions. + +To understand AVClass context structures, consider the `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 about unsupported options + +Common encoder options like "bitrate" are stored in the AVCodecContext class, +while encoder-specific options like "profile" are stored in an X264Context +instance in AVCodecContext::priv_data. These options are then exposed through +a tree of AVOption objects, which include user-visible help text and +machine-readable information about the memory location to read/write +each option. Common @ref avoptions "AVOptions" functionality lets end users +get and set those values, and provides readable feedback about errors. But +even though they can be manipulated through an API, the X264Context class is +private and new releases can modify it without affecting the public interface. + +FFmpeg itself uses the context design pattern to solve many problems. +You can use this pattern anywhere it would be useful, and may want to use +AVClass and @ref avoptions "AVOptions" if they're relevant to your situation. -- 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-requ...@ffmpeg.org with subject "unsubscribe".