[FFmpeg-devel] [PATCH 3/7] ffv1enc: split off encoder initialization into a separate function

Lynne dev at lynne.ee
Sat Nov 9 09:22:22 EET 2024


---
 libavcodec/ffv1enc.c | 352 +++++++++++++++++++++++--------------------
 libavcodec/ffv1enc.h |  30 ++++
 2 files changed, 216 insertions(+), 166 deletions(-)
 create mode 100644 libavcodec/ffv1enc.h

diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c
index 7a6c718b41..10103f129b 100644
--- a/libavcodec/ffv1enc.c
+++ b/libavcodec/ffv1enc.c
@@ -39,6 +39,7 @@
 #include "put_golomb.h"
 #include "rangecoder.h"
 #include "ffv1.h"
+#include "ffv1enc.h"
 
 static const int8_t quant5_10bit[256] = {
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,
@@ -513,17 +514,11 @@ static int sort_stt(FFV1Context *s, uint8_t stt[256])
     return print;
 }
 
-static av_cold int encode_init(AVCodecContext *avctx)
+av_cold int ff_ffv1_encode_init(AVCodecContext *avctx)
 {
     FFV1Context *s = avctx->priv_data;
-    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
     int i, j, k, m, ret;
 
-    if ((ret = ff_ffv1_common_init(avctx)) < 0)
-        return ret;
-
-    s->version = 0;
-
     if ((avctx->flags & (AV_CODEC_FLAG_PASS1 | AV_CODEC_FLAG_PASS2)) ||
         avctx->slices > 1)
         s->version = FFMAX(s->version, 2);
@@ -569,6 +564,182 @@ static av_cold int encode_init(AVCodecContext *avctx)
         return AVERROR_INVALIDDATA;
     }
 
