[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