Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: "Clément Bœsch" <u@pkh.me>
To: ffmpeg-devel@ffmpeg.org
Cc: "Clément Bœsch" <u@pkh.me>
Subject: [FFmpeg-devel] [PATCH v2 05/32] avfilter/paletteuse: switch from u8[4] to u32 for color code
Date: Wed, 28 Dec 2022 00:17:47 +0100
Message-ID: <20221227231814.2520181-6-u@pkh.me> (raw)
In-Reply-To: <20221227231814.2520181-1-u@pkh.me>

This change simplifies the code quite a bit and make it consistent with
how it's done in palettegen.
---
 libavfilter/vf_paletteuse.c | 98 ++++++++++++++++---------------------
 1 file changed, 41 insertions(+), 57 deletions(-)

diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c
index f9d8a1cdfc..fb4016b11c 100644
--- a/libavfilter/vf_paletteuse.c
+++ b/libavfilter/vf_paletteuse.c
@@ -57,7 +57,7 @@ enum diff_mode {
 };
 
 struct color_node {
-    uint8_t val[4];
+    uint32_t val;
     uint8_t palette_id;
     int split;
     int left_id, right_id;
@@ -162,9 +162,11 @@ static av_always_inline uint32_t dither_color(uint32_t px, int er, int eg,
          | av_clip_uint8((px       & 0xff) + ((eb * scale) / (1<<shift)));
 }
 
-static av_always_inline int diff(const uint8_t *c1, const uint8_t *c2, const int trans_thresh)
+static av_always_inline int diff(const uint32_t a, const uint32_t b, const int trans_thresh)
 {
     // XXX: try L*a*b with CIE76 (dL*dL + da*da + db*db)
+    const uint8_t c1[] = {a >> 24, a >> 16 & 0xff, a >> 8 & 0xff, a & 0xff};
+    const uint8_t c2[] = {b >> 24, b >> 16 & 0xff, b >> 8 & 0xff, b & 0xff};
     const int dr = c1[1] - c2[1];
     const int dg = c1[2] - c2[2];
     const int db = c1[3] - c2[3];
@@ -178,7 +180,7 @@ static av_always_inline int diff(const uint8_t *c1, const uint8_t *c2, const int
     }
 }
 
-static av_always_inline uint8_t colormap_nearest_bruteforce(const uint32_t *palette, const uint8_t *argb, const int trans_thresh)
+static av_always_inline uint8_t colormap_nearest_bruteforce(const uint32_t *palette, const uint32_t argb, const int trans_thresh)
 {
     int i, pal_id = -1, min_dist = INT_MAX;
 
@@ -186,13 +188,7 @@ static av_always_inline uint8_t colormap_nearest_bruteforce(const uint32_t *pale
         const uint32_t c = palette[i];
 
         if (c >> 24 >= trans_thresh) { // ignore transparent entry
-            const uint8_t palargb[] = {
-                palette[i]>>24,
-                palette[i]>>16 & 0xff,
-                palette[i]>> 8 & 0xff,
-                palette[i]     & 0xff,
-            };
-            const int d = diff(palargb, argb, trans_thresh);
+            const int d = diff(palette[i], argb, trans_thresh);
             if (d < min_dist) {
                 pal_id = i;
                 min_dist = d;
@@ -210,14 +206,14 @@ struct nearest_color {
 
 static void colormap_nearest_node(const struct color_node *map,
                                   const int node_pos,
-                                  const uint8_t *target,
+                                  const uint32_t target,
                                   const int trans_thresh,
                                   struct nearest_color *nearest)
 {
     const struct color_node *kd = map + node_pos;
-    const int s = kd->split;
+    const int shift = (3 - kd->split) * 8;
     int dx, nearer_kd_id, further_kd_id;
-    const uint8_t *current = kd->val;
+    const uint32_t current = kd->val;
     const int current_to_target = diff(target, current, trans_thresh);
 
     if (current_to_target < nearest->dist_sqd) {
@@ -226,7 +222,7 @@ static void colormap_nearest_node(const struct color_node *map,
     }
 
     if (kd->left_id != -1 || kd->right_id != -1) {
-        dx = target[s] - current[s];
+        dx = (int)(target>>shift & 0xff) - (int)(current>>shift & 0xff);
 
         if (dx <= 0) nearer_kd_id = kd->left_id,  further_kd_id = kd->right_id;
         else         nearer_kd_id = kd->right_id, further_kd_id = kd->left_id;
@@ -239,7 +235,7 @@ static void colormap_nearest_node(const struct color_node *map,
     }
 }
 
-static av_always_inline uint8_t colormap_nearest_recursive(const struct color_node *node, const uint8_t *rgb, const int trans_thresh)
+static av_always_inline uint8_t colormap_nearest_recursive(const struct color_node *node, const uint8_t rgb, const int trans_thresh)
 {
     struct nearest_color res = {.dist_sqd = INT_MAX, .node_pos = -1};
     colormap_nearest_node(node, 0, rgb, trans_thresh, &res);
@@ -251,7 +247,7 @@ struct stack_node {
     int dx2;
 };
 
-static av_always_inline uint8_t colormap_nearest_iterative(const struct color_node *root, const uint8_t *target, const int trans_thresh)
+static av_always_inline uint8_t colormap_nearest_iterative(const struct color_node *root, const uint32_t target, const int trans_thresh)
 {
     int pos = 0, best_node_id = -1, best_dist = INT_MAX, cur_color_id = 0;
     struct stack_node nodes[16];
@@ -260,7 +256,7 @@ static av_always_inline uint8_t colormap_nearest_iterative(const struct color_no
     for (;;) {
 
         const struct color_node *kd = &root[cur_color_id];
-        const uint8_t *current = kd->val;
+        const uint32_t current = kd->val;
         const int current_to_target = diff(target, current, trans_thresh);
 
         /* Compare current color node to the target and update our best node if
@@ -274,8 +270,8 @@ static av_always_inline uint8_t colormap_nearest_iterative(const struct color_no
 
         /* Check if it's not a leaf */
         if (kd->left_id != -1 || kd->right_id != -1) {
-            const int split = kd->split;
-            const int dx = target[split] - current[split];
+            const int shift = (3 - kd->split) * 8;
+            const int dx = (target>>shift & 0xff) - (current>>shift & 0xff);
             int nearer_kd_id, further_kd_id;
 
             /* Define which side is the most interesting. */
@@ -331,24 +327,20 @@ end:
 /**
  * Check if the requested color is in the cache already. If not, find it in the
  * color tree and cache it.
- * Note: a, r, g, and b are the components of color, but are passed as well to avoid
- * recomputing them (they are generally computed by the caller for other uses).
  */
 static av_always_inline int color_get(PaletteUseContext *s, uint32_t color,
-                                      uint8_t a, uint8_t r, uint8_t g, uint8_t b,
                                       const enum color_search_method search_method)
 {
     int i;
-    const uint8_t argb_elts[] = {a, r, g, b};
-    const uint8_t rhash = r & ((1<<NBITS)-1);
-    const uint8_t ghash = g & ((1<<NBITS)-1);
-    const uint8_t bhash = b & ((1<<NBITS)-1);
+    const uint8_t rhash = (color>>16) & ((1<<NBITS)-1);
+    const uint8_t ghash = (color>> 8) & ((1<<NBITS)-1);
+    const uint8_t bhash =  color      & ((1<<NBITS)-1);
     const unsigned hash = rhash<<(NBITS*2) | ghash<<NBITS | bhash;
     struct cache_node *node = &s->cache[hash];
     struct cached_color *e;
 
     // first, check for transparency
-    if (a < s->trans_thresh && s->transparency_index >= 0) {
+    if (color>>24 < s->trans_thresh && s->transparency_index >= 0) {
         return s->transparency_index;
     }
 
@@ -363,7 +355,7 @@ static av_always_inline int color_get(PaletteUseContext *s, uint32_t color,
     if (!e)
         return AVERROR(ENOMEM);
     e->color = color;
-    e->pal_entry = COLORMAP_NEAREST(search_method, s->palette, s->map, argb_elts, s->trans_thresh);
+    e->pal_entry = COLORMAP_NEAREST(search_method, s->palette, s->map, color, s->trans_thresh);
 
     return e->pal_entry;
 }
@@ -372,12 +364,11 @@ static av_always_inline int get_dst_color_err(PaletteUseContext *s,
                                               uint32_t c, int *er, int *eg, int *eb,
                                               const enum color_search_method search_method)
 {
-    const uint8_t a = c >> 24;
     const uint8_t r = c >> 16 & 0xff;
     const uint8_t g = c >>  8 & 0xff;
     const uint8_t b = c       & 0xff;
     uint32_t dstc;
-    const int dstx = color_get(s, c, a, r, g, b, search_method);
+    const int dstx = color_get(s, c, search_method);
     if (dstx < 0)
         return dstx;
     dstc = s->palette[dstx];
@@ -419,7 +410,7 @@ static av_always_inline int set_frame(PaletteUseContext *s, AVFrame *out, AVFram
                 const uint8_t g = av_clip_uint8(g8 + d);
                 const uint8_t b = av_clip_uint8(b8 + d);
                 const uint32_t color_new = (unsigned)(a8) << 24 | r << 16 | g << 8 | b;
-                const int color = color_get(s, color_new, a8, r, g, b, search_method);
+                const int color = color_get(s, color_new, search_method);
 
                 if (color < 0)
                     return color;
@@ -483,11 +474,7 @@ static av_always_inline int set_frame(PaletteUseContext *s, AVFrame *out, AVFram
                 if (         down) src[src_linesize + x    ] = dither_color(src[src_linesize + x    ], er, eg, eb, 1, 2);
 
             } else {
-                const uint8_t a = src[x] >> 24;
-                const uint8_t r = src[x] >> 16 & 0xff;
-                const uint8_t g = src[x] >>  8 & 0xff;
-                const uint8_t b = src[x]       & 0xff;
-                const int color = color_get(s, src[x], a, r, g, b, search_method);
+                const int color = color_get(s, src[x], search_method);
 
                 if (color < 0)
                     return color;
@@ -507,20 +494,20 @@ static void disp_node(AVBPrint *buf,
                       int depth)
 {
     const struct color_node *node = &map[node_id];
-    const uint32_t fontcolor = node->val[1] > 0x50 &&
-                               node->val[2] > 0x50 &&
-                               node->val[3] > 0x50 ? 0 : 0xffffff;
+    const uint32_t fontcolor = (node->val>>16 & 0xff) > 0x50 &&
+                               (node->val>> 8 & 0xff) > 0x50 &&
+                               (node->val     & 0xff) > 0x50 ? 0 : 0xffffff;
     const int rgb_comp = node->split - 1;
     av_bprintf(buf, "%*cnode%d ["
                "label=\"%c%02X%c%02X%c%02X%c\" "
-               "fillcolor=\"#%02x%02x%02x\" "
+               "fillcolor=\"#%06"PRIX32"\" "
                "fontcolor=\"#%06"PRIX32"\"]\n",
                depth*INDENT, ' ', node->palette_id,
-               "[  "[rgb_comp], node->val[1],
-               "][ "[rgb_comp], node->val[2],
-               " ]["[rgb_comp], node->val[3],
+               "[  "[rgb_comp], node->val>>16 & 0xff,
+               "][ "[rgb_comp], node->val>> 8 & 0xff,
+               " ]["[rgb_comp], node->val     & 0xff,
                "  ]"[rgb_comp],
-               node->val[1], node->val[2], node->val[3],
+               node->val & 0xffffff,
                fontcolor);
     if (parent_id != -1)
         av_bprintf(buf, "%*cnode%d -> node%d\n", depth*INDENT, ' ',
@@ -563,16 +550,14 @@ static int debug_accuracy(const struct color_node *node, const uint32_t *palette
     for (r = 0; r < 256; r++) {
         for (g = 0; g < 256; g++) {
             for (b = 0; b < 256; b++) {
-                const uint8_t argb[] = {0xff, r, g, b};
+                const uint32_t argb = 0xff000000 | r<<16 | g<<8 | b;
                 const int r1 = COLORMAP_NEAREST(search_method, palette, node, argb, trans_thresh);
                 const int r2 = colormap_nearest_bruteforce(palette, argb, trans_thresh);
                 if (r1 != r2) {
                     const uint32_t c1 = palette[r1];
                     const uint32_t c2 = palette[r2];
-                    const uint8_t palargb1[] = { 0xff, c1>>16 & 0xff, c1>> 8 & 0xff, c1 & 0xff };
-                    const uint8_t palargb2[] = { 0xff, c2>>16 & 0xff, c2>> 8 & 0xff, c2 & 0xff };
-                    const int d1 = diff(palargb1, argb, trans_thresh);
-                    const int d2 = diff(palargb2, argb, trans_thresh);
+                    const int d1 = diff(0xff000000 | c1, argb, trans_thresh);
+                    const int d2 = diff(0xff000000 | c2, argb, trans_thresh);
                     if (d1 != d2) {
                         av_log(NULL, AV_LOG_ERROR,
                                "/!\\ %02X%02X%02X: %d ! %d (%06"PRIX32" ! %06"PRIX32") / dist: %d ! %d\n",
@@ -686,6 +671,7 @@ static int colormap_insert(struct color_node *map,
 {
     uint32_t c;
     int component, cur_id;
+    uint8_t comp_value;
     int node_left_id = -1, node_right_id = -1;
     struct color_node *node;
     struct color_rect box1, box2;
@@ -700,17 +686,15 @@ static int colormap_insert(struct color_node *map,
     node = &map[cur_id];
     node->split = component;
     node->palette_id = pal_id;
-    node->val[0] = c>>24;
-    node->val[1] = c>>16 & 0xff;
-    node->val[2] = c>> 8 & 0xff;
-    node->val[3] = c     & 0xff;
+    node->val = c;
 
     color_used[pal_id] = 1;
 
     /* get the two boxes this node creates */
     box1 = box2 = *box;
-    box1.max[component-1] = node->val[component];
-    box2.min[component-1] = FFMIN(node->val[component] + 1, 255);
+    comp_value = node->val >> ((3 - component) * 8) & 0xff;
+    box1.max[component-1] = comp_value;
+    box2.min[component-1] = FFMIN(comp_value + 1, 255);
 
     node_left_id = colormap_insert(map, color_used, nb_used, palette, trans_thresh, &box1);
 
@@ -787,8 +771,8 @@ static void debug_mean_error(PaletteUseContext *s, const AVFrame *in1,
         for (x = 0; x < in1->width; x++) {
             const uint32_t c1 = src1[x];
             const uint32_t c2 = palette[src2[x]];
-            const uint8_t argb1[] = {0xff, c1 >> 16 & 0xff, c1 >> 8 & 0xff, c1 & 0xff};
-            const uint8_t argb2[] = {0xff, c2 >> 16 & 0xff, c2 >> 8 & 0xff, c2 & 0xff};
+            const uint32_t argb1 = 0xff000000 | c1;
+            const uint32_t argb2 = 0xff000000 | c2;
             mean_err += diff(argb1, argb2, s->trans_thresh);
         }
         src1 += src1_linesize;
-- 
2.39.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".

  parent reply	other threads:[~2022-12-27 23:19 UTC|newest]

Thread overview: 75+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-11-05 15:26 [FFmpeg-devel] Rework color quantization in palette{gen,use} Clément Bœsch
2022-11-05 15:26 ` [FFmpeg-devel] [PATCH 01/15] Revert "avfilter/vf_palette(gen|use): support palettes with alpha" Clément Bœsch
2022-11-05 15:26 ` [FFmpeg-devel] [PATCH 02/15] avfilter: add palette utils Clément Bœsch
2022-11-05 15:26 ` [FFmpeg-devel] [PATCH 03/15] avfilter/palette{use, gen}: simplify a few alpha masks Clément Bœsch
2022-11-05 15:26 ` [FFmpeg-devel] [PATCH 04/15] avfilter/paletteuse: switch from u8[4] to u32 for color code Clément Bœsch
2022-11-05 15:26 ` [FFmpeg-devel] [PATCH 05/15] avfilter/paletteuse: name target color arg consistently in colormap functions Clément Bœsch
2022-11-05 15:26 ` [FFmpeg-devel] [PATCH 06/15] avfilter/paletteuse: remove unused alpha split dimension Clément Bœsch
2022-11-05 15:26 ` [FFmpeg-devel] [PATCH 07/15] avfilter/paletteuse: remove redundant alpha condition Clément Bœsch
2022-11-05 15:26 ` [FFmpeg-devel] [PATCH 08/15] avfilter/paletteuse: switch to a perceptual model Clément Bœsch
2022-11-05 15:26 ` [FFmpeg-devel] [PATCH 09/15] avfilter/palettegen: average color in linear space Clément Bœsch
2022-11-05 15:39   ` Paul B Mahol
2022-11-05 18:50     ` Clément Bœsch
2022-11-05 15:26 ` [FFmpeg-devel] [PATCH 10/15] avfilter/palettegen: move box variance computation in a dedicated function Clément Bœsch
2022-11-05 15:26 ` [FFmpeg-devel] [PATCH 11/15] avfilter/palettegen: comment on the unnormalized variance Clément Bœsch
2022-11-05 15:26 ` [FFmpeg-devel] [PATCH 12/15] avfilter/palettegen: base split decision on a perceptual model Clément Bœsch
2022-11-05 19:07   ` Andreas Rheinhardt
2022-11-08 21:09     ` Clément Bœsch
2022-12-27 23:20     ` Clément Bœsch
2022-11-05 15:26 ` [FFmpeg-devel] [PATCH 13/15] avfilter/palettegen: use variance per-axis instead of the range Clément Bœsch
2022-11-05 15:26 ` [FFmpeg-devel] [PATCH 14/15] avfilter/palettegen: rename longest to split_axis Clément Bœsch
2022-11-05 15:26 ` [FFmpeg-devel] [PATCH 15/15] avfilter/palette{use, gen}: update Copyright after recent changes Clément Bœsch
2022-11-05 15:44 ` [FFmpeg-devel] Rework color quantization in palette{gen,use} Paul B Mahol
2022-11-05 18:54   ` Clément Bœsch
2022-11-06 13:19     ` Ronald S. Bultje
2022-11-08 21:22       ` Clément Bœsch
2022-11-05 21:52 ` Soft Works
2022-11-06 17:09 ` Michael Niedermayer
2022-11-06 17:30   ` Michael Niedermayer
2022-11-08 21:14     ` Clément Bœsch
2022-12-31 12:11     ` Clément Bœsch
2023-01-02 21:57       ` Michael Niedermayer
2023-01-02 23:05         ` Clément Bœsch
2023-01-03 18:50           ` Michael Niedermayer
2022-11-06 19:46 ` Soft Works
2022-11-08 21:07   ` Clément Bœsch
2022-11-08 22:37     ` Soft Works
2022-12-27 23:31       ` Clément Bœsch
2022-12-27 23:17 ` [FFmpeg-devel] New iteration for the color quantization in palette{gen, use} Clément Bœsch
2022-12-27 23:17   ` [FFmpeg-devel] [PATCH v2 01/32] avfilter/palettegen: allow a minimum of 2 colors Clément Bœsch
2022-12-28 21:04     ` Tomas Härdin
2022-12-28 21:23       ` Clément Bœsch
2023-01-03 18:59         ` Tomas Härdin
2022-12-27 23:17   ` [FFmpeg-devel] [PATCH v2 02/32] avfilter/palette{gen, use}: revert support palettes with alpha Clément Bœsch
2023-01-03 19:11     ` Paul B Mahol
2022-12-27 23:17   ` [FFmpeg-devel] [PATCH v2 03/32] avfilter/palette{gen, use}: simplify a few alpha masks Clément Bœsch
2022-12-27 23:17   ` [FFmpeg-devel] [PATCH v2 04/32] avfilter/palette{gen, use}: add palette utils Clément Bœsch
2022-12-27 23:17   ` Clément Bœsch [this message]
2022-12-27 23:17   ` [FFmpeg-devel] [PATCH v2 06/32] avfilter/paletteuse: name target color arg consistently in colormap functions Clément Bœsch
2022-12-27 23:17   ` [FFmpeg-devel] [PATCH v2 07/32] avfilter/paletteuse: remove unused alpha split dimension Clément Bœsch
2022-12-27 23:17   ` [FFmpeg-devel] [PATCH v2 08/32] avfilter/paletteuse: remove redundant alpha condition Clément Bœsch
2022-12-27 23:17   ` [FFmpeg-devel] [PATCH v2 09/32] avfilter/paletteuse: switch to a perceptual model Clément Bœsch
2022-12-27 23:17   ` [FFmpeg-devel] [PATCH v2 10/32] avfilter/palettegen: move box stats computation to a dedicated function Clément Bœsch
2022-12-27 23:17   ` [FFmpeg-devel] [PATCH v2 11/32] avfilter/palettegen: define the best axis to cut using the squared error Clément Bœsch
2022-12-27 23:17   ` [FFmpeg-devel] [PATCH v2 12/32] avfilter/palettegen: use box->major_axis without intermediate variable Clément Bœsch
2022-12-27 23:17   ` [FFmpeg-devel] [PATCH v2 13/32] avfilter/palettegen: always compute the box variance Clément Bœsch
2022-12-27 23:17   ` [FFmpeg-devel] [PATCH v2 14/32] avfilter/palettegen: rename variance to cut_score Clément Bœsch
2022-12-27 23:17   ` [FFmpeg-devel] [PATCH v2 15/32] avfilter/palettegen: change cut score from ∑e² to max e² Clément Bœsch
2022-12-27 23:17   ` [FFmpeg-devel] [PATCH v2 16/32] avfilter/palettegen: compute average color within compute_box_stats() Clément Bœsch
2022-12-27 23:17   ` [FFmpeg-devel] [PATCH v2 17/32] avfilter/palettegen: misc cosmetics Clément Bœsch
2022-12-27 23:18   ` [FFmpeg-devel] [PATCH v2 18/32] avfilter/palettegen: rename local variable box_weight to weight Clément Bœsch
2022-12-27 23:18   ` [FFmpeg-devel] [PATCH v2 19/32] avfilter/palettegen: switch to signed arithmetic Clément Bœsch
2022-12-27 23:18   ` [FFmpeg-devel] [PATCH v2 20/32] avfilter/palettegen: base box split decision on a perceptual model Clément Bœsch
2022-12-27 23:18   ` [FFmpeg-devel] [PATCH v2 21/32] avfilter/palettegen: add a warning about supporting only sRGB Clément Bœsch
2022-12-27 23:18   ` [FFmpeg-devel] [PATCH v2 22/32] avfilter/palettegen: make refs order deterministic Clément Bœsch
2022-12-27 23:18   ` [FFmpeg-devel] [PATCH v2 23/32] avfilter/palettegen: use libc qsort Clément Bœsch
2022-12-27 23:18   ` [FFmpeg-devel] [PATCH v2 24/32] avfilter/palette{gen, use}: update Copyright after recent changes Clément Bœsch
2022-12-27 23:18   ` [FFmpeg-devel] [PATCH v2 25/32] avfilter/palette: add lowbias32 hashing Clément Bœsch
2022-12-27 23:18   ` [FFmpeg-devel] [PATCH v2 26/32] avfilter/palettegen: use lowbias32 for color hashing Clément Bœsch
2022-12-27 23:18   ` [FFmpeg-devel] [PATCH v2 27/32] avfilter/paletteuse: " Clément Bœsch
2022-12-27 23:18   ` [FFmpeg-devel] [PATCH v2 28/32] avfilter/paletteuse: switch to recursive method Clément Bœsch
2022-12-27 23:18   ` [FFmpeg-devel] [PATCH v2 29/32] avfilter/paletteuse: remove alternative search methods Clément Bœsch
2022-12-27 23:18   ` [FFmpeg-devel] [PATCH v2 30/32] avfilter/paletteuse: remove mean error tool Clément Bœsch
2022-12-27 23:18   ` [FFmpeg-devel] [PATCH v2 31/32] avfilter/paletteuse: move r, g, b computation in a more local scope Clément Bœsch
2022-12-27 23:18   ` [FFmpeg-devel] [PATCH v2 32/32] avfilter/palette{gen, use}: misc for-loop cosmetics Clément Bœsch
2023-01-03 16:28   ` [FFmpeg-devel] New iteration for the color quantization in palette{gen, use} Clément Bœsch

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=20221227231814.2520181-6-u@pkh.me \
    --to=u@pkh.me \
    --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