+    if (s->ac == AC_RANGE_CUSTOM_TAB) {
+        for (i = 1; i < 256; i++)
+            s->state_transition[i] = ver2_state[i];
+    } else {
+        RangeCoder c;
+        ff_build_rac_states(&c, 0.05 * (1LL << 32), 256 - 8);
+        for (i = 1; i < 256; i++)
+            s->state_transition[i] = c.one_state[i];
+    }
+
+    for (i = 0; i < 256; i++) {
+        s->quant_table_count = 2;
+        if ((s->qtable == -1 && s->bits_per_raw_sample <= 8) || s->qtable == 1) {
+            s->quant_tables[0][0][i]=           quant11[i];
+            s->quant_tables[0][1][i]=        11*quant11[i];
+            s->quant_tables[0][2][i]=     11*11*quant11[i];
+            s->quant_tables[1][0][i]=           quant11[i];
+            s->quant_tables[1][1][i]=        11*quant11[i];
+            s->quant_tables[1][2][i]=     11*11*quant5 [i];
+            s->quant_tables[1][3][i]=   5*11*11*quant5 [i];
+            s->quant_tables[1][4][i]= 5*5*11*11*quant5 [i];
+            s->context_count[0] = (11 * 11 * 11        + 1) / 2;
+            s->context_count[1] = (11 * 11 * 5 * 5 * 5 + 1) / 2;
+        } else {
+            s->quant_tables[0][0][i]=           quant9_10bit[i];
+            s->quant_tables[0][1][i]=         9*quant9_10bit[i];
+            s->quant_tables[0][2][i]=       9*9*quant9_10bit[i];
+            s->quant_tables[1][0][i]=           quant9_10bit[i];
+            s->quant_tables[1][1][i]=         9*quant9_10bit[i];
+            s->quant_tables[1][2][i]=       9*9*quant5_10bit[i];
+            s->quant_tables[1][3][i]=     5*9*9*quant5_10bit[i];
+            s->quant_tables[1][4][i]=   5*5*9*9*quant5_10bit[i];
+            s->context_count[0] = (9 * 9 * 9         + 1) / 2;
+            s->context_count[1] = (9 * 9 * 5 * 5 * 5 + 1) / 2;
+        }
+    }
+
+    if ((ret = ff_ffv1_allocate_initial_states(s)) < 0)
+        return ret;
+
+    if (!s->transparency)
+        s->plane_count = 2;
+    if (!s->chroma_planes && s->version > 3)
+        s->plane_count--;
+
+    s->picture_number = 0;
+
+    if (avctx->flags & (AV_CODEC_FLAG_PASS1 | AV_CODEC_FLAG_PASS2)) {
+        for (i = 0; i < s->quant_table_count; i++) {
+            s->rc_stat2[i] = av_mallocz(s->context_count[i] *
+                                        sizeof(*s->rc_stat2[i]));
+            if (!s->rc_stat2[i])
+                return AVERROR(ENOMEM);
+        }
+    }
+    if (avctx->stats_in) {
+        char *p = avctx->stats_in;
+        uint8_t (*best_state)[256] = av_malloc_array(256, 256);
+        int gob_count = 0;
+        char *next;
+        if (!best_state)
+            return AVERROR(ENOMEM);
+
+        av_assert0(s->version >= 2);
+
+        for (;;) {
+            for (j = 0; j < 256; j++)
+                for (i = 0; i < 2; i++) {
+                    s->rc_stat[j][i] = strtol(p, &next, 0);
+                    if (next == p) {
+                        av_log(avctx, AV_LOG_ERROR,
+                               "2Pass file invalid at %d %d [%s]\n", j, i, p);
+                        av_freep(&best_state);
+                        return AVERROR_INVALIDDATA;
+                    }
+                    p = next;
+                }
+            for (i = 0; i < s->quant_table_count; i++)
+                for (j = 0; j < s->context_count[i]; j++) {
+                    for (k = 0; k < 32; k++)
+                        for (m = 0; m < 2; m++) {
+                            s->rc_stat2[i][j][k][m] = strtol(p, &next, 0);
+                            if (next == p) {
+                                av_log(avctx, AV_LOG_ERROR,
+                                       "2Pass file invalid at %d %d %d %d [%s]\n",
+                                       i, j, k, m, p);
+                                av_freep(&best_state);
+                                return AVERROR_INVALIDDATA;
+                            }
+                            p = next;
+                        }
+                }
+            gob_count = strtol(p, &next, 0);
+            if (next == p || gob_count <= 0) {
+                av_log(avctx, AV_LOG_ERROR, "2Pass file invalid\n");
+                av_freep(&best_state);
+                return AVERROR_INVALIDDATA;
+            }
+            p = next;
+            while (*p == '\n' || *p == ' ')
+                p++;
+            if (p[0] == 0)
+                break;
+        }
+        if (s->ac == AC_RANGE_CUSTOM_TAB)
+            sort_stt(s, s->state_transition);
+
+        find_best_state(best_state, s->state_transition);
+
+        for (i = 0; i < s->quant_table_count; i++) {
+            for (k = 0; k < 32; k++) {
+                double a=0, b=0;
+                int jp = 0;
+                for (j = 0; j < s->context_count[i]; j++) {
+                    double p = 128;
+                    if (s->rc_stat2[i][j][k][0] + s->rc_stat2[i][j][k][1] > 200 && j || a+b > 200) {
+                        if (a+b)
+                            p = 256.0 * b / (a + b);
+                        s->initial_states[i][jp][k] =
+                            best_state[av_clip(round(p), 1, 255)][av_clip_uint8((a + b) / gob_count)];
+                        for(jp++; jp<j; jp++)
+                            s->initial_states[i][jp][k] = s->initial_states[i][jp-1][k];
+                        a=b=0;
+                    }
+                    a += s->rc_stat2[i][j][k][0];
+                    b += s->rc_stat2[i][j][k][1];
+                    if (a+b) {
+                        p = 256.0 * b / (a + b);
+                    }
+                    s->initial_states[i][j][k] =
+                        best_state[av_clip(round(p), 1, 255)][av_clip_uint8((a + b) / gob_count)];
+                }
+            }
+        }
+        av_freep(&best_state);
+    }
+
+    if (s->version <= 1) {
+        /* Disable slices when the version doesn't support them */
+        s->num_h_slices = 1;
+        s->num_v_slices = 1;
+    } else {
+        if ((ret = write_extradata(s)) < 0)
+            return ret;
+    }
+
+    if ((ret = ff_ffv1_init_slice_contexts(s)) < 0)
+        return ret;
+    s->slice_count = s->max_slice_count;
+
+    for (int j = 0; j < s->slice_count; j++) {
+        for (int i = 0; i < s->plane_count; i++) {
+            PlaneContext *const p = &s->slices[j].plane[i];
+
+            p->quant_table_index = s->context_model;
+            p->context_count     = s->context_count[p->quant_table_index];
+        }
+
+        ff_build_rac_states(&s->slices[j].c, 0.05 * (1LL << 32), 256 - 8);
+    }
+
+    if ((ret = ff_ffv1_init_slices_state(s)) < 0)
+        return ret;
+
+    return 0;
+}
+
+static int encode_init_internal(AVCodecContext *avctx)
+{
+    int ret;
+    FFV1Context *s = avctx->priv_data;
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
+
+    if ((ret = ff_ffv1_common_init(avctx)) < 0)
+        return ret;
+
     if (s->ac == 1) // Compatbility with common command line usage
         s->ac = AC_RANGE_CUSTOM_TAB;
     else if (s->ac == AC_RANGE_DEFAULT_TAB_FORCE)
@@ -716,148 +887,11 @@ static av_cold int encode_init(AVCodecContext *avctx)
         }
     }
 
-    if (s->ac == AC_RANGE_CUSTOM_TAB) {
-        for (i = 1; i < 256; i++)
-            s->state_transition[i] = ver2_state[i];
-    } else {
-        RangeCoder c;
-        ff_build_rac_states(&c, 0.05 * (1LL << 32), 256 - 8);
-        for (i = 1; i < 256; i++)
-            s->state_transition[i] = c.one_state[i];
-    }
-
-    for (i = 0; i < MAX_QUANT_TABLE_SIZE; i++) {
-        s->quant_table_count = 2;
-        if ((s->qtable == -1 && s->bits_per_raw_sample <= 8) || s->qtable == 1) {
-            s->quant_tables[0][0][i]=           quant11[i];
-            s->quant_tables[0][1][i]=        11*quant11[i];
-            s->quant_tables[0][2][i]=     11*11*quant11[i];
-            s->quant_tables[1][0][i]=           quant11[i];
-            s->quant_tables[1][1][i]=        11*quant11[i];
-            s->quant_tables[1][2][i]=     11*11*quant5 [i];
-            s->quant_tables[1][3][i]=   5*11*11*quant5 [i];
-            s->quant_tables[1][4][i]= 5*5*11*11*quant5 [i];
-            s->context_count[0] = (11 * 11 * 11        + 1) / 2;
-            s->context_count[1] = (11 * 11 * 5 * 5 * 5 + 1) / 2;
-        } else {
-            s->quant_tables[0][0][i]=           quant9_10bit[i];
-            s->quant_tables[0][1][i]=         9*quant9_10bit[i];
-            s->quant_tables[0][2][i]=       9*9*quant9_10bit[i];
-            s->quant_tables[1][0][i]=           quant9_10bit[i];
-            s->quant_tables[1][1][i]=         9*quant9_10bit[i];
-            s->quant_tables[1][2][i]=       9*9*quant5_10bit[i];
-            s->quant_tables[1][3][i]=     5*9*9*quant5_10bit[i];
-            s->quant_tables[1][4][i]=   5*5*9*9*quant5_10bit[i];
-            s->context_count[0] = (9 * 9 * 9         + 1) / 2;
-            s->context_count[1] = (9 * 9 * 5 * 5 * 5 + 1) / 2;
-        }
-    }
-
-    if ((ret = ff_ffv1_allocate_initial_states(s)) < 0)
-        return ret;
-
-    if (!s->transparency)
-        s->plane_count = 2;
-    if (!s->chroma_planes && s->version > 3)
-        s->plane_count--;
-
     ret = av_pix_fmt_get_chroma_sub_sample (avctx->pix_fmt, &s->chroma_h_shift, &s->chroma_v_shift);
     if (ret)
         return ret;
 
-    s->picture_number = 0;
-
-    if (avctx->flags & (AV_CODEC_FLAG_PASS1 | AV_CODEC_FLAG_PASS2)) {
-        for (i = 0; i < s->quant_table_count; i++) {
-            s->rc_stat2[i] = av_mallocz(s->context_count[i] *
-                                        sizeof(*s->rc_stat2[i]));
-            if (!s->rc_stat2[i])
-                return AVERROR(ENOMEM);
-        }
-    }
-    if (avctx->stats_in) {
-        char *p = avctx->stats_in;
-        uint8_t (*best_state)[256] = av_malloc_array(256, 256);
-        int gob_count = 0;
-        char *next;
-        if (!best_state)
-            return AVERROR(ENOMEM);
-
-        av_assert0(s->version >= 2);
-
-        for (;;) {
-            for (j = 0; j < 256; j++)
-                for (i = 0; i < 2; i++) {
-                    s->rc_stat[j][i] = strtol(p, &next, 0);
-                    if (next == p) {
-                        av_log(avctx, AV_LOG_ERROR,
-                               "2Pass file invalid at %d %d [%s]\n", j, i, p);
-                        av_freep(&best_state);
-                        return AVERROR_INVALIDDATA;
-                    }
-                    p = next;
-                }
-            for (i = 0; i < s->quant_table_count; i++)
-                for (j = 0; j < s->context_count[i]; j++) {
-                    for (k = 0; k < 32; k++)
-                        for (m = 0; m < 2; m++) {
-                            s->rc_stat2[i][j][k][m] = strtol(p, &next, 0);
-                            if (next == p) {
-                                av_log(avctx, AV_LOG_ERROR,
-                                       "2Pass file invalid at %d %d %d %d [%s]\n",
-                                       i, j, k, m, p);
-                                av_freep(&best_state);
-                                return AVERROR_INVALIDDATA;
-                            }
-                            p = next;
-                        }
-                }
-            gob_count = strtol(p, &next, 0);
-            if (next == p || gob_count <= 0) {
-                av_log(avctx, AV_LOG_ERROR, "2Pass file invalid\n");
-                av_freep(&best_state);
-                return AVERROR_INVALIDDATA;
-            }
-            p = next;
-            while (*p == '\n' || *p == ' ')
-                p++;
-            if (p[0] == 0)
-                break;
-        }
-        if (s->ac == AC_RANGE_CUSTOM_TAB)
-            sort_stt(s, s->state_transition);
-
-        find_best_state(best_state, s->state_transition);
-
-        for (i = 0; i < s->quant_table_count; i++) {
-            for (k = 0; k < 32; k++) {
-                double a=0, b=0;
-                int jp = 0;
-                for (j = 0; j < s->context_count[i]; j++) {
-                    double p = 128;
-                    if (s->rc_stat2[i][j][k][0] + s->rc_stat2[i][j][k][1] > 200 && j || a+b > 200) {
-                        if (a+b)
-                            p = 256.0 * b / (a + b);
-                        s->initial_states[i][jp][k] =
-                            best_state[av_clip(round(p), 1, 255)][av_clip_uint8((a + b) / gob_count)];
-                        for(jp++; jp<j; jp++)
-                            s->initial_states[i][jp][k] = s->initial_states[i][jp-1][k];
-                        a=b=0;
-                    }
-                    a += s->rc_stat2[i][j][k][0];
-                    b += s->rc_stat2[i][j][k][1];
-                    if (a+b) {
-                        p = 256.0 * b / (a + b);
-                    }
-                    s->initial_states[i][j][k] =
-                        best_state[av_clip(round(p), 1, 255)][av_clip_uint8((a + b) / gob_count)];
-                }
-            }
-        }
-        av_freep(&best_state);
-    }
-
-    if (s->version > 1) {
+    {
         int plane_count = 1 + 2*s->chroma_planes + s->transparency;
         int max_h_slices = AV_CEIL_RSHIFT(avctx->width , s->chroma_h_shift);
         int max_v_slices = AV_CEIL_RSHIFT(avctx->height, s->chroma_v_shift);
@@ -886,27 +920,13 @@ static av_cold int encode_init(AVCodecContext *avctx)
                "supported number with -slices (ex:4,6,9,12,16, ...)\n",
                avctx->slices);
         return AVERROR(ENOSYS);
-slices_ok:
-        if ((ret = write_extradata(s)) < 0)
-            return ret;
     }
 
-    if ((ret = ff_ffv1_init_slice_contexts(s)) < 0)
-        return ret;
-    s->slice_count = s->max_slice_count;
-
-    for (int j = 0; j < s->slice_count; j++) {
-        for (int i = 0; i < s->plane_count; i++) {
-            PlaneContext *const p = &s->slices[j].plane[i];
-
-            p->quant_table_index = s->context_model;
-            p->context_count     = s->context_count[p->quant_table_index];
-        }
-
-        ff_build_rac_states(&s->slices[j].c, 0.05 * (1LL << 32), 256 - 8);
-    }
+slices_ok:
+    s->version = 0;
 
-    if ((ret = ff_ffv1_init_slices_state(s)) < 0)
+    ret = ff_ffv1_encode_init(avctx);
+    if (ret < 0)
         return ret;
 
 #define STATS_OUT_SIZE 1024 * 1024 * 6
@@ -914,8 +934,8 @@ slices_ok:
         avctx->stats_out = av_mallocz(STATS_OUT_SIZE);
         if (!avctx->stats_out)
             return AVERROR(ENOMEM);
-        for (i = 0; i < s->quant_table_count; i++)
-            for (j = 0; j < s->max_slice_count; j++) {
+        for (int i = 0; i < s->quant_table_count; i++)
+            for (int j = 0; j < s->max_slice_count; j++) {
                 FFV1SliceContext *sc = &s->slices[j];
                 av_assert0(!sc->rc_stat2[i]);
                 sc->rc_stat2[i] = av_mallocz(s->context_count[i] *
@@ -1320,7 +1340,7 @@ const FFCodec ff_ffv1_encoder = {
                       AV_CODEC_CAP_SLICE_THREADS |
                       AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
     .priv_data_size = sizeof(FFV1Context),
-    .init           = encode_init,
+    .init           = encode_init_internal,
     FF_CODEC_ENCODE_CB(encode_frame),
     .close          = ff_ffv1_close,
     .p.pix_fmts     = (const enum AVPixelFormat[]) {
diff --git a/libavcodec/ffv1enc.h b/libavcodec/ffv1enc.h
new file mode 100644
index 0000000000..c062af0bf5
--- /dev/null
+++ b/libavcodec/ffv1enc.h
@@ -0,0 +1,30 @@
+/*
+ * FFV1 encoder
+ *
+ * Copyright (c) 2003-2013 Michael Niedermayer <michaelni at gmx.at>
+ *
+ * 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 AVCODEC_FFV1ENC_H
+#define AVCODEC_FFV1ENC_H
+
+#include "avcodec.h"
+
+av_cold int ff_ffv1_encode_init(AVCodecContext *avctx);
+
+#endif /* AVCODEC_FFV1ENC_H */
-- 
2.45.2.753.g447d99e1c3b


More information about the ffmpeg-devel mailing list