[FFmpeg-devel] [PATCH 3/3] libavfilter/dnn: Initialze DNNData variables

2023-09-19 Thread wenbin . chen-at-intel . com
From: Wenbin Chen 

Signed-off-by: Wenbin Chen 
---
 libavfilter/dnn/dnn_backend_tf.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libavfilter/dnn/dnn_backend_tf.c b/libavfilter/dnn/dnn_backend_tf.c
index b521de7fbe..e1e8cef0d2 100644
--- a/libavfilter/dnn/dnn_backend_tf.c
+++ b/libavfilter/dnn/dnn_backend_tf.c
@@ -629,6 +629,7 @@ static int fill_model_input_tf(TFModel *tf_model, 
TFRequestItem *request) {
 TFContext *ctx = _model->ctx;
 int ret = 0;
 
+memset(, 0, sizeof(input));
 lltask = ff_queue_pop_front(tf_model->lltask_queue);
 av_assert0(lltask);
 task = lltask->task;
@@ -724,7 +725,7 @@ static void infer_completion_callback(void *args) {
 TFModel *tf_model = task->model;
 TFContext *ctx = _model->ctx;
 
-outputs = av_malloc_array(task->nb_output, sizeof(*outputs));
+outputs = av_calloc(task->nb_output, sizeof(*outputs));
 if (!outputs) {
 av_log(ctx, AV_LOG_ERROR, "Failed to allocate memory for *outputs\n");
 goto err;
-- 
2.34.1

___
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".


[FFmpeg-devel] [PATCH 2/3] libavfilter/dnn: Add scale and mean preprocess to openvino backend

2023-09-19 Thread wenbin . chen-at-intel . com
From: Wenbin Chen 

Dnn models has different data preprocess requirements. Scale and mean
parameters are added to preprocess input data.

Signed-off-by: Wenbin Chen 
---
 libavfilter/dnn/dnn_backend_openvino.c | 43 --
 libavfilter/dnn/dnn_io_proc.c  | 82 +-
 libavfilter/dnn_interface.h|  2 +
 3 files changed, 108 insertions(+), 19 deletions(-)

diff --git a/libavfilter/dnn/dnn_backend_openvino.c 
b/libavfilter/dnn/dnn_backend_openvino.c
index 3ba5f5331a..4224600f94 100644
--- a/libavfilter/dnn/dnn_backend_openvino.c
+++ b/libavfilter/dnn/dnn_backend_openvino.c
@@ -46,6 +46,8 @@ typedef struct OVOptions{
 int batch_size;
 int input_resizable;
 DNNLayout layout;
+float scale;
+float mean;
 } OVOptions;
 
 typedef struct OVContext {
@@ -105,6 +107,8 @@ static const AVOption dnn_openvino_options[] = {
 { "none",  "none", 0, AV_OPT_TYPE_CONST, { .i64 = DL_NONE }, 0, 0, 
FLAGS, "layout"},
 { "nchw",  "nchw", 0, AV_OPT_TYPE_CONST, { .i64 = DL_NCHW }, 0, 0, 
FLAGS, "layout"},
 { "nhwc",  "nhwc", 0, AV_OPT_TYPE_CONST, { .i64 = DL_NHWC }, 0, 0, 
FLAGS, "layout"},
+{ "scale", "Add scale preprocess operation. Divide each element of input 
by specified value.", OFFSET(options.scale), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, 
INT_MIN, INT_MAX, FLAGS},
+{ "mean",  "Add mean preprocess operation. Subtract specified value from 
each element of input.", OFFSET(options.mean),  AV_OPT_TYPE_FLOAT, { .dbl = 0 
}, INT_MIN, INT_MAX, FLAGS},
 { NULL }
 };
 
@@ -209,6 +213,7 @@ static int fill_model_input_ov(OVModel *ov_model, 
OVRequestItem *request)
 ie_blob_t *input_blob = NULL;
 #endif
 
+memset(, 0, sizeof(input));
 lltask = ff_queue_peek_front(ov_model->lltask_queue);
 av_assert0(lltask);
 task = lltask->task;
@@ -274,6 +279,9 @@ static int fill_model_input_ov(OVModel *ov_model, 
OVRequestItem *request)
 // all models in openvino open model zoo use BGR as input,
 // change to be an option when necessary.
 input.order = DCO_BGR;
+// We use preprocess_steps to scale input data, so disable scale and mean 
here.
+input.scale = 1;
+input.mean = 0;
 
 for (int i = 0; i < ctx->options.batch_size; ++i) {
 lltask = ff_queue_pop_front(ov_model->lltask_queue);
@@ -343,6 +351,7 @@ static void infer_completion_callback(void *args)
 ov_shape_t output_shape = {0};
 ov_element_type_e precision;
 
+memset(, 0, sizeof(output));
 status = 
ov_infer_request_get_output_tensor_by_index(request->infer_request, 0, 
_tensor);
 if (status != OK) {
 av_log(ctx, AV_LOG_ERROR,
@@ -409,6 +418,8 @@ static void infer_completion_callback(void *args)
 #endif
 output.dt   = precision_to_datatype(precision);
 output.layout   = ctx->options.layout;
+output.scale= ctx->options.scale;
+output.mean = ctx->options.mean;
 
 av_assert0(request->lltask_count >= 1);
 for (int i = 0; i < request->lltask_count; ++i) {
@@ -542,7 +553,9 @@ static int init_model_ov(OVModel *ov_model, const char 
*input_name, const char *
 ie_config_t config = {NULL, NULL, NULL};
 char *all_dev_names = NULL;
 #endif
-
+// We scale pixel by default when do frame processing.
+if (fabsf(ctx->options.scale) < 1e-6f)
+ctx->options.scale = ov_model->model->func_type == DFT_PROCESS_FRAME ? 
255 : 1;
 // batch size
 if (ctx->options.batch_size <= 0) {
 ctx->options.batch_size = 1;
@@ -609,15 +622,37 @@ static int init_model_ov(OVModel *ov_model, const char 
*input_name, const char *
 goto err;
 }
 
+status = 
ov_preprocess_input_tensor_info_set_element_type(input_tensor_info, U8);
 if (ov_model->model->func_type != DFT_PROCESS_FRAME)
-//set precision only for detect and classify
-status = 
ov_preprocess_input_tensor_info_set_element_type(input_tensor_info, U8);
-status |= ov_preprocess_output_set_element_type(output_tensor_info, F32);
+status |= ov_preprocess_output_set_element_type(output_tensor_info, 
F32);
+else if (fabsf(ctx->options.scale - 1) > 1e-6f || fabsf(ctx->options.mean) 
> 1e-6f)
+status |= ov_preprocess_output_set_element_type(output_tensor_info, 
F32);
+else
+status |= ov_preprocess_output_set_element_type(output_tensor_info, 
U8);
 if (status != OK) {
 av_log(ctx, AV_LOG_ERROR, "Failed to set input/output element type\n");
 ret = ov2_map_error(status, NULL);
 goto err;
 }
+// set preprocess steps.
+if (fabsf(ctx->options.scale - 1) > 1e-6f || fabsf(ctx->options.mean) > 
1e-6f) {
+ov_preprocess_preprocess_steps_t* input_process_steps = NULL;
+status = 
ov_preprocess_input_info_get_preprocess_steps(ov_model->input_info, 
_process_steps);
+if (status != OK) {
+av_log(ctx, AV_LOG_ERROR, "Failed to get preprocess steps\n");
+ret = ov2_map_error(status, NULL);
+

[FFmpeg-devel] [PATCH 1/3] libavfilter/dnn: add layout option to openvino backend

2023-09-19 Thread wenbin . chen-at-intel . com
From: Wenbin Chen 

Dnn models have different input layout (NCHW or NHWC), so a
"layout" option is added
Use openvino's API to do layout conversion for input data. Use swscale
to do layout conversion for output data as openvino doesn't have
similiar C API for output.

Signed-off-by: Wenbin Chen 
---
 libavfilter/dnn/dnn_backend_openvino.c |  47 +++-
 libavfilter/dnn/dnn_io_proc.c  | 151 ++---
 libavfilter/dnn_interface.h|   7 ++
 3 files changed, 185 insertions(+), 20 deletions(-)

diff --git a/libavfilter/dnn/dnn_backend_openvino.c 
b/libavfilter/dnn/dnn_backend_openvino.c
index 4922833b07..3ba5f5331a 100644
--- a/libavfilter/dnn/dnn_backend_openvino.c
+++ b/libavfilter/dnn/dnn_backend_openvino.c
@@ -45,6 +45,7 @@ typedef struct OVOptions{
 uint8_t async;
 int batch_size;
 int input_resizable;
+DNNLayout layout;
 } OVOptions;
 
 typedef struct OVContext {
@@ -100,6 +101,10 @@ static const AVOption dnn_openvino_options[] = {
 DNN_BACKEND_COMMON_OPTIONS
 { "batch_size",  "batch size per request", OFFSET(options.batch_size),  
AV_OPT_TYPE_INT,{ .i64 = 1 }, 1, 1000, FLAGS},
 { "input_resizable", "can input be resizable or not", 
OFFSET(options.input_resizable), AV_OPT_TYPE_BOOL,   { .i64 = 0 }, 0, 1, 
FLAGS },
+{ "layout", "input layout of model", OFFSET(options.layout), 
AV_OPT_TYPE_INT, { .i64 = DL_NONE}, DL_NONE, DL_NHWC, FLAGS, "layout" },
+{ "none",  "none", 0, AV_OPT_TYPE_CONST, { .i64 = DL_NONE }, 0, 0, 
FLAGS, "layout"},
+{ "nchw",  "nchw", 0, AV_OPT_TYPE_CONST, { .i64 = DL_NCHW }, 0, 0, 
FLAGS, "layout"},
+{ "nhwc",  "nhwc", 0, AV_OPT_TYPE_CONST, { .i64 = DL_NHWC }, 0, 0, 
FLAGS, "layout"},
 { NULL }
 };
 
@@ -231,9 +236,9 @@ static int fill_model_input_ov(OVModel *ov_model, 
OVRequestItem *request)
 avpriv_report_missing_feature(ctx, "Do not support dynamic model.");
 return AVERROR(ENOSYS);
 }
-input.height = dims[2];
-input.width = dims[3];
-input.channels = dims[1];
+input.height = dims[1];
+input.width = dims[2];
+input.channels = dims[3];
 input.dt = precision_to_datatype(precision);
 input.data = av_malloc(input.height * input.width * input.channels * 
get_datatype_size(input.dt));
 if (!input.data)
@@ -403,6 +408,7 @@ static void infer_completion_callback(void *args)
 av_assert0(request->lltask_count <= dims.dims[0]);
 #endif
 output.dt   = precision_to_datatype(precision);
+output.layout   = ctx->options.layout;
 
 av_assert0(request->lltask_count >= 1);
 for (int i = 0; i < request->lltask_count; ++i) {
@@ -521,11 +527,14 @@ static int init_model_ov(OVModel *ov_model, const char 
*input_name, const char *
 OVContext *ctx = _model->ctx;
 #if HAVE_OPENVINO2
 ov_status_e status;
-ov_preprocess_input_tensor_info_t* input_tensor_info;
-ov_preprocess_output_tensor_info_t* output_tensor_info;
+ov_preprocess_input_tensor_info_t* input_tensor_info = NULL;
+ov_preprocess_output_tensor_info_t* output_tensor_info = NULL;
+ov_preprocess_input_model_info_t* input_model_info = NULL;
 ov_model_t *tmp_ov_model;
 ov_layout_t* NHWC_layout = NULL;
+ov_layout_t* NCHW_layout = NULL;
 const char* NHWC_desc = "NHWC";
+const char* NCHW_desc = "NCHW";
 const char* device = ctx->options.device_type;
 #else
 IEStatusCode status;
@@ -570,6 +579,7 @@ static int init_model_ov(OVModel *ov_model, const char 
*input_name, const char *
 
 //set input layout
 status = ov_layout_create(NHWC_desc, _layout);
+status |= ov_layout_create(NCHW_desc, _layout);
 if (status != OK) {
 av_log(ctx, AV_LOG_ERROR, "Failed to create layout for input.\n");
 ret = ov2_map_error(status, NULL);
@@ -583,6 +593,22 @@ static int init_model_ov(OVModel *ov_model, const char 
*input_name, const char *
 goto err;
 }
 
+status = ov_preprocess_input_info_get_model_info(ov_model->input_info, 
_model_info);
+if (status != OK) {
+av_log(ctx, AV_LOG_ERROR, "Failed to get input model info\n");
+ret = ov2_map_error(status, NULL);
+goto err;
+}
+if (ctx->options.layout == DL_NCHW)
+status = ov_preprocess_input_model_info_set_layout(input_model_info, 
NCHW_layout);
+else if (ctx->options.layout == DL_NHWC)
+status = ov_preprocess_input_model_info_set_layout(input_model_info, 
NHWC_layout);
+if (status != OK) {
+av_log(ctx, AV_LOG_ERROR, "Failed to get set input model layout\n");
+ret = ov2_map_error(status, NULL);
+goto err;
+}
+
 if (ov_model->model->func_type != DFT_PROCESS_FRAME)
 //set precision only for detect and classify
 status = 
ov_preprocess_input_tensor_info_set_element_type(input_tensor_info, U8);
@@ -618,6 +644,9 @@ static int init_model_ov(OVModel *ov_model, const char 
*input_name, const char *
 ret = ov2_map_error(status, NULL);
   

Re: [FFmpeg-devel] FFmpeg release 6.1

2023-09-19 Thread Xiang, Haihao
On Di, 2023-09-19 at 20:38 -0400, Neal Gompa wrote:
> On Tue, Sep 19, 2023 at 5:58 PM Lynne  wrote:
> > 
> > Sep 19, 2023, 21:16 by mich...@niedermayer.cc:
> > 
> > > On Tue, Sep 19, 2023 at 07:18:03PM +0200, Niklas Haas wrote:
> > > 
> > > > On Tue, 11 Apr 2023 00:14:28 +0200 Michael Niedermayer
> > > >  wrote:
> > > > > Hi all
> > > > > 
> > > > > There was the request to make a 6.1 before end of April
> > > > > Is that still so ?
> > > > > 
> > > > > Assuming it is, its time to make that branch and release soon
> > > > 
> > > > Hi,
> > > > 
> > > > It is now september. What happened to this release? FFmpeg 6.1 is
> > > > currently the only thing blocking the adoption of vulkan video.
> > > > 
> > > 
> > > there are several security issues that need to be fixed
> > > ossfuzz found more, it also put some random unlreated issues again
> > > into the same ticket. (which are basically invissible sub-tickets)
> > > the evc code also needs a security review, Maybe Dawid is working on this
> > > iam not sure. And iam sure theres more
> > > We also have a security issue in fate, i belive nicolas is looking into
> > > that, that doesnt hold up the release but all these things compete for
> > > time
> > > and some people you may have noticed tried to just randomly block patches
> > > going back and forth on these and discussing with tech/community
> > > committtees
> > > also took time.
> > > And last but not least if people want me to design a standalone SDR
> > > library
> > > while thats not holding up 6.1 it takes time from the pot from 6.1 work.
> > > I did say this, i was attacked but yes time is unforgiving it doesnt care
> > > 
> > > Also I did fall behind with security fixes in the summer a bit, the
> > > weather was
> > > nice, some members of the community where not nice. So i tried to spend
> > > some
> > > time with the nice weather
> > > 
> > > If you want 6.1 to happen quick. be nice to me or help with anything that
> > > i
> > > have to work on 6.1 or other so theres more time in the pot
> > > what about merging libplacebo into FFmpeg for example ?
> > > As far as iam concerned you can have absolute final power about anything
> > > in that libplacebo inside FFmpeg.
> > > Or help with the whole SDR thing. If i dont have to think about it and
> > > can concentrate on the release and security then yes it will happen faster
> > > 
> > > I also have some paid work under NDA which i signed a contract for, i need
> > > to work on that too. Yes code will be submitted to FFmpeg when/if its done
> > > And theres life, i have other shit to do too. For example my taxes and i
> > > also
> > > want to spend some time working on AI/neural nets. I guess that will not
> > > be
> > > FFmpeg related as id like my work on AI not to be in a similar position to
> > > where avradio is now.
> > > 
> > > So yeah, i think theres no problem with 6.1 its just not happening as
> > > quick
> > > as I and others wanted
> > > 
> > > thx
> > > 
> > > [...]
> > > --
> > > Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
> > > 
> > > If you think the mosad wants you dead since a long time then you are
> > > either
> > > wrong or dead since a long time.
> > > 
> > 
> > I'm not sure it's a good idea to wait to merge the EVC decoder.
> > Perhaps we should move that to the next release.
> > 
> > I'd like to get my AAC padding/duration fixes in, and drop lavc's
> > old FFT code entirely.
> 
> From my wishlist, the only thing left unmerged is AV1 VA-API encode
> support. The patchset is on v5 now and seems to be fine? I can't test
> it due to lack of compatible hardware, so if someone here does have
> something and can do it, it'd be great to see it get reviewed and
> landed.

AV1 VA-API encode works well for me, I'll push it if no more comments.

BRs
Haihao

> 
> 
> 

___
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".


Re: [FFmpeg-devel] [PATCH v5 1/8] avcodec/cbs_av1: Add tx mode enum values

2023-09-19 Thread Xiang, Haihao
On Di, 2023-09-19 at 20:40 -0400, Neal Gompa wrote:
> On Mon, Sep 11, 2023 at 3:52 AM  wrote:
> > 
> > From: Fei Wang 
> > 
> > Signed-off-by: Fei Wang 
> > ---
> >  libavcodec/av1.h | 7 +++
> >  libavcodec/cbs_av1_syntax_template.c | 4 ++--
> >  2 files changed, 9 insertions(+), 2 deletions(-)
> > 
> > diff --git a/libavcodec/av1.h b/libavcodec/av1.h
> > index 384f7cddc7..8704bc41c1 100644
> > --- a/libavcodec/av1.h
> > +++ b/libavcodec/av1.h
> > @@ -175,6 +175,13 @@ enum {
> >  AV1_RESTORE_SWITCHABLE = 3,
> >  };
> > 
> > +// TX mode (section 6.8.21)
> > +enum {
> > +    AV1_ONLY_4X4    = 0,
> > +    AV1_TX_MODE_LARGEST = 1,
> > +    AV1_TX_MODE_SELECT  = 2,
> > +};
> > +
> >  // Sequence Headers are actually unbounded because one can use
> >  // an arbitrary number of leading zeroes when encoding via uvlc.
> >  // The following estimate is based around using the lowest number
> > diff --git a/libavcodec/cbs_av1_syntax_template.c
> > b/libavcodec/cbs_av1_syntax_template.c
> > index 6f09c4e410..3be1f2d30f 100644
> > --- a/libavcodec/cbs_av1_syntax_template.c
> > +++ b/libavcodec/cbs_av1_syntax_template.c
> > @@ -1028,9 +1028,9 @@ static int FUNC(read_tx_mode)(CodedBitstreamContext
> > *ctx, RWContext *rw,
> >  int err;
> > 
> >  if (priv->coded_lossless)
> > -    infer(tx_mode, 0);
> > +    infer(tx_mode, AV1_ONLY_4X4);
> >  else
> > -    increment(tx_mode, 1, 2);
> > +    increment(tx_mode, AV1_TX_MODE_LARGEST, AV1_TX_MODE_SELECT);
> > 
> >  return 0;
> >  }
> > --
> > 2.25.1
> > 
> 
> Code looks good to me, I just lack hardware to exercise the functionality.
> 
> Acked-by: Neal Gompa 
> 

This patchset looks good and works well for me. I'll push this patchset in a few
days if there are no more comments

Thanks
Haihao


___
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".


Re: [FFmpeg-devel] [PATCH v5 8/8] lavc/av1: Add unit test for level handling

2023-09-19 Thread Neal Gompa
On Mon, Sep 11, 2023 at 3:54 AM  wrote:
>
> From: Fei Wang 
>
> Signed-off-by: Fei Wang 
> ---
>  libavcodec/tests/.gitignore   |   1 +
>  libavcodec/tests/av1_levels.c | 126 ++
>  tests/fate/libavcodec.mak |   5 ++
>  3 files changed, 132 insertions(+)
>  create mode 100644 libavcodec/tests/av1_levels.c
>
> diff --git a/libavcodec/tests/.gitignore b/libavcodec/tests/.gitignore
> index 2acfc4e804..5e0ccc5838 100644
> --- a/libavcodec/tests/.gitignore
> +++ b/libavcodec/tests/.gitignore
> @@ -1,3 +1,4 @@
> +/av1_levels
>  /avcodec
>  /avfft
>  /avpacket
> diff --git a/libavcodec/tests/av1_levels.c b/libavcodec/tests/av1_levels.c
> new file mode 100644
> index 00..e862d197d2
> --- /dev/null
> +++ b/libavcodec/tests/av1_levels.c
> @@ -0,0 +1,126 @@
> +/*
> + * Copyright (c) 2023 Intel Corporation
> + *
> + * 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
> + */
> +
> +#include 
> +#include 
> +#include "libavutil/log.h"
> +#include "libavcodec/av1_levels.h"
> +
> +static const struct {
> +int width;
> +int height;
> +float framerate;
> +int level_idx;
> +} test_sizes[] = {
> +{  426,  240,  30.0,  0 },
> +{  640,  360,  30.0,  1 },
> +{  854,  480,  30.0,  4 },
> +{ 1280,  720,  30.0,  5 },
> +{ 1920, 1080,  30.0,  8 },
> +{ 1920, 1080,  60.0,  9 },
> +{ 3840, 2160,  30.0, 12 },
> +{ 3840, 2160,  60.0, 13 },
> +{ 3840, 2160, 120.0, 14 },
> +{ 7680, 4320,  30.0, 16 },
> +{ 7680, 4320,  60.0, 17 },
> +{ 7680, 4320, 120.0, 18 },
> +};
> +
> +static const struct {
> +int64_t bitrate;
> +int tier;
> +int level_idx;
> +} test_bitrate[] = {
> +{   150, 0,  0 },
> +{   300, 0,  1 },
> +{   600, 0,  4 },
> +{  1000, 0,  5 },
> +{  1200, 0,  8 },
> +{  3000, 1,  8 },
> +{  2000, 0,  9 },
> +{  5000, 1,  9 },
> +{  3000, 0, 12 },
> +{ 1, 1, 12 },
> +{  4000, 0, 13 },
> +{ 16000, 1, 13 },
> +{  6000, 0, 14 },
> +{ 24000, 1, 14 },
> +{ 1, 0, 17 },
> +{ 48000, 1, 17 },
> +{ 16000, 0, 18 },
> +{ 8, 1, 18 },
> +};
> +
> +static const struct {
> +int tiles;
> +int tile_cols;
> +int level_idx;
> +} test_tiles[] = {
> +{8,  4,  0 },
> +{   16,  6,  4 },
> +{   32,  8,  8 },
> +{   64,  8, 12 },
> +{  128, 16, 16 },
> +};
> +
> +int main(void)
> +{
> +const AV1LevelDescriptor *level;
> +int i;
> +
> +#define CHECK(expected, format, ...) do { \
> +if (level ? (level->level_idx != expected) \
> + : !level) { \
> +av_log(NULL, AV_LOG_ERROR, "Incorrect level for " \
> +   format ": expected %d, got %d.\n", __VA_ARGS__, \
> +   expected, level ? level->level_idx : -1); \
> +return 1; \
> +} \
> +} while (0)
> +
> +for (i = 0; i < FF_ARRAY_ELEMS(test_sizes); i++) {
> +level = ff_av1_guess_level(0, 0,
> +   test_sizes[i].width,
> +   test_sizes[i].height,
> +   0, 0, test_sizes[i].framerate);
> +CHECK(test_sizes[i].level_idx, "size %dx%d, framerate %f",
> +  test_sizes[i].width, test_sizes[i].height, 
> test_sizes[i].framerate);
> +}
> +
> +for (i = 0; i < FF_ARRAY_ELEMS(test_bitrate); i++) {
> +level = ff_av1_guess_level(test_bitrate[i].bitrate,
> +   test_bitrate[i].tier,
> +   0, 0, 0, 0, 0);
> +CHECK(test_bitrate[i].level_idx, "bitrate %"PRId64" tier %d",
> +  test_bitrate[i].bitrate, test_bitrate[i].tier);
> +}
> +
> +for (i = 0; i < FF_ARRAY_ELEMS(test_tiles); i++) {
> +level = ff_av1_guess_level(0, 0, 0, 0,
> +   test_tiles[i].tiles,
> +   test_tiles[i].tile_cols,
> +   0);
> +CHECK(test_tiles[i].level_idx, "tiles %d, tile cols %d",
> +  test_tiles[i].tiles,
> +  test_tiles[i].tile_cols);
> +}
> +
> +return 0;

Re: [FFmpeg-devel] [PATCH v5 7/8] lavc/vaapi_encode: Add VAAPI AV1 encoder

2023-09-19 Thread Neal Gompa
On Mon, Sep 11, 2023 at 3:53 AM  wrote:
>
> From: Fei Wang 
>
> Signed-off-by: Fei Wang 
> ---
> Update:
> 1. use AV_PROFILE* instead of deprecated FF_PROFILE*.
>
>  Changelog |   1 +
>  configure |   3 +
>  doc/encoders.texi |  14 +
>  libavcodec/Makefile   |   2 +
>  libavcodec/allcodecs.c|   1 +
>  libavcodec/av1_levels.c   |  92 
>  libavcodec/av1_levels.h   |  58 +++
>  libavcodec/vaapi_encode.c | 198 +--
>  libavcodec/vaapi_encode.h |  24 +
>  libavcodec/vaapi_encode_av1.c | 949 ++
>  libavcodec/version.h  |   2 +-
>  11 files changed, 1311 insertions(+), 33 deletions(-)
>  create mode 100644 libavcodec/av1_levels.c
>  create mode 100644 libavcodec/av1_levels.h
>  create mode 100644 libavcodec/vaapi_encode_av1.c
>
> diff --git a/Changelog b/Changelog
> index 0cfcecfb93..303a3d9ca2 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -32,6 +32,7 @@ version :
>  - apsnr and asisdr audio filters
>  - OSQ demuxer and decoder
>  - Support HEVC,VP9,AV1 codec fourcclist in enhanced rtmp protocol
> +- VAAPI AV1 encoder
>
>
>  version 6.0:
> diff --git a/configure b/configure
> index bd7f7697c8..ec7a80cd48 100755
> --- a/configure
> +++ b/configure
> @@ -3323,6 +3323,8 @@ av1_qsv_decoder_select="qsvdec"
>  av1_qsv_encoder_select="qsvenc"
>  av1_qsv_encoder_deps="libvpl"
>  av1_amf_encoder_deps="amf"
> +av1_vaapi_encoder_deps="VAEncPictureParameterBufferAV1"
> +av1_vaapi_encoder_select="cbs_av1 vaapi_encode"
>
>  # parsers
>  aac_parser_select="adts_header mpeg4audio"
> @@ -7110,6 +7112,7 @@ if enabled vaapi; then
>  check_type "va/va.h va/va_enc_jpeg.h" "VAEncPictureParameterBufferJPEG"
>  check_type "va/va.h va/va_enc_vp8.h"  "VAEncPictureParameterBufferVP8"
>  check_type "va/va.h va/va_enc_vp9.h"  "VAEncPictureParameterBufferVP9"
> +check_type "va/va.h va/va_enc_av1.h"  "VAEncPictureParameterBufferAV1"
>  fi
>
>  if enabled_all opencl libdrm ; then
> diff --git a/doc/encoders.texi b/doc/encoders.texi
> index 6f8f5e127e..d7d9584a0c 100644
> --- a/doc/encoders.texi
> +++ b/doc/encoders.texi
> @@ -3995,6 +3995,20 @@ Average variable bitrate.
>  Each encoder also has its own specific options:
>  @table @option
>
> +@item av1_vaapi
> +@option{profile} sets the value of @emph{seq_profile}.
> +@option{tier} sets the value of @emph{seq_tier}.
> +@option{level} sets the value of @emph{seq_level_idx}.
> +
> +@table @option
> +@item tiles
> +Set the number of tiles to encode the input video with, as columns x rows.
> +(default is auto, which means use minimal tile column/row number).
> +@item tile_groups
> +Set tile groups number. All the tiles will be distributed as evenly as 
> possible to
> +each tile group. (default is 1).
> +@end table
> +
>  @item h264_vaapi
>  @option{profile} sets the value of @emph{profile_idc} and the 
> @emph{constraint_set*_flag}s.
>  @option{level} sets the value of @emph{level_idc}.
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index bf3b0a93f9..cae2e773a1 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -258,6 +258,7 @@ OBJS-$(CONFIG_AV1_MEDIACODEC_DECODER)  += mediacodecdec.o
>  OBJS-$(CONFIG_AV1_MEDIACODEC_ENCODER)  += mediacodecenc.o
>  OBJS-$(CONFIG_AV1_NVENC_ENCODER)   += nvenc_av1.o nvenc.o
>  OBJS-$(CONFIG_AV1_QSV_ENCODER) += qsvenc_av1.o
> +OBJS-$(CONFIG_AV1_VAAPI_ENCODER)   += vaapi_encode_av1.o av1_levels.o
>  OBJS-$(CONFIG_AVRN_DECODER)+= avrndec.o
>  OBJS-$(CONFIG_AVRP_DECODER)+= r210dec.o
>  OBJS-$(CONFIG_AVRP_ENCODER)+= r210enc.o
> @@ -1322,6 +1323,7 @@ TESTPROGS = avcodec 
> \
>  jpeg2000dwt \
>  mathops\
>
> +TESTPROGS-$(CONFIG_AV1_VAAPI_ENCODER) += av1_levels
>  TESTPROGS-$(CONFIG_CABAC) += cabac
>  TESTPROGS-$(CONFIG_DCT)   += avfft
>  TESTPROGS-$(CONFIG_FFT)   += fft fft-fixed32
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index 6e95ca5636..5136a566f1 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -845,6 +845,7 @@ extern const FFCodec ff_av1_nvenc_encoder;
>  extern const FFCodec ff_av1_qsv_decoder;
>  extern const FFCodec ff_av1_qsv_encoder;
>  extern const FFCodec ff_av1_amf_encoder;
> +extern const FFCodec ff_av1_vaapi_encoder;
>  extern const FFCodec ff_libopenh264_encoder;
>  extern const FFCodec ff_libopenh264_decoder;
>  extern const FFCodec ff_h264_amf_encoder;
> diff --git a/libavcodec/av1_levels.c b/libavcodec/av1_levels.c
> new file mode 100644
> index 00..19b6ee1736
> --- /dev/null
> +++ b/libavcodec/av1_levels.c
> @@ -0,0 +1,92 @@
> +/*
> + * Copyright (c) 2023 Intel Corporation
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free 

Re: [FFmpeg-devel] [PATCH v5 6/8] lavc/vaapi_encode: Separate reference frame into previous/future list

2023-09-19 Thread Neal Gompa
On Mon, Sep 11, 2023 at 3:54 AM  wrote:
>
> From: Fei Wang 
>
> To support more reference frames from different directions.
>
> Signed-off-by: Fei Wang 
> ---
>  libavcodec/vaapi_encode.c   | 112 +---
>  libavcodec/vaapi_encode.h   |  15 +++--
>  libavcodec/vaapi_encode_h264.c  |  94 +--
>  libavcodec/vaapi_encode_h265.c  |  76 +-
>  libavcodec/vaapi_encode_mpeg2.c |   6 +-
>  libavcodec/vaapi_encode_vp8.c   |   6 +-
>  libavcodec/vaapi_encode_vp9.c   |  26 
>  7 files changed, 208 insertions(+), 127 deletions(-)
>
> diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c
> index 46762342eb..79036673e7 100644
> --- a/libavcodec/vaapi_encode.c
> +++ b/libavcodec/vaapi_encode.c
> @@ -276,21 +276,34 @@ static int vaapi_encode_issue(AVCodecContext *avctx,
>  av_log(avctx, AV_LOG_DEBUG, "Issuing encode for pic %"PRId64"/%"PRId64" "
> "as type %s.\n", pic->display_order, pic->encode_order,
> picture_type_name[pic->type]);
> -if (pic->nb_refs == 0) {
> +if (pic->nb_refs[0] == 0 && pic->nb_refs[1] == 0) {
>  av_log(avctx, AV_LOG_DEBUG, "No reference pictures.\n");
>  } else {
> -av_log(avctx, AV_LOG_DEBUG, "Refers to:");
> -for (i = 0; i < pic->nb_refs; i++) {
> +av_log(avctx, AV_LOG_DEBUG, "L0 refers to");
> +for (i = 0; i < pic->nb_refs[0]; i++) {
>  av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64,
> -   pic->refs[i]->display_order, pic->refs[i]->encode_order);
> +   pic->refs[0][i]->display_order, 
> pic->refs[0][i]->encode_order);
>  }
>  av_log(avctx, AV_LOG_DEBUG, ".\n");
> +
> +if (pic->nb_refs[1]) {
> +av_log(avctx, AV_LOG_DEBUG, "L1 refers to");
> +for (i = 0; i < pic->nb_refs[1]; i++) {
> +av_log(avctx, AV_LOG_DEBUG, " %"PRId64"/%"PRId64,
> +   pic->refs[1][i]->display_order, 
> pic->refs[1][i]->encode_order);
> +}
> +av_log(avctx, AV_LOG_DEBUG, ".\n");
> +}
>  }
>
>  av_assert0(!pic->encode_issued);
> -for (i = 0; i < pic->nb_refs; i++) {
> -av_assert0(pic->refs[i]);
> -av_assert0(pic->refs[i]->encode_issued);
> +for (i = 0; i < pic->nb_refs[0]; i++) {
> +av_assert0(pic->refs[0][i]);
> +av_assert0(pic->refs[0][i]->encode_issued);
> +}
> +for (i = 0; i < pic->nb_refs[1]; i++) {
> +av_assert0(pic->refs[1][i]);
> +av_assert0(pic->refs[1][i]->encode_issued);
>  }
>
>  av_log(avctx, AV_LOG_DEBUG, "Input surface is %#x.\n", 
> pic->input_surface);
> @@ -832,8 +845,12 @@ static void vaapi_encode_add_ref(AVCodecContext *avctx,
>
>  if (is_ref) {
>  av_assert0(pic != target);
> -av_assert0(pic->nb_refs < MAX_PICTURE_REFERENCES);
> -pic->refs[pic->nb_refs++] = target;
> +av_assert0(pic->nb_refs[0] < MAX_PICTURE_REFERENCES &&
> +   pic->nb_refs[1] < MAX_PICTURE_REFERENCES);
> +if (target->display_order < pic->display_order)
> +pic->refs[0][pic->nb_refs[0]++] = target;
> +else
> +pic->refs[1][pic->nb_refs[1]++] = target;
>  ++refs;
>  }
>
> @@ -862,10 +879,16 @@ static void vaapi_encode_remove_refs(AVCodecContext 
> *avctx,
>  if (pic->ref_removed[level])
>  return;
>
> -for (i = 0; i < pic->nb_refs; i++) {
> -av_assert0(pic->refs[i]);
> ---pic->refs[i]->ref_count[level];
> -av_assert0(pic->refs[i]->ref_count[level] >= 0);
> +for (i = 0; i < pic->nb_refs[0]; i++) {
> +av_assert0(pic->refs[0][i]);
> +--pic->refs[0][i]->ref_count[level];
> +av_assert0(pic->refs[0][i]->ref_count[level] >= 0);
> +}
> +
> +for (i = 0; i < pic->nb_refs[1]; i++) {
> +av_assert0(pic->refs[1][i]);
> +--pic->refs[1][i]->ref_count[level];
> +av_assert0(pic->refs[1][i]->ref_count[level] >= 0);
>  }
>
>  for (i = 0; i < pic->nb_dpb_pics; i++) {
> @@ -910,7 +933,7 @@ static void vaapi_encode_set_b_pictures(AVCodecContext 
> *avctx,
>  vaapi_encode_add_ref(avctx, pic, end,   1, 1, 0);
>  vaapi_encode_add_ref(avctx, pic, prev,  0, 0, 1);
>
> -for (ref = end->refs[1]; ref; ref = ref->refs[1])
> +for (ref = end->refs[1][0]; ref; ref = ref->refs[1][0])
>  vaapi_encode_add_ref(avctx, pic, ref, 0, 1, 0);
>  }
>  *last = prev;
> @@ -933,7 +956,7 @@ static void vaapi_encode_set_b_pictures(AVCodecContext 
> *avctx,
>  vaapi_encode_add_ref(avctx, pic, end,   1, 1, 0);
>  vaapi_encode_add_ref(avctx, pic, prev,  0, 0, 1);
>
> -for (ref = end->refs[1]; ref; ref = ref->refs[1])
> +for (ref = end->refs[1][0]; ref; ref = ref->refs[1][0])
>  vaapi_encode_add_ref(avctx, pic, ref, 0, 1, 0);
>
>  if (i > 1)
> @@ 

Re: [FFmpeg-devel] [PATCH v5 5/8] lavc/vaapi_encode: Extract set output pkt property function

2023-09-19 Thread Neal Gompa
On Mon, Sep 11, 2023 at 3:53 AM  wrote:
>
> From: Fei Wang 
>
> Signed-off-by: Fei Wang 
> ---
>  libavcodec/vaapi_encode.c | 65 +++
>  1 file changed, 38 insertions(+), 27 deletions(-)
>
> diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c
> index 5ae63c9f25..46762342eb 100644
> --- a/libavcodec/vaapi_encode.c
> +++ b/libavcodec/vaapi_encode.c
> @@ -650,6 +650,41 @@ fail_at_end:
>  return err;
>  }
>
> +static int vaapi_encode_set_output_property(AVCodecContext *avctx,
> +VAAPIEncodePicture *pic,
> +AVPacket *pkt)
> +{
> +VAAPIEncodeContext *ctx = avctx->priv_data;
> +
> +if (pic->type == PICTURE_TYPE_IDR)
> +pkt->flags |= AV_PKT_FLAG_KEY;
> +
> +pkt->pts = pic->pts;
> +pkt->duration = pic->duration;
> +
> +// for no-delay encoders this is handled in generic codec
> +if (avctx->codec->capabilities & AV_CODEC_CAP_DELAY &&
> +avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) {
> +pkt->opaque = pic->opaque;
> +pkt->opaque_ref = pic->opaque_ref;
> +pic->opaque_ref = NULL;
> +}
> +
> +if (ctx->output_delay == 0) {
> +pkt->dts = pkt->pts;
> +} else if (pic->encode_order < ctx->decode_delay) {
> +if (ctx->ts_ring[pic->encode_order] < INT64_MIN + ctx->dts_pts_diff)
> +pkt->dts = INT64_MIN;
> +else
> +pkt->dts = ctx->ts_ring[pic->encode_order] - ctx->dts_pts_diff;
> +} else {
> +pkt->dts = ctx->ts_ring[(pic->encode_order - ctx->decode_delay) %
> +(3 * ctx->output_delay + ctx->async_depth)];
> +}
> +
> +return 0;
> +}
> +
>  static int vaapi_encode_output(AVCodecContext *avctx,
> VAAPIEncodePicture *pic, AVPacket *pkt)
>  {
> @@ -691,12 +726,6 @@ static int vaapi_encode_output(AVCodecContext *avctx,
>  ptr += buf->size;
>  }
>
> -if (pic->type == PICTURE_TYPE_IDR)
> -pkt->flags |= AV_PKT_FLAG_KEY;
> -
> -pkt->pts = pic->pts;
> -pkt->duration = pic->duration;
> -
>  vas = vaUnmapBuffer(ctx->hwctx->display, pic->output_buffer);
>  if (vas != VA_STATUS_SUCCESS) {
>  av_log(avctx, AV_LOG_ERROR, "Failed to unmap output buffers: "
> @@ -705,14 +734,6 @@ static int vaapi_encode_output(AVCodecContext *avctx,
>  goto fail;
>  }
>
> -// for no-delay encoders this is handled in generic codec
> -if (avctx->codec->capabilities & AV_CODEC_CAP_DELAY &&
> -avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) {
> -pkt->opaque = pic->opaque;
> -pkt->opaque_ref = pic->opaque_ref;
> -pic->opaque_ref = NULL;
> -}
> -
>  av_buffer_unref(>output_buffer_ref);
>  pic->output_buffer = VA_INVALID_ID;
>
> @@ -1273,19 +1294,9 @@ int ff_vaapi_encode_receive_packet(AVCodecContext 
> *avctx, AVPacket *pkt)
>  return err;
>  }
>
> -if (ctx->output_delay == 0) {
> -pkt->dts = pkt->pts;
> -} else if (pic->encode_order < ctx->decode_delay) {
> -if (ctx->ts_ring[pic->encode_order] < INT64_MIN + ctx->dts_pts_diff)
> -pkt->dts = INT64_MIN;
> -else
> -pkt->dts = ctx->ts_ring[pic->encode_order] - ctx->dts_pts_diff;
> -} else {
> -pkt->dts = ctx->ts_ring[(pic->encode_order - ctx->decode_delay) %
> -(3 * ctx->output_delay + ctx->async_depth)];
> -}
> -av_log(avctx, AV_LOG_DEBUG, "Output packet: pts %"PRId64" dts 
> %"PRId64".\n",
> -   pkt->pts, pkt->dts);
> +vaapi_encode_set_output_property(avctx, pic, pkt);
> +av_log(avctx, AV_LOG_DEBUG, "Output packet: pts %"PRId64", dts 
> %"PRId64", "
> +   "size %d bytes.\n", pkt->pts, pkt->dts, pkt->size);
>
>  ctx->output_order = pic->encode_order;
>  vaapi_encode_clear_old(avctx);
> --
> 2.25.1
>

LGTM.

Reviewed-by: Neal Gompa 



-- 
真実はいつも一つ!/ Always, there's only one truth!
___
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".


Re: [FFmpeg-devel] [PATCH v5 4/8] lavc/vaapi_encode: Init pic at the beginning of API

2023-09-19 Thread Neal Gompa
On Mon, Sep 11, 2023 at 3:53 AM  wrote:
>
> From: Fei Wang 
>
> Signed-off-by: Fei Wang 
> ---
>  libavcodec/vaapi_encode.c | 5 +
>  1 file changed, 1 insertion(+), 4 deletions(-)
>
> diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c
> index 0316fe5c18..5ae63c9f25 100644
> --- a/libavcodec/vaapi_encode.c
> +++ b/libavcodec/vaapi_encode.c
> @@ -1205,7 +1205,7 @@ fail:
>  int ff_vaapi_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
>  {
>  VAAPIEncodeContext *ctx = avctx->priv_data;
> -VAAPIEncodePicture *pic;
> +VAAPIEncodePicture *pic = NULL;
>  AVFrame *frame = ctx->frame;
>  int err;
>
> @@ -1228,8 +1228,6 @@ int ff_vaapi_encode_receive_packet(AVCodecContext 
> *avctx, AVPacket *pkt)
>  }
>
>  if (ctx->has_sync_buffer_func) {
> -pic = NULL;
> -
>  if (av_fifo_can_write(ctx->encode_fifo)) {
>  err = vaapi_encode_pick_next(avctx, );
>  if (!err) {
> @@ -1255,7 +1253,6 @@ int ff_vaapi_encode_receive_packet(AVCodecContext 
> *avctx, AVPacket *pkt)
>  av_fifo_read(ctx->encode_fifo, , 1);
>  ctx->encode_order = pic->encode_order + 1;
>  } else {
> -pic = NULL;
>  err = vaapi_encode_pick_next(avctx, );
>  if (err < 0)
>  return err;
> --
> 2.25.1
>

LGTM and existing VAAPI stuff works.

Reviewed-by: Neal Gompa 



-- 
真実はいつも一つ!/ Always, there's only one truth!
___
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".


Re: [FFmpeg-devel] [PATCH v5 1/8] avcodec/cbs_av1: Add tx mode enum values

2023-09-19 Thread Neal Gompa
On Tue, Sep 19, 2023 at 8:40 PM Neal Gompa  wrote:
>
> On Mon, Sep 11, 2023 at 3:52 AM  wrote:
> >
> > From: Fei Wang 
> >
> > Signed-off-by: Fei Wang 
> > ---
> >  libavcodec/av1.h | 7 +++
> >  libavcodec/cbs_av1_syntax_template.c | 4 ++--
> >  2 files changed, 9 insertions(+), 2 deletions(-)
> >
> > diff --git a/libavcodec/av1.h b/libavcodec/av1.h
> > index 384f7cddc7..8704bc41c1 100644
> > --- a/libavcodec/av1.h
> > +++ b/libavcodec/av1.h
> > @@ -175,6 +175,13 @@ enum {
> >  AV1_RESTORE_SWITCHABLE = 3,
> >  };
> >
> > +// TX mode (section 6.8.21)
> > +enum {
> > +AV1_ONLY_4X4= 0,
> > +AV1_TX_MODE_LARGEST = 1,
> > +AV1_TX_MODE_SELECT  = 2,
> > +};
> > +
> >  // Sequence Headers are actually unbounded because one can use
> >  // an arbitrary number of leading zeroes when encoding via uvlc.
> >  // The following estimate is based around using the lowest number
> > diff --git a/libavcodec/cbs_av1_syntax_template.c 
> > b/libavcodec/cbs_av1_syntax_template.c
> > index 6f09c4e410..3be1f2d30f 100644
> > --- a/libavcodec/cbs_av1_syntax_template.c
> > +++ b/libavcodec/cbs_av1_syntax_template.c
> > @@ -1028,9 +1028,9 @@ static int FUNC(read_tx_mode)(CodedBitstreamContext 
> > *ctx, RWContext *rw,
> >  int err;
> >
> >  if (priv->coded_lossless)
> > -infer(tx_mode, 0);
> > +infer(tx_mode, AV1_ONLY_4X4);
> >  else
> > -increment(tx_mode, 1, 2);
> > +increment(tx_mode, AV1_TX_MODE_LARGEST, AV1_TX_MODE_SELECT);
> >
> >  return 0;
> >  }
> > --
> > 2.25.1
> >
>
> Code looks good to me, I just lack hardware to exercise the functionality.
>
> Acked-by: Neal Gompa 
>

Actually, update this now that I'm giving feedback for each patch individually.

This patch is fine and works with my existing software AV1 path, so...

Reviewed-by: Neal Gompa 


-- 
真実はいつも一つ!/ Always, there's only one truth!
___
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".


Re: [FFmpeg-devel] [PATCH v5 3/8] avcodec/cbs_av1: Allow specifying obu size byte length

2023-09-19 Thread Neal Gompa
On Mon, Sep 11, 2023 at 3:53 AM  wrote:
>
> From: Fei Wang 
>
> Signed-off-by: Fei Wang 
> ---
>  libavcodec/cbs_av1.c | 30 +-
>  libavcodec/cbs_av1.h |  1 +
>  2 files changed, 22 insertions(+), 9 deletions(-)
>
> diff --git a/libavcodec/cbs_av1.c b/libavcodec/cbs_av1.c
> index 6c478603f1..4e687ace79 100644
> --- a/libavcodec/cbs_av1.c
> +++ b/libavcodec/cbs_av1.c
> @@ -138,15 +138,19 @@ static int cbs_av1_read_leb128(CodedBitstreamContext 
> *ctx, GetBitContext *gbc,
>  return 0;
>  }
>
> +/** Minimum byte length will be used to indicate the len128 of value if 
> byte_len is 0. */
>  static int cbs_av1_write_leb128(CodedBitstreamContext *ctx, PutBitContext 
> *pbc,
> -const char *name, uint64_t value)
> +const char *name, uint64_t value, uint8_t 
> byte_len)
>  {
>  int len, i;
>  uint8_t byte;
>
>  CBS_TRACE_WRITE_START();
>
> -len = (av_log2(value) + 7) / 7;
> +if (byte_len)
> +av_assert0(byte_len >= (av_log2(value) + 7) / 7);
> +
> +len = byte_len ? byte_len : (av_log2(value) + 7) / 7;
>
>  for (i = 0; i < len; i++) {
>  if (put_bits_left(pbc) < 8)
> @@ -618,7 +622,7 @@ static size_t 
> cbs_av1_get_payload_bytes_left(GetBitContext *gbc)
>  } while (0)
>
>  #define leb128(name) do { \
> -CHECK(cbs_av1_write_leb128(ctx, rw, #name, current->name)); \
> +CHECK(cbs_av1_write_leb128(ctx, rw, #name, current->name, 0)); \
>  } while (0)
>
>  #define infer(name, value) do { \
> @@ -1002,9 +1006,14 @@ static int cbs_av1_write_obu(CodedBitstreamContext 
> *ctx,
>
>  if (obu->header.obu_has_size_field) {
>  pbc_tmp = *pbc;
> -// Add space for the size field to fill later.
> -put_bits32(pbc, 0);
> -put_bits32(pbc, 0);
> +if (obu->obu_size_byte_len) {
> +for (int i = 0; i < obu->obu_size_byte_len; i++)
> +put_bits(pbc, 8, 0);
> +} else {
> +// Add space for the size field to fill later.
> +put_bits32(pbc, 0);
> +put_bits32(pbc, 0);
> +}
>  }
>
>  td = NULL;
> @@ -1124,7 +1133,7 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
>  end_pos   /= 8;
>
>  *pbc = pbc_tmp;
> -err = cbs_av1_write_leb128(ctx, pbc, "obu_size", obu->obu_size);
> +err = cbs_av1_write_leb128(ctx, pbc, "obu_size", obu->obu_size, 
> obu->obu_size_byte_len);
>  if (err < 0)
>  goto error;
>
> @@ -1141,8 +1150,11 @@ static int cbs_av1_write_obu(CodedBitstreamContext 
> *ctx,
>  }
>
>  if (obu->obu_size > 0) {
> -memmove(pbc->buf + data_pos,
> -pbc->buf + start_pos, header_size);
> +if (!obu->obu_size_byte_len) {
> +obu->obu_size_byte_len = start_pos - data_pos;
> +memmove(pbc->buf + data_pos,
> +pbc->buf + start_pos, header_size);
> +}
>  skip_put_bytes(pbc, header_size);
>
>  if (td) {
> diff --git a/libavcodec/cbs_av1.h b/libavcodec/cbs_av1.h
> index 64dfdce9c4..a9e2d2284f 100644
> --- a/libavcodec/cbs_av1.h
> +++ b/libavcodec/cbs_av1.h
> @@ -401,6 +401,7 @@ typedef struct AV1RawOBU {
>  AV1RawOBUHeader header;
>
>  size_t obu_size;
> +uint8_t obu_size_byte_len;
>
>  union {
>  AV1RawSequenceHeader sequence_header;
> --
> 2.25.1
>

Code looks good to me.

Reviewed-by: Neal Gompa 



-- 
真実はいつも一つ!/ Always, there's only one truth!
___
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".


Re: [FFmpeg-devel] [PATCH v5 2/8] cbs: Make tracing more general

2023-09-19 Thread Neal Gompa
On Mon, Sep 11, 2023 at 3:53 AM  wrote:
>
> From: Mark Thompson 
>
> Turn tracing into callbacks for each syntax element, with default
> callbacks to match current trace_headers behaviour for debug.  Move
> the construction of bit strings into the trace callback, which
> simplifies all of the read and write functions.
>
> Signed-off-by: Fei Wang 
> ---
>  libavcodec/cbs.c   | 121 +--
>  libavcodec/cbs.h   |  88 +-
>  libavcodec/cbs_av1.c   | 206 +
>  libavcodec/cbs_bsf.c   |   5 +
>  libavcodec/cbs_h2645.c | 134 +
>  libavcodec/cbs_internal.h  |  85 +-
>  libavcodec/cbs_vp9.c   | 108 +
>  libavcodec/trace_headers_bsf.c |   2 +
>  8 files changed, 373 insertions(+), 376 deletions(-)
>
> diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c
> index 3ec8285e21..daf7f66427 100644
> --- a/libavcodec/cbs.c
> +++ b/libavcodec/cbs.c
> @@ -117,8 +117,9 @@ av_cold int ff_cbs_init(CodedBitstreamContext **ctx_ptr,
>
>  ctx->decompose_unit_types = NULL;
>
> -ctx->trace_enable = 0;
> -ctx->trace_level  = AV_LOG_TRACE;
> +ctx->trace_enable  = 0;
> +ctx->trace_level   = AV_LOG_TRACE;
> +ctx->trace_context = ctx;
>
>  *ctx_ptr = ctx;
>  return 0;
> @@ -496,19 +497,27 @@ void ff_cbs_trace_header(CodedBitstreamContext *ctx,
>  av_log(ctx->log_ctx, ctx->trace_level, "%s\n", name);
>  }
>
> -void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position,
> - const char *str, const int *subscripts,
> - const char *bits, int64_t value)
> +void ff_cbs_trace_read_log(void *trace_context,
> +   GetBitContext *gbc, int length,
> +   const char *str, const int *subscripts,
> +   int64_t value)
>  {
> +CodedBitstreamContext *ctx = trace_context;
>  char name[256];
> +char bits[256];
>  size_t name_len, bits_len;
>  int pad, subs, i, j, k, n;
> -
> -if (!ctx->trace_enable)
> -return;
> +int position;
>
>  av_assert0(value >= INT_MIN && value <= UINT32_MAX);
>
> +position = get_bits_count(gbc);
> +
> +av_assert0(length < 256);
> +for (i = 0; i < length; i++)
> +bits[i] = get_bits1(gbc) ? '1' : '0';
> +bits[length] = 0;
> +
>  subs = subscripts ? subscripts[0] : 0;
>  n = 0;
>  for (i = j = 0; str[i];) {
> @@ -535,7 +544,7 @@ void ff_cbs_trace_syntax_element(CodedBitstreamContext 
> *ctx, int position,
>  av_assert0(n == subs);
>
>  name_len = strlen(name);
> -bits_len = strlen(bits);
> +bits_len = length;
>
>  if (name_len + bits_len > 60)
>  pad = bits_len + 2;
> @@ -546,6 +555,36 @@ void ff_cbs_trace_syntax_element(CodedBitstreamContext 
> *ctx, int position,
> position, name, pad, bits, value);
>  }
>
> +void ff_cbs_trace_write_log(void *trace_context,
> +PutBitContext *pbc, int length,
> +const char *str, const int *subscripts,
> +int64_t value)
> +{
> +CodedBitstreamContext *ctx = trace_context;
> +
> +// Ensure that the syntax element is written to the output buffer,
> +// make a GetBitContext pointed at the start position, then call the
> +// read log function which can read the bits back to log them.
> +
> +GetBitContext gbc;
> +int position;
> +
> +if (length > 0) {
> +PutBitContext flush;
> +flush = *pbc;
> +flush_put_bits();
> +}
> +
> +position = put_bits_count(pbc);
> +av_assert0(position >= length);
> +
> +init_get_bits(, pbc->buf, position);
> +
> +skip_bits_long(, position - length);
> +
> +ff_cbs_trace_read_log(ctx, , length, str, subscripts, value);
> +}
> +
>  static av_always_inline int cbs_read_unsigned(CodedBitstreamContext *ctx,
>GetBitContext *gbc,
>int width, const char *name,
> @@ -555,7 +594,8 @@ static av_always_inline int 
> cbs_read_unsigned(CodedBitstreamContext *ctx,
>uint32_t range_max)
>  {
>  uint32_t value;
> -int position;
> +
> +CBS_TRACE_READ_START();
>
>  av_assert0(width > 0 && width <= 32);
>
> @@ -565,21 +605,9 @@ static av_always_inline int 
> cbs_read_unsigned(CodedBitstreamContext *ctx,
>  return AVERROR_INVALIDDATA;
>  }
>
> -if (ctx->trace_enable)
> -position = get_bits_count(gbc);
> -
>  value = get_bits_long(gbc, width);
>
> -if (ctx->trace_enable) {
> -char bits[33];
> -int i;
> -for (i = 0; i < width; i++)
> -bits[i] = value >> (width - i - 1) & 1 ? '1' : '0';
> -bits[i] = 0;
> -
> -ff_cbs_trace_syntax_element(ctx, position, name, 

Re: [FFmpeg-devel] [PATCH v5 1/8] avcodec/cbs_av1: Add tx mode enum values

2023-09-19 Thread Neal Gompa
On Mon, Sep 11, 2023 at 3:52 AM  wrote:
>
> From: Fei Wang 
>
> Signed-off-by: Fei Wang 
> ---
>  libavcodec/av1.h | 7 +++
>  libavcodec/cbs_av1_syntax_template.c | 4 ++--
>  2 files changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/libavcodec/av1.h b/libavcodec/av1.h
> index 384f7cddc7..8704bc41c1 100644
> --- a/libavcodec/av1.h
> +++ b/libavcodec/av1.h
> @@ -175,6 +175,13 @@ enum {
>  AV1_RESTORE_SWITCHABLE = 3,
>  };
>
> +// TX mode (section 6.8.21)
> +enum {
> +AV1_ONLY_4X4= 0,
> +AV1_TX_MODE_LARGEST = 1,
> +AV1_TX_MODE_SELECT  = 2,
> +};
> +
>  // Sequence Headers are actually unbounded because one can use
>  // an arbitrary number of leading zeroes when encoding via uvlc.
>  // The following estimate is based around using the lowest number
> diff --git a/libavcodec/cbs_av1_syntax_template.c 
> b/libavcodec/cbs_av1_syntax_template.c
> index 6f09c4e410..3be1f2d30f 100644
> --- a/libavcodec/cbs_av1_syntax_template.c
> +++ b/libavcodec/cbs_av1_syntax_template.c
> @@ -1028,9 +1028,9 @@ static int FUNC(read_tx_mode)(CodedBitstreamContext 
> *ctx, RWContext *rw,
>  int err;
>
>  if (priv->coded_lossless)
> -infer(tx_mode, 0);
> +infer(tx_mode, AV1_ONLY_4X4);
>  else
> -increment(tx_mode, 1, 2);
> +increment(tx_mode, AV1_TX_MODE_LARGEST, AV1_TX_MODE_SELECT);
>
>  return 0;
>  }
> --
> 2.25.1
>

Code looks good to me, I just lack hardware to exercise the functionality.

Acked-by: Neal Gompa 



-- 
真実はいつも一つ!/ Always, there's only one truth!
___
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".


Re: [FFmpeg-devel] FFmpeg release 6.1

2023-09-19 Thread Neal Gompa
On Tue, Sep 19, 2023 at 5:58 PM Lynne  wrote:
>
> Sep 19, 2023, 21:16 by mich...@niedermayer.cc:
>
> > On Tue, Sep 19, 2023 at 07:18:03PM +0200, Niklas Haas wrote:
> >
> >> On Tue, 11 Apr 2023 00:14:28 +0200 Michael Niedermayer 
> >>  wrote:
> >> > Hi all
> >> >
> >> > There was the request to make a 6.1 before end of April
> >> > Is that still so ?
> >> >
> >> > Assuming it is, its time to make that branch and release soon
> >>
> >> Hi,
> >>
> >> It is now september. What happened to this release? FFmpeg 6.1 is
> >> currently the only thing blocking the adoption of vulkan video.
> >>
> >
> > there are several security issues that need to be fixed
> > ossfuzz found more, it also put some random unlreated issues again
> > into the same ticket. (which are basically invissible sub-tickets)
> > the evc code also needs a security review, Maybe Dawid is working on this
> > iam not sure. And iam sure theres more
> > We also have a security issue in fate, i belive nicolas is looking into
> > that, that doesnt hold up the release but all these things compete for time
> > and some people you may have noticed tried to just randomly block patches
> > going back and forth on these and discussing with tech/community committtees
> > also took time.
> > And last but not least if people want me to design a standalone SDR library
> > while thats not holding up 6.1 it takes time from the pot from 6.1 work.
> > I did say this, i was attacked but yes time is unforgiving it doesnt care
> >
> > Also I did fall behind with security fixes in the summer a bit, the weather 
> > was
> > nice, some members of the community where not nice. So i tried to spend some
> > time with the nice weather
> >
> > If you want 6.1 to happen quick. be nice to me or help with anything that i
> > have to work on 6.1 or other so theres more time in the pot
> > what about merging libplacebo into FFmpeg for example ?
> > As far as iam concerned you can have absolute final power about anything
> > in that libplacebo inside FFmpeg.
> > Or help with the whole SDR thing. If i dont have to think about it and
> > can concentrate on the release and security then yes it will happen faster
> >
> > I also have some paid work under NDA which i signed a contract for, i need
> > to work on that too. Yes code will be submitted to FFmpeg when/if its done
> > And theres life, i have other shit to do too. For example my taxes and i 
> > also
> > want to spend some time working on AI/neural nets. I guess that will not be
> > FFmpeg related as id like my work on AI not to be in a similar position to
> > where avradio is now.
> >
> > So yeah, i think theres no problem with 6.1 its just not happening as quick
> > as I and others wanted
> >
> > thx
> >
> > [...]
> > --
> > Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
> >
> > If you think the mosad wants you dead since a long time then you are either
> > wrong or dead since a long time.
> >
>
> I'm not sure it's a good idea to wait to merge the EVC decoder.
> Perhaps we should move that to the next release.
>
> I'd like to get my AAC padding/duration fixes in, and drop lavc's
> old FFT code entirely.

From my wishlist, the only thing left unmerged is AV1 VA-API encode
support. The patchset is on v5 now and seems to be fine? I can't test
it due to lack of compatible hardware, so if someone here does have
something and can do it, it'd be great to see it get reviewed and
landed.



-- 
真実はいつも一つ!/ Always, there's only one truth!
___
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".


[FFmpeg-devel] [PATCH 5/5] avformat/avs: Check if return code is representable

2023-09-19 Thread Michael Niedermayer
Fixes: leak
Fixes: 
62164/clusterfuzz-testcase-minimized-ffmpeg_dem_AVS_fuzzer-6738814988320768

Found-by: continuous fuzzing process 
https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer 
---
 libavformat/avs.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/libavformat/avs.c b/libavformat/avs.c
index ab47980a11c..19f03731573 100644
--- a/libavformat/avs.c
+++ b/libavformat/avs.c
@@ -140,6 +140,10 @@ static int avs_read_audio_packet(AVFormatContext * s, 
AVPacket * pkt)
 return 0;/* this indicate EOS */
 if (ret < 0)
 return ret;
+if (size != (int)size) {
+av_packet_unref(pkt);
+return AVERROR(EDOM);
+}
 
 pkt->stream_index = avs->st_audio->index;
 pkt->flags |= AV_PKT_FLAG_KEY;
-- 
2.17.1

___
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".


[FFmpeg-devel] [PATCH 4/5] avcodec/vlc: free multi on fail

2023-09-19 Thread Michael Niedermayer
Fixes: leak
Fixes: 
62164/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_UTVIDEO_fuzzer-6449246523752448

Found-by: continuous fuzzing process 
https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer 
---
 libavcodec/vlc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libavcodec/vlc.c b/libavcodec/vlc.c
index 3b66c943546..acc081e8b74 100644
--- a/libavcodec/vlc.c
+++ b/libavcodec/vlc.c
@@ -478,6 +478,7 @@ int ff_vlc_init_multi_from_lengths(VLC *vlc, VLC_MULTI 
*multi, int nb_bits, int
 fail:
 if (buf != localbuf)
 av_free(buf);
+ff_vlc_free_multi(multi);
 return AVERROR_INVALIDDATA;
 }
 
-- 
2.17.1

___
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".


[FFmpeg-devel] [PATCH 3/5] avcodec/utvideodec: move allocation to the end of init

2023-09-19 Thread Michael Niedermayer
Fixes: mem leak
Fixes: 
62164/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_UTVIDEO_fuzzer-804266926080

Found-by: continuous fuzzing process 
https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer 
---
 libavcodec/utvideodec.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/libavcodec/utvideodec.c b/libavcodec/utvideodec.c
index 7ee07209d47..4987ee0196a 100644
--- a/libavcodec/utvideodec.c
+++ b/libavcodec/utvideodec.c
@@ -985,10 +985,6 @@ static av_cold int decode_init(AVCodecContext *avctx)
 return AVERROR_INVALIDDATA;
 }
 
-c->buffer = av_calloc(avctx->width + 8, c->pro?2:1);
-if (!c->buffer)
-return AVERROR(ENOMEM);
-
 av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, _shift, _shift);
 if ((avctx->width  & ((1width + 8, c->pro?2:1);
+if (!c->buffer)
+return AVERROR(ENOMEM);
+
 return 0;
 }
 
-- 
2.17.1

___
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".


[FFmpeg-devel] [PATCH 2/5] avcodec/flacdec: Fix integer overflow in "33bit" DECODER_SUBFRAME_FIXED_WIDE()

2023-09-19 Thread Michael Niedermayer
Fixes: signed integer overflow: 4 * 2307917133220067266 cannot be represented 
in type 'long'
Fixes: 
62164/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_FLAC_fuzzer-6307690022043648

Found-by: continuous fuzzing process 
https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer 
---
 libavcodec/flacdec.c | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/libavcodec/flacdec.c b/libavcodec/flacdec.c
index 0569f019b3a..ed2de14d0a9 100644
--- a/libavcodec/flacdec.c
+++ b/libavcodec/flacdec.c
@@ -366,19 +366,19 @@ static int decode_subframe_fixed(FLACContext *s, int32_t 
*decoded,
 break;\
 case 1:   \
 for (int i = pred_order; i < blocksize; i++)  \
-decoded[i] = (int64_t)residual[i] + (int64_t)decoded[i-1];\
+decoded[i] = (uint64_t)residual[i] + (uint64_t)decoded[i-1];\
 break;\
 case 2:   \
 for (int i = pred_order; i < blocksize; i++)  \
-decoded[i] = (int64_t)residual[i] + 2*(int64_t)decoded[i-1] - 
(int64_t)decoded[i-2];  \
+decoded[i] = (uint64_t)residual[i] + 2*(uint64_t)decoded[i-1] - 
(uint64_t)decoded[i-2];  \
 break;\
 case 3:   \
 for (int i = pred_order; i < blocksize; i++)  \
-decoded[i] = (int64_t)residual[i] + 3*(int64_t)decoded[i-1] - 
3*(int64_t)decoded[i-2] + (int64_t)decoded[i-3];   \
+decoded[i] = (uint64_t)residual[i] + 3*(uint64_t)decoded[i-1] - 
3*(uint64_t)decoded[i-2] + (uint64_t)decoded[i-3];   \
 break;\
 case 4:   \
 for (int i = pred_order; i < blocksize; i++)  \
-decoded[i] = (int64_t)residual[i] + 4*(int64_t)decoded[i-1] - 
6*(int64_t)decoded[i-2] + 4*(int64_t)decoded[i-3] - (int64_t)decoded[i-4];   \
+decoded[i] = (uint64_t)residual[i] + 4*(uint64_t)decoded[i-1] - 
6*(uint64_t)decoded[i-2] + 4*(uint64_t)decoded[i-3] - (uint64_t)decoded[i-4];   
\
 break;\
 default:  \
 av_log(s->avctx, AV_LOG_ERROR, "illegal pred order %d\n", pred_order); 
  \
-- 
2.17.1

___
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".


[FFmpeg-devel] [PATCH 1/5] avcodec/flacdec: Fix overflow in "33bit" decorrelate

2023-09-19 Thread Michael Niedermayer
Fixes: signed integer overflow: 538976288 - -9223372036854775808 cannot be 
represented in type 'long'
Fixes: 
62164/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_FLAC_fuzzer-6275845531238400

Found-by: continuous fuzzing process 
https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer 
---
 libavcodec/flacdec.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libavcodec/flacdec.c b/libavcodec/flacdec.c
index 524a0469495..0569f019b3a 100644
--- a/libavcodec/flacdec.c
+++ b/libavcodec/flacdec.c
@@ -706,10 +706,10 @@ static void decorrelate_33bps(int ch_mode, int32_t 
**decoded, int64_t *decoded_3
 int i;
 if (ch_mode == FLAC_CHMODE_LEFT_SIDE ) {
 for (i = 0; i < len; i++)
-   decoded[1][i] = decoded[0][i] - decoded_33bps[i];
+   decoded[1][i] = decoded[0][i] - (uint64_t)decoded_33bps[i];
 } else if (ch_mode == FLAC_CHMODE_RIGHT_SIDE ) {
 for (i = 0; i < len; i++)
-   decoded[0][i] = decoded[1][i] + decoded_33bps[i];
+   decoded[0][i] = decoded[1][i] + (uint64_t)decoded_33bps[i];
 } else if (ch_mode == FLAC_CHMODE_MID_SIDE ) {
 for (i = 0; i < len; i++) {
 uint64_t a = decoded[0][i];
-- 
2.17.1

___
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".


Re: [FFmpeg-devel] FFmpeg release 6.1

2023-09-19 Thread Lynne
Sep 19, 2023, 21:16 by mich...@niedermayer.cc:

> On Tue, Sep 19, 2023 at 07:18:03PM +0200, Niklas Haas wrote:
>
>> On Tue, 11 Apr 2023 00:14:28 +0200 Michael Niedermayer 
>>  wrote:
>> > Hi all
>> > 
>> > There was the request to make a 6.1 before end of April
>> > Is that still so ?
>> > 
>> > Assuming it is, its time to make that branch and release soon
>>
>> Hi,
>>
>> It is now september. What happened to this release? FFmpeg 6.1 is
>> currently the only thing blocking the adoption of vulkan video.
>>
>
> there are several security issues that need to be fixed
> ossfuzz found more, it also put some random unlreated issues again
> into the same ticket. (which are basically invissible sub-tickets)
> the evc code also needs a security review, Maybe Dawid is working on this
> iam not sure. And iam sure theres more
> We also have a security issue in fate, i belive nicolas is looking into
> that, that doesnt hold up the release but all these things compete for time
> and some people you may have noticed tried to just randomly block patches
> going back and forth on these and discussing with tech/community committtees
> also took time.
> And last but not least if people want me to design a standalone SDR library
> while thats not holding up 6.1 it takes time from the pot from 6.1 work.
> I did say this, i was attacked but yes time is unforgiving it doesnt care
>
> Also I did fall behind with security fixes in the summer a bit, the weather 
> was
> nice, some members of the community where not nice. So i tried to spend some
> time with the nice weather
>
> If you want 6.1 to happen quick. be nice to me or help with anything that i
> have to work on 6.1 or other so theres more time in the pot
> what about merging libplacebo into FFmpeg for example ?
> As far as iam concerned you can have absolute final power about anything
> in that libplacebo inside FFmpeg.
> Or help with the whole SDR thing. If i dont have to think about it and
> can concentrate on the release and security then yes it will happen faster
>
> I also have some paid work under NDA which i signed a contract for, i need
> to work on that too. Yes code will be submitted to FFmpeg when/if its done
> And theres life, i have other shit to do too. For example my taxes and i also
> want to spend some time working on AI/neural nets. I guess that will not be
> FFmpeg related as id like my work on AI not to be in a similar position to
> where avradio is now.
>
> So yeah, i think theres no problem with 6.1 its just not happening as quick
> as I and others wanted
>
> thx
>
> [...]
> -- 
> Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
>
> If you think the mosad wants you dead since a long time then you are either
> wrong or dead since a long time.
>

I'm not sure it's a good idea to wait to merge the EVC decoder.
Perhaps we should move that to the next release.

I'd like to get my AAC padding/duration fixes in, and drop lavc's
old FFT code entirely.
___
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".


[FFmpeg-devel] [PATCH 42/42] avcodec/ffv1dec: Switch to ProgressFrames

2023-09-19 Thread Andreas Rheinhardt
Avoids implicit av_frame_ref() and therefore allocations
and error checks. It also avoids explicitly allocating
the AVFrames (done implicitly when getting the buffer).

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/ffv1.c|  1 -
 libavcodec/ffv1.h|  4 +--
 libavcodec/ffv1dec.c | 83 +++-
 3 files changed, 37 insertions(+), 51 deletions(-)

diff --git a/libavcodec/ffv1.c b/libavcodec/ffv1.c
index b6204740ed..9075b34950 100644
--- a/libavcodec/ffv1.c
+++ b/libavcodec/ffv1.c
@@ -31,7 +31,6 @@
 #include "avcodec.h"
 #include "rangecoder.h"
 #include "ffv1.h"
-#include "threadframe.h"
 
 av_cold int ff_ffv1_common_init(AVCodecContext *avctx)
 {
diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h
index 04869da5c9..83a236fda8 100644
--- a/libavcodec/ffv1.h
+++ b/libavcodec/ffv1.h
@@ -32,9 +32,9 @@
 #include "avcodec.h"
 #include "get_bits.h"
 #include "mathops.h"
+#include "progressframe.h"
 #include "put_bits.h"
 #include "rangecoder.h"
-#include "threadframe.h"
 
 #ifdef __INTEL_COMPILER
 #undef av_flatten
@@ -87,7 +87,7 @@ typedef struct FFV1Context {
 int flags;
 int64_t picture_number;
 int key_frame;
-ThreadFrame picture, last_picture;
+ProgressFrame picture, last_picture;
 struct FFV1Context *fsrc;
 
 AVFrame *cur;
diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c
index 20cc345780..b7e02b82b2 100644
--- a/libavcodec/ffv1dec.c
+++ b/libavcodec/ffv1dec.c
@@ -37,8 +37,8 @@
 #include "golomb.h"
 #include "mathops.h"
 #include "ffv1.h"
+#include "progressframe.h"
 #include "thread.h"
-#include "threadframe.h"
 
 static inline av_flatten int get_symbol_inline(RangeCoder *c, uint8_t *state,
int is_signed)
@@ -264,8 +264,8 @@ static int decode_slice(AVCodecContext *c, void *arg)
 for( si=0; fs != f->slice_context[si]; si ++)
 ;
 
-if(f->fsrc && !(p->flags & AV_FRAME_FLAG_KEY))
-ff_thread_await_progress(>last_picture, si, 0);
+if (f->fsrc && !(p->flags & AV_FRAME_FLAG_KEY) && f->last_picture.f)
+ff_thread_progress_await(>last_picture, si);
 
 if(f->fsrc && !(p->flags & AV_FRAME_FLAG_KEY)) {
 FFV1Context *fssrc = f->fsrc->slice_context[si];
@@ -370,7 +370,7 @@ static int decode_slice(AVCodecContext *c, void *arg)
 }
 }
 
-ff_thread_report_progress(>picture, si, 0);
+ff_thread_progress_report(>picture, si);
 
 return 0;
 }
@@ -847,11 +847,6 @@ static av_cold int decode_init(AVCodecContext *avctx)
 if ((ret = ff_ffv1_common_init(avctx)) < 0)
 return ret;
 
-f->picture.f  = av_frame_alloc();
-f->last_picture.f = av_frame_alloc();
-if (!f->picture.f || !f->last_picture.f)
-return AVERROR(ENOMEM);
-
 if (avctx->extradata_size > 0 && (ret = read_extra_header(f)) < 0)
 return ret;
 
@@ -868,31 +863,21 @@ static int decode_frame(AVCodecContext *avctx, AVFrame 
*rframe,
 int buf_size= avpkt->size;
 FFV1Context *f  = avctx->priv_data;
 RangeCoder *const c = >slice_context[0]->c;
-int i, ret;
+int i, ret, key_frame;
 uint8_t keystate = 128;
 uint8_t *buf_p;
 AVFrame *p;
 
-if (f->last_picture.f)
-ff_thread_release_ext_buffer(avctx, >last_picture);
-FFSWAP(ThreadFrame, f->picture, f->last_picture);
-
-f->cur = p = f->picture.f;
+ff_thread_progress_unref(avctx, >last_picture);
+FFSWAP(ProgressFrame, f->picture, f->last_picture);
 
-if (f->version < 3 && avctx->field_order > AV_FIELD_PROGRESSIVE) {
-/* we have interlaced material flagged in container */
-p->flags |= AV_FRAME_FLAG_INTERLACED;
-if (avctx->field_order == AV_FIELD_TT || avctx->field_order == 
AV_FIELD_TB)
-p->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
-}
 
 f->avctx = avctx;
 ff_init_range_decoder(c, buf, buf_size);
 ff_build_rac_states(c, 0.05 * (1LL << 32), 256 - 8);
 
-p->pict_type = AV_PICTURE_TYPE_I; //FIXME I vs. P
 if (get_rac(c, )) {
-p->flags |= AV_FRAME_FLAG_KEY;
+key_frame = AV_FRAME_FLAG_KEY;
 f->key_frame_ok = 0;
 if ((ret = read_header(f)) < 0)
 return ret;
@@ -903,7 +888,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame 
*rframe,
"Cannot decode non-keyframe without valid keyframe\n");
 return AVERROR_INVALIDDATA;
 }
-p->flags &= ~AV_FRAME_FLAG_KEY;
+key_frame = 0;
 }
 
 if (f->ac != AC_GOLOMB_RICE) {
@@ -921,10 +906,23 @@ static int decode_frame(AVCodecContext *avctx, AVFrame 
*rframe,
 return AVERROR_INVALIDDATA;
 }
 
-ret = ff_thread_get_ext_buffer(avctx, >picture, AV_GET_BUFFER_FLAG_REF);
+ret = ff_thread_progress_get_buffer(avctx, >picture,
+AV_GET_BUFFER_FLAG_REF);
 if (ret < 0)
 return ret;
 
+f->cur = p = f->picture.f;
+
+p->pict_type = AV_PICTURE_TYPE_I; //FIXME I 

[FFmpeg-devel] [PATCH 41/42] avcodec/pngdec: Switch to ProgressFrames

2023-09-19 Thread Andreas Rheinhardt
Avoids implicit av_frame_ref() and therefore allocations
and error checks. It also avoids explicitly allocating
the AVFrames (done implicitly when getting the buffer).

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/pngdec.c | 64 +++--
 1 file changed, 27 insertions(+), 37 deletions(-)

diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c
index c011ca386e..8576ccb3b1 100644
--- a/libavcodec/pngdec.c
+++ b/libavcodec/pngdec.c
@@ -40,8 +40,8 @@
 #include "apng.h"
 #include "png.h"
 #include "pngdsp.h"
+#include "progressframe.h"
 #include "thread.h"
-#include "threadframe.h"
 #include "zlib_wrapper.h"
 
 #include 
@@ -61,8 +61,8 @@ typedef struct PNGDecContext {
 AVCodecContext *avctx;
 
 GetByteContext gb;
-ThreadFrame last_picture;
-ThreadFrame picture;
+ProgressFrame last_picture;
+ProgressFrame picture;
 
 AVDictionary *frame_metadata;
 
@@ -815,7 +815,7 @@ static int decode_idat_chunk(AVCodecContext *avctx, 
PNGDecContext *s,
 s->bpp += byte_depth;
 }
 
-ff_thread_release_ext_buffer(avctx, >picture);
+ff_thread_progress_unref(avctx, >picture);
 if (s->dispose_op == APNG_DISPOSE_OP_PREVIOUS) {
 /* We only need a buffer for the current picture. */
 ret = ff_thread_get_buffer(avctx, p, 0);
@@ -824,8 +824,8 @@ static int decode_idat_chunk(AVCodecContext *avctx, 
PNGDecContext *s,
 } else if (s->dispose_op == APNG_DISPOSE_OP_BACKGROUND) {
 /* We need a buffer for the current picture as well as
  * a buffer for the reference to retain. */
-ret = ff_thread_get_ext_buffer(avctx, >picture,
-   AV_GET_BUFFER_FLAG_REF);
+ret = ff_thread_progress_get_buffer(avctx, >picture,
+AV_GET_BUFFER_FLAG_REF);
 if (ret < 0)
 return ret;
 ret = ff_thread_get_buffer(avctx, p, 0);
@@ -833,8 +833,9 @@ static int decode_idat_chunk(AVCodecContext *avctx, 
PNGDecContext *s,
 return ret;
 } else {
 /* The picture output this time and the reference to retain 
coincide. */
-if ((ret = ff_thread_get_ext_buffer(avctx, >picture,
-AV_GET_BUFFER_FLAG_REF)) < 0)
+ret = ff_thread_progress_get_buffer(avctx, >picture,
+AV_GET_BUFFER_FLAG_REF);
+if (ret < 0)
 return ret;
 ret = av_frame_ref(p, s->picture.f);
 if (ret < 0)
@@ -1195,7 +1196,7 @@ static void handle_p_frame_png(PNGDecContext *s, AVFrame 
*p)
 
 ls = FFMIN(ls, s->width * s->bpp);
 
-ff_thread_await_progress(>last_picture, INT_MAX, 0);
+ff_thread_progress_await(>last_picture, INT_MAX);
 for (j = 0; j < s->height; j++) {
 for (i = 0; i < ls; i++)
 pd[i] += pd_last[i];
@@ -1227,7 +1228,7 @@ static int handle_p_frame_apng(AVCodecContext *avctx, 
PNGDecContext *s,
 return AVERROR_PATCHWELCOME;
 }
 
-ff_thread_await_progress(>last_picture, INT_MAX, 0);
+ff_thread_progress_await(>last_picture, INT_MAX);
 
 // copy unchanged rectangles from the last frame
 for (y = 0; y < s->y_offset; y++)
@@ -1594,7 +1595,7 @@ exit_loop:
 }
 
 /* handle P-frames only if a predecessor frame is available */
-if (s->last_picture.f->data[0]) {
+if (s->last_picture.f) {
 if (   !(avpkt->flags & AV_PKT_FLAG_KEY) && avctx->codec_tag != 
AV_RL32("MPNG")
 && s->last_picture.f->width == p->width
 && s->last_picture.f->height== p->height
@@ -1611,12 +1612,11 @@ exit_loop:
 if (CONFIG_APNG_DECODER && s->dispose_op == APNG_DISPOSE_OP_BACKGROUND)
 apng_reset_background(s, p);
 
-ff_thread_report_progress(>picture, INT_MAX, 0);
-
-return 0;
-
+ret = 0;
 fail:
-ff_thread_report_progress(>picture, INT_MAX, 0);
+if (s->picture.f)
+ff_thread_progress_report(>picture, INT_MAX);
+
 return ret;
 }
 
@@ -1703,8 +1703,8 @@ static int decode_frame_png(AVCodecContext *avctx, 
AVFrame *p,
 goto the_end;
 
 if (!(avctx->active_thread_type & FF_THREAD_FRAME)) {
-ff_thread_release_ext_buffer(avctx, >last_picture);
-FFSWAP(ThreadFrame, s->picture, s->last_picture);
+ff_thread_progress_unref(avctx, >last_picture);
+FFSWAP(ProgressFrame, s->picture, s->last_picture);
 }
 
 *got_frame = 1;
@@ -1756,10 +1756,10 @@ static int decode_frame_apng(AVCodecContext *avctx, 
AVFrame *p,
 
 if (!(avctx->active_thread_type & FF_THREAD_FRAME)) {
 if (s->dispose_op == APNG_DISPOSE_OP_PREVIOUS) {
-ff_thread_release_ext_buffer(avctx, >picture);
+ff_thread_progress_unref(avctx, >picture);
 } else {
-ff_thread_release_ext_buffer(avctx, >last_picture);
-

[FFmpeg-devel] [PATCH 40/42] avcodec/hevcdec: Switch to ProgressFrames

2023-09-19 Thread Andreas Rheinhardt
Avoids implicit av_frame_ref() and therefore allocations
and error checks. It also avoids explicitly allocating
the AVFrames (done implicitly when getting the buffer).

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/hevc_filter.c |  8 
 libavcodec/hevc_mvs.c|  6 +++---
 libavcodec/hevc_refs.c   | 22 ++
 libavcodec/hevcdec.c | 24 ++--
 libavcodec/hevcdec.h |  4 ++--
 5 files changed, 29 insertions(+), 35 deletions(-)

diff --git a/libavcodec/hevc_filter.c b/libavcodec/hevc_filter.c
index 0c45310ea6..07bae34782 100644
--- a/libavcodec/hevc_filter.c
+++ b/libavcodec/hevc_filter.c
@@ -26,7 +26,7 @@
 #include "libavutil/internal.h"
 
 #include "hevcdec.h"
-#include "threadframe.h"
+#include "progressframe.h"
 
 #define LUMA 0
 #define CB 1
@@ -874,15 +874,15 @@ void ff_hevc_hls_filter(HEVCLocalContext *lc, int x, int 
y, int ctb_size)
 if (y && x_end) {
 sao_filter_CTB(lc, s, x, y - ctb_size);
 if (s->threads_type & FF_THREAD_FRAME )
-ff_thread_report_progress(>ref->tf, y, 0);
+ff_thread_progress_report(>ref->tf, y);
 }
 if (x_end && y_end) {
 sao_filter_CTB(lc, s, x , y);
 if (s->threads_type & FF_THREAD_FRAME )
-ff_thread_report_progress(>ref->tf, y + ctb_size, 0);
+ff_thread_progress_report(>ref->tf, y + ctb_size);
 }
 } else if (s->threads_type & FF_THREAD_FRAME && x_end)
-ff_thread_report_progress(>ref->tf, y + ctb_size - 4, 0);
+ff_thread_progress_report(>ref->tf, y + ctb_size - 4);
 }
 
 void ff_hevc_hls_filters(HEVCLocalContext *lc, int x_ctb, int y_ctb, int 
ctb_size)
diff --git a/libavcodec/hevc_mvs.c b/libavcodec/hevc_mvs.c
index 0a8cc2c43d..be02d52b3e 100644
--- a/libavcodec/hevc_mvs.c
+++ b/libavcodec/hevc_mvs.c
@@ -23,7 +23,7 @@
 
 #include "hevc.h"
 #include "hevcdec.h"
-#include "threadframe.h"
+#include "progressframe.h"
 
 static const uint8_t l0_l1_cand_idx[12][2] = {
 { 0, 1, },
@@ -248,7 +248,7 @@ static int temporal_luma_motion_vector(const HEVCContext 
*s, int x0, int y0,
 x &= ~15;
 y &= ~15;
 if (s->threads_type == FF_THREAD_FRAME)
-ff_thread_await_progress(>tf, y, 0);
+ff_thread_progress_await(>tf, y);
 x_pu   = x >> s->ps.sps->log2_min_pu_size;
 y_pu   = y >> s->ps.sps->log2_min_pu_size;
 temp_col   = TAB_MVF(x_pu, y_pu);
@@ -262,7 +262,7 @@ static int temporal_luma_motion_vector(const HEVCContext 
*s, int x0, int y0,
 x &= ~15;
 y &= ~15;
 if (s->threads_type == FF_THREAD_FRAME)
-ff_thread_await_progress(>tf, y, 0);
+ff_thread_progress_await(>tf, y);
 x_pu   = x >> s->ps.sps->log2_min_pu_size;
 y_pu   = y >> s->ps.sps->log2_min_pu_size;
 temp_col   = TAB_MVF(x_pu, y_pu);
diff --git a/libavcodec/hevc_refs.c b/libavcodec/hevc_refs.c
index 9cdc4233df..afb9ff0cc0 100644
--- a/libavcodec/hevc_refs.c
+++ b/libavcodec/hevc_refs.c
@@ -27,18 +27,15 @@
 #include "thread.h"
 #include "hevc.h"
 #include "hevcdec.h"
+#include "progressframe.h"
 #include "refstruct.h"
-#include "threadframe.h"
 
 void ff_hevc_unref_frame(HEVCContext *s, HEVCFrame *frame, int flags)
 {
-/* frame->frame can be NULL if context init failed */
-if (!frame->frame || !frame->frame->buf[0])
-return;
-
 frame->flags &= ~flags;
 if (!frame->flags) {
-ff_thread_release_ext_buffer(s->avctx, >tf);
+ff_thread_progress_unref(s->avctx, >tf);
+frame->frame = NULL;
 ff_thread_release_buffer(s->avctx, frame->frame_grain);
 frame->needs_fg = 0;
 
@@ -84,13 +81,14 @@ static HEVCFrame *alloc_frame(HEVCContext *s)
 int i, j, ret;
 for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
 HEVCFrame *frame = >DPB[i];
-if (frame->frame->buf[0])
+if (frame->frame)
 continue;
 
-ret = ff_thread_get_ext_buffer(s->avctx, >tf,
-   AV_GET_BUFFER_FLAG_REF);
+ret = ff_thread_progress_get_buffer(s->avctx, >tf,
+AV_GET_BUFFER_FLAG_REF);
 if (ret < 0)
 return NULL;
+frame->frame = frame->tf.f;
 
 frame->rpl = ff_refstruct_allocz(s->pkt.nb_nals * sizeof(*frame->rpl));
 if (!frame->rpl)
@@ -136,7 +134,7 @@ int ff_hevc_set_new_ref(HEVCContext *s, AVFrame **frame, 
int poc)
 for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
 HEVCFrame *frame = >DPB[i];
 
-if (frame->frame->buf[0] && frame->sequence == s->seq_decode &&
+if (frame->frame && frame->sequence == s->seq_decode &&
 frame->poc == poc) {
 av_log(s->avctx, AV_LOG_ERROR, "Duplicate POC in a sequence: 
%d.\n",
 

[FFmpeg-devel] [PATCH 39/42] avcodec/hevcdec: Move collocated_ref to HEVCContext

2023-09-19 Thread Andreas Rheinhardt
Only the collocated_ref of the current frame (i.e. HEVCContext.ref)
is ever used*, so move it to HEVCContext directly after ref.

*: This goes so far that collocated_ref was not even synced across
threads in case of frame-threading.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/hevc_mvs.c  | 2 +-
 libavcodec/hevc_refs.c | 5 ++---
 libavcodec/hevcdec.c   | 6 +++---
 libavcodec/hevcdec.h   | 2 +-
 4 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/libavcodec/hevc_mvs.c b/libavcodec/hevc_mvs.c
index c231797a57..0a8cc2c43d 100644
--- a/libavcodec/hevc_mvs.c
+++ b/libavcodec/hevc_mvs.c
@@ -227,7 +227,7 @@ static int temporal_luma_motion_vector(const HEVCContext 
*s, int x0, int y0,
 int availableFlagLXCol = 0;
 int colPic;
 
-const HEVCFrame *ref = s->ref->collocated_ref;
+const HEVCFrame *ref = s->collocated_ref;
 
 if (!ref) {
 memset(mvLXCol, 0, sizeof(*mvLXCol));
diff --git a/libavcodec/hevc_refs.c b/libavcodec/hevc_refs.c
index fa53b273c7..9cdc4233df 100644
--- a/libavcodec/hevc_refs.c
+++ b/libavcodec/hevc_refs.c
@@ -49,8 +49,6 @@ void ff_hevc_unref_frame(HEVCContext *s, HEVCFrame *frame, 
int flags)
 ff_refstruct_unref(>rpl_tab);
 frame->refPicList = NULL;
 
-frame->collocated_ref = NULL;
-
 ff_refstruct_unref(>hwaccel_picture_private);
 }
 }
@@ -152,6 +150,7 @@ int ff_hevc_set_new_ref(HEVCContext *s, AVFrame **frame, 
int poc)
 
 *frame = ref->frame;
 s->ref = ref;
+s->collocated_ref = NULL;
 
 if (s->sh.pic_output_flag)
 ref->flags = HEVC_FRAME_FLAG_OUTPUT | HEVC_FRAME_FLAG_SHORT_REF;
@@ -383,7 +382,7 @@ int ff_hevc_slice_rpl(HEVCContext *s)
 
 if (sh->collocated_list == list_idx &&
 sh->collocated_ref_idx < rpl->nb_refs)
-s->ref->collocated_ref = rpl->ref[sh->collocated_ref_idx];
+s->collocated_ref = rpl->ref[sh->collocated_ref_idx];
 }
 
 return 0;
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index c8067a736e..a476a7c7ce 100644
--- a/libavcodec/hevcdec.c
+++ b/libavcodec/hevcdec.c
@@ -2910,7 +2910,7 @@ static int hevc_frame_start(HEVCContext *s)
 fail:
 if (s->ref)
 ff_hevc_unref_frame(s, s->ref, ~0);
-s->ref = NULL;
+s->ref = s->collocated_ref = NULL;
 return ret;
 }
 
@@ -3131,7 +3131,7 @@ static int decode_nal_units(HEVCContext *s, const uint8_t 
*buf, int length)
 int i, ret = 0;
 int eos_at_start = 1;
 
-s->ref = NULL;
+s->ref = s->collocated_ref = NULL;
 s->last_eos = s->eos;
 s->eos = 0;
 s->overlap = 0;
@@ -3339,7 +3339,7 @@ static int hevc_decode_frame(AVCodecContext *avctx, 
AVFrame *rframe,
 if (sd && sd_size > 0)
 ff_dovi_update_cfg(>dovi_ctx, (AVDOVIDecoderConfigurationRecord *) 
sd);
 
-s->ref = NULL;
+s->ref = s->collocated_ref = NULL;
 ret= decode_nal_units(s, avpkt->data, avpkt->size);
 if (ret < 0)
 return ret;
diff --git a/libavcodec/hevcdec.h b/libavcodec/hevcdec.h
index edf2f188cf..bed8716f99 100644
--- a/libavcodec/hevcdec.h
+++ b/libavcodec/hevcdec.h
@@ -413,7 +413,6 @@ typedef struct HEVCFrame {
 RefPicListTab **rpl_tab;   ///< RefStruct reference
 int ctb_count;
 int poc;
-struct HEVCFrame *collocated_ref;
 
 RefPicListTab *rpl;///< RefStruct reference
 int nb_rpl_elems;
@@ -527,6 +526,7 @@ typedef struct HEVCContext {
 enum HEVCNALUnitType nal_unit_type;
 int temporal_id;  ///< temporal_id_plus1 - 1
 HEVCFrame *ref;
+HEVCFrame *collocated_ref;
 HEVCFrame DPB[32];
 int poc;
 int pocTid0;
-- 
2.34.1

___
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".


[FFmpeg-devel] [PATCH 38/42] avcodec/codec_internal: Remove FF_CODEC_CAP_ALLOCATE_PROGRESS

2023-09-19 Thread Andreas Rheinhardt
Before commit f025b8e110b36c1cdb4fb56c4cd57aeca1767b5b,
every frame-threaded decoder used ThreadFrames, even when
they did not have any inter-frame dependencies at all.
In order to distinguish those decoders that need the AVBuffer
for progress communication from those that do not (to avoid
the allocation for the latter), the former decoders were marked
with the FF_CODEC_CAP_ALLOCATE_PROGRESS internal codec cap.

Yet distinguishing these two can be done in a more natural way:
Don't use ThreadFrames when not needed and split ff_thread_get_buffer()
into a core function that calls the user's get_buffer2 callback
and a wrapper around it that also allocates the progress AVBuffer.
This has been done in 02220b88fc38ef9dd4f2d519f5d3e4151258b60c
and since that commit the ALLOCATE_PROGRESS cap was nearly redundant.

The only exception was WebP and VP8. WebP can contain VP8
and uses the VP8 decoder directly (i.e. they share the same
AVCodecContext). Both decoders are frame-threaded and VP8
has inter-frame dependencies (in general, not in valid WebP)
and therefore the ALLOCATE_PROGRESS cap. In order to avoid
allocating progress in case of a frame-threaded WebP decoder
the cap and the check for the cap has been kept in place.

Yet now the VP8 decoder has been switched to use ProgressFrames
and therefore there is just no reason any more for this check
and the cap. This commit therefore removes both.

Also change the value of FF_CODEC_CAP_USES_PROGRESSFRAMES
to leave no gaps.

Signed-off-by: Andreas Rheinhardt 
---
 doc/multithreading.txt  |  8 
 libavcodec/codec_internal.h |  7 +--
 libavcodec/ffv1dec.c|  3 +--
 libavcodec/h264dec.c|  2 +-
 libavcodec/hevcdec.c|  2 +-
 libavcodec/mpeg4videodec.c  |  3 +--
 libavcodec/pngdec.c |  3 +--
 libavcodec/pthread_frame.c  | 12 +---
 libavcodec/rv30.c   |  1 -
 libavcodec/rv40.c   |  1 -
 libavcodec/tests/avcodec.c  |  7 +--
 11 files changed, 16 insertions(+), 33 deletions(-)

diff --git a/doc/multithreading.txt b/doc/multithreading.txt
index 470194ff85..0fb467392d 100644
--- a/doc/multithreading.txt
+++ b/doc/multithreading.txt
@@ -53,10 +53,10 @@ thread.
 Add AV_CODEC_CAP_FRAME_THREADS to the codec capabilities. There will be very 
little
 speed gain at this point but it should work.
 
-If there are inter-frame dependencies, so the codec calls
-ff_thread_report/await_progress(), set FF_CODEC_CAP_ALLOCATE_PROGRESS in
-AVCodec.caps_internal and use ff_thread_get_buffer() to allocate frames. The
-frames must then be freed with ff_thread_release_buffer().
+Use ff_thread_get_buffer() (or ff_thread_get_ext_buffer() or
+ff_thread_progress_get_buffer() in case you have inter-frame dependencies)
+to allocate frames. The frames must then be freed with 
ff_thread_release_buffer()
+(or ff_thread_release_ext_buffer() or ff_thread_progress_unref()).
 Otherwise decode directly into the user-supplied frames.
 
 Call ff_thread_report_progress() after some part of the current picture has 
decoded.
diff --git a/libavcodec/codec_internal.h b/libavcodec/codec_internal.h
index c03b64ceba..4ddf394c0b 100644
--- a/libavcodec/codec_internal.h
+++ b/libavcodec/codec_internal.h
@@ -65,12 +65,7 @@
 /**
  * The decoder might make use of the ProgressFrame API.
  */
-#define FF_CODEC_CAP_USES_PROGRESSFRAMES(1 << 11)
-/*
- * The codec supports frame threading and has inter-frame dependencies, so it
- * uses ff_thread_report/await_progress().
- */
-#define FF_CODEC_CAP_ALLOCATE_PROGRESS  (1 << 6)
+#define FF_CODEC_CAP_USES_PROGRESSFRAMES(1 << 6)
 /**
  * Codec handles avctx->thread_count == 0 (auto) internally.
  */
diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c
index 54cf075b8f..20cc345780 100644
--- a/libavcodec/ffv1dec.c
+++ b/libavcodec/ffv1dec.c
@@ -1125,6 +1125,5 @@ const FFCodec ff_ffv1_decoder = {
 UPDATE_THREAD_CONTEXT(update_thread_context),
 .p.capabilities = AV_CODEC_CAP_DR1 |
   AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_SLICE_THREADS,
-.caps_internal  = FF_CODEC_CAP_INIT_CLEANUP |
-  FF_CODEC_CAP_ALLOCATE_PROGRESS,
+.caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
 };
diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c
index 8578d3b346..39666faace 100644
--- a/libavcodec/h264dec.c
+++ b/libavcodec/h264dec.c
@@ -1140,7 +1140,7 @@ const FFCodec ff_h264_decoder = {
NULL
},
 .caps_internal = FF_CODEC_CAP_EXPORTS_CROPPING |
- FF_CODEC_CAP_ALLOCATE_PROGRESS | 
FF_CODEC_CAP_INIT_CLEANUP,
+ FF_CODEC_CAP_INIT_CLEANUP,
 .flush = h264_decode_flush,
 UPDATE_THREAD_CONTEXT(ff_h264_update_thread_context),
 UPDATE_THREAD_CONTEXT_FOR_USER(ff_h264_update_thread_context_for_user),
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index 23cc543f82..c8067a736e 100644
--- a/libavcodec/hevcdec.c
+++ 

[FFmpeg-devel] [PATCH 37/42] avcodec/vp8: Convert to ProgressFrame API

2023-09-19 Thread Andreas Rheinhardt
Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/vp8.c  | 90 +++
 libavcodec/vp8.h  |  5 +--
 libavcodec/webp.c |  3 +-
 3 files changed, 33 insertions(+), 65 deletions(-)

diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c
index 4a51c551b8..30d22016f5 100644
--- a/libavcodec/vp8.c
+++ b/libavcodec/vp8.c
@@ -34,9 +34,9 @@
 #include "hwaccel_internal.h"
 #include "hwconfig.h"
 #include "mathops.h"
+#include "progressframe.h"
 #include "refstruct.h"
 #include "thread.h"
-#include "threadframe.h"
 #include "vp8.h"
 #include "vp89_rac.h"
 #include "vp8data.h"
@@ -102,9 +102,9 @@ static void free_buffers(VP8Context *s)
 
 static int vp8_alloc_frame(VP8Context *s, VP8Frame *f, int ref)
 {
-int ret;
-if ((ret = ff_thread_get_ext_buffer(s->avctx, >tf,
-ref ? AV_GET_BUFFER_FLAG_REF : 0)) < 0)
+int ret = ff_thread_progress_get_buffer(s->avctx, >tf,
+ref ? AV_GET_BUFFER_FLAG_REF : 0);
+if (ret < 0)
 return ret;
 if (!(f->seg_map = ff_refstruct_allocz(s->mb_width * s->mb_height)))
 goto fail;
@@ -116,7 +116,7 @@ static int vp8_alloc_frame(VP8Context *s, VP8Frame *f, int 
ref)
 
 fail:
 ff_refstruct_unref(>seg_map);
-ff_thread_release_ext_buffer(s->avctx, >tf);
+ff_thread_progress_unref(s->avctx, >tf);
 return ret;
 }
 
@@ -124,23 +124,16 @@ static void vp8_release_frame(VP8Context *s, VP8Frame *f)
 {
 ff_refstruct_unref(>seg_map);
 ff_refstruct_unref(>hwaccel_picture_private);
-ff_thread_release_ext_buffer(s->avctx, >tf);
+ff_thread_progress_unref(s->avctx, >tf);
 }
 
 #if CONFIG_VP8_DECODER
-static int vp8_ref_frame(VP8Context *s, VP8Frame *dst, const VP8Frame *src)
+static void vp8_replace_frame(VP8Context *s, VP8Frame *dst, const VP8Frame 
*src)
 {
-int ret;
-
-vp8_release_frame(s, dst);
-
-if ((ret = ff_thread_ref_frame(>tf, >tf)) < 0)
-return ret;
+ff_thread_progress_replace(s->avctx, >tf, >tf);
 ff_refstruct_replace(>seg_map, src->seg_map);
 ff_refstruct_replace(>hwaccel_picture_private,
   src->hwaccel_picture_private);
-
-return 0;
 }
 #endif /* CONFIG_VP8_DECODER */
 
@@ -183,7 +176,7 @@ static VP8Frame *vp8_find_free_buffer(VP8Context *s)
 av_log(s->avctx, AV_LOG_FATAL, "Ran out of free frames!\n");
 abort();
 }
-if (frame->tf.f->buf[0])
+if (frame->tf.f)
 vp8_release_frame(s, frame);
 
 return frame;
@@ -1829,7 +1822,7 @@ static const uint8_t subpel_idx[3][8] = {
  */
 static av_always_inline
 void vp8_mc_luma(VP8Context *s, VP8ThreadData *td, uint8_t *dst,
- const ThreadFrame *ref, const VP8mv *mv,
+ const ProgressFrame *ref, const VP8mv *mv,
  int x_off, int y_off, int block_w, int block_h,
  int width, int height, ptrdiff_t linesize,
  vp8_mc_func mc_func[3][3])
@@ -1846,7 +1839,7 @@ void vp8_mc_luma(VP8Context *s, VP8ThreadData *td, 
uint8_t *dst,
 y_off += mv->y >> 2;
 
 // edge emulation
-ff_thread_await_progress(ref, (3 + y_off + block_h + 
subpel_idx[2][my]) >> 4, 0);
+ff_thread_progress_await(ref, (3 + y_off + block_h + 
subpel_idx[2][my]) >> 4);
 src += y_off * linesize + x_off;
 if (x_off < mx_idx || x_off >= width  - block_w - subpel_idx[2][mx] ||
 y_off < my_idx || y_off >= height - block_h - subpel_idx[2][my]) {
@@ -1862,7 +1855,7 @@ void vp8_mc_luma(VP8Context *s, VP8ThreadData *td, 
uint8_t *dst,
 }
 mc_func[my_idx][mx_idx](dst, linesize, src, src_linesize, block_h, mx, 
my);
 } else {
-ff_thread_await_progress(ref, (3 + y_off + block_h) >> 4, 0);
+ff_thread_progress_await(ref, (3 + y_off + block_h) >> 4);
 mc_func[0][0](dst, linesize, src + y_off * linesize + x_off,
   linesize, block_h, 0, 0);
 }
@@ -1887,7 +1880,7 @@ void vp8_mc_luma(VP8Context *s, VP8ThreadData *td, 
uint8_t *dst,
  */
 static av_always_inline
 void vp8_mc_chroma(VP8Context *s, VP8ThreadData *td, uint8_t *dst1,
-   uint8_t *dst2, const ThreadFrame *ref, const VP8mv *mv,
+   uint8_t *dst2, const ProgressFrame *ref, const VP8mv *mv,
int x_off, int y_off, int block_w, int block_h,
int width, int height, ptrdiff_t linesize,
vp8_mc_func mc_func[3][3])
@@ -1904,7 +1897,7 @@ void vp8_mc_chroma(VP8Context *s, VP8ThreadData *td, 
uint8_t *dst1,
 // edge emulation
 src1 += y_off * linesize + x_off;
 src2 += y_off * linesize + x_off;
-ff_thread_await_progress(ref, (3 + y_off + block_h + 
subpel_idx[2][my]) >> 3, 0);
+ff_thread_progress_await(ref, (3 + y_off + block_h + 
subpel_idx[2][my]) >> 3);
 if (x_off < mx_idx || x_off >= width  - block_w - subpel_idx[2][mx] ||
 y_off < my_idx || 

[FFmpeg-devel] [PATCH 36/42] avcodec/wavpack: Use ThreadProgress API

2023-09-19 Thread Andreas Rheinhardt
It is more natural given that WavPack doesn't need the data of
the previous frame at all; it just needs the DSD context.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/wavpack.c | 100 +++
 1 file changed, 44 insertions(+), 56 deletions(-)

diff --git a/libavcodec/wavpack.c b/libavcodec/wavpack.c
index 97705c8854..acb23ab8fe 100644
--- a/libavcodec/wavpack.c
+++ b/libavcodec/wavpack.c
@@ -30,7 +30,7 @@
 #include "get_bits.h"
 #include "refstruct.h"
 #include "thread.h"
-#include "threadframe.h"
+#include "threadprogress.h"
 #include "unary.h"
 #include "wavpack.h"
 #include "dsd.h"
@@ -107,11 +107,11 @@ typedef struct WavpackContext {
 int samples;
 int ch_offset;
 
-AVFrame *frame;
-ThreadFrame curr_frame, prev_frame;
 Modulation modulation;
 
 DSDContext *dsdctx; ///< RefStruct reference
+ThreadProgress *curr_progress, *prev_progress; ///< RefStruct references
+FFRefStructPool *progress_pool; ///< RefStruct reference
 int dsd_channels;
 } WavpackContext;
 
@@ -992,10 +992,18 @@ static int wv_dsd_reset(WavpackContext *s, int channels)
 
 s->dsd_channels = 0;
 ff_refstruct_unref(>dsdctx);
+ff_refstruct_unref(>curr_progress);
+ff_refstruct_unref(>prev_progress);
 
 if (!channels)
 return 0;
 
+if (!s->progress_pool) {
+s->progress_pool = ff_refstruct_pool_alloc(sizeof(*s->curr_progress), 
0);
+if (!s->progress_pool)
+return AVERROR(ENOMEM);
+}
+
 if (channels > INT_MAX / sizeof(*s->dsdctx))
 return AVERROR(EINVAL);
 
@@ -1015,17 +1023,9 @@ static int update_thread_context(AVCodecContext *dst, 
const AVCodecContext *src)
 {
 WavpackContext *fsrc = src->priv_data;
 WavpackContext *fdst = dst->priv_data;
-int ret;
-
-if (dst == src)
-return 0;
-
-ff_thread_release_ext_buffer(dst, >curr_frame);
-if (fsrc->curr_frame.f->data[0]) {
-if ((ret = ff_thread_ref_frame(>curr_frame, >curr_frame)) 
< 0)
-return ret;
-}
 
+ff_refstruct_replace(>progress_pool, fsrc->progress_pool);
+ff_refstruct_replace(>curr_progress, fsrc->curr_progress);
 ff_refstruct_replace(>dsdctx, fsrc->dsdctx);
 fdst->dsd_channels = fsrc->dsd_channels;
 
@@ -1041,12 +1041,6 @@ static av_cold int wavpack_decode_init(AVCodecContext 
*avctx)
 
 s->fdec_num = 0;
 
-s->curr_frame.f = av_frame_alloc();
-s->prev_frame.f = av_frame_alloc();
-
-if (!s->curr_frame.f || !s->prev_frame.f)
-return AVERROR(ENOMEM);
-
 ff_init_dsd_data();
 
 return 0;
@@ -1061,18 +1055,15 @@ static av_cold int wavpack_decode_end(AVCodecContext 
*avctx)
 av_freep(>fdec);
 s->fdec_num = 0;
 
-ff_thread_release_ext_buffer(avctx, >curr_frame);
-av_frame_free(>curr_frame.f);
-
-ff_thread_release_ext_buffer(avctx, >prev_frame);
-av_frame_free(>prev_frame.f);
-
 ff_refstruct_unref(>dsdctx);
+ff_refstruct_unref(>curr_progress);
+ff_refstruct_unref(>prev_progress);
+ff_refstruct_pool_uninit(>progress_pool);
 
 return 0;
 }
 
-static int wavpack_decode_block(AVCodecContext *avctx, int block_no,
+static int wavpack_decode_block(AVCodecContext *avctx, AVFrame *frame, int 
block_no,
 const uint8_t *buf, int buf_size)
 {
 WavpackContext *wc = avctx->priv_data;
@@ -1526,24 +1517,27 @@ static int wavpack_decode_block(AVCodecContext *avctx, 
int block_no,
 av_log(avctx, AV_LOG_ERROR, "Error reinitializing the DSD 
context\n");
 return ret;
 }
-ff_thread_release_ext_buffer(avctx, >curr_frame);
 }
 av_channel_layout_copy(>ch_layout, _ch_layout);
 avctx->sample_rate = new_samplerate;
 avctx->sample_fmt  = sample_fmt;
 avctx->bits_per_raw_sample = orig_bpp;
 
-ff_thread_release_ext_buffer(avctx, >prev_frame);
-FFSWAP(ThreadFrame, wc->curr_frame, wc->prev_frame);
-
 /* get output buffer */
-wc->curr_frame.f->nb_samples = s->samples;
-ret = ff_thread_get_ext_buffer(avctx, >curr_frame,
-   AV_GET_BUFFER_FLAG_REF);
+frame->nb_samples = s->samples;
+ret = ff_thread_get_buffer(avctx, frame, 0);
 if (ret < 0)
 return ret;
 
-wc->frame = wc->curr_frame.f;
+ff_refstruct_unref(>prev_progress);
+if (wc->dsdctx) {
+wc->prev_progress = ff_refstruct_pool_get(wc->progress_pool);
+if (!wc->prev_progress)
+return AVERROR(ENOMEM);
+ff_thread_progress_init(wc->prev_progress, avctx);
+}
+FFSWAP(ThreadProgress*, wc->prev_progress, wc->curr_progress);
+av_assert1(!!wc->dsdctx == !!wc->curr_progress);
 ff_thread_finish_setup(avctx);
 }
 
@@ -1552,9 +1546,9 @@ static int wavpack_decode_block(AVCodecContext *avctx, 
int block_no,
 return 

[FFmpeg-devel] [PATCH 35/42] avcodec/threadprogress: Add new API for frame-threaded progress

2023-09-19 Thread Andreas Rheinhardt
The API is very similar by the ProgressFrame API, with the exception
that it no longer has an included AVFrame. Instead one can wait
on anything via a ThreadProgress. One just has to ensure that
the lifetime of the object containing the ThreadProgress is long
enough (the corresponding problem for ProgressFrames is solved
by allocating the progress and giving each thread a reference
to it). This will typically be solved by putting a ThreadProgress
in a refcounted structure that is shared between threads.
It will be put to the test in the following commits.

An alternative to the check for whether the owner exists
(meaning "do we use frame-threading?") would be to initialize
the progress to INT_MAX in case frame threading is not in use.
This would probably be preferable on arches where atomic reads
are cheap (like x86), but are there ones where it is not?

One could also (guarded by e.g. an ASSERT_LEVEL check) actually
track the progress for non-framethreading, too, in order to
track errors even in single-threaded mode.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/pthread_frame.c  | 50 +
 libavcodec/threadprogress.h | 37 +++
 2 files changed, 87 insertions(+)
 create mode 100644 libavcodec/threadprogress.h

diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index 9e827f0606..219ab16ccd 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -40,6 +40,7 @@
 #include "refstruct.h"
 #include "thread.h"
 #include "threadframe.h"
+#include "threadprogress.h"
 #include "version_major.h"
 
 #include "libavutil/avassert.h"
@@ -1069,3 +1070,52 @@ void ff_thread_progress_await(const ProgressFrame *f, 
int n)
 pthread_cond_wait(>progress_cond, >progress_mutex);
 pthread_mutex_unlock(>progress_mutex);
 }
+
+void ff_thread_progress_init(ThreadProgress *pro, AVCodecContext *owner)
+{
+PerThreadContext *p = pro->owner = owner->active_thread_type & 
FF_THREAD_FRAME ?
+   owner->internal->thread_ctx : NULL;
+if (!p)
+return;
+atomic_init(>progress, -1);
+if (atomic_load_explicit(>debug_threads, memory_order_relaxed))
+av_log(owner, AV_LOG_DEBUG, "Initializing ThreadProgress %p\n", 
(void*)pro);
+}
+
+void ff_thread_progress_report2(ThreadProgress *pro, int n)
+{
+PerThreadContext *p = pro->owner;
+
+if (!p ||
+atomic_load_explicit(>progress, memory_order_relaxed) >= n)
+return;
+
+if (atomic_load_explicit(>debug_threads, memory_order_relaxed))
+av_log(p->avctx, AV_LOG_DEBUG,
+   "%p finished %d\n", (void*)pro, n);
+
+pthread_mutex_lock(>progress_mutex);
+
+atomic_store_explicit(>progress, n, memory_order_release);
+
+pthread_cond_broadcast(>progress_cond);
+pthread_mutex_unlock(>progress_mutex);
+}
+
+void ff_thread_progress_await2(const ThreadProgress *pro, int n)
+{
+PerThreadContext *p = pro->owner;
+
+if (!p ||
+atomic_load_explicit(>progress, memory_order_acquire) >= n)
+return;
+
+if (atomic_load_explicit(>debug_threads, memory_order_relaxed))
+av_log(p->avctx, AV_LOG_DEBUG,
+   "thread awaiting %d from %p\n", n, (void*)pro);
+
+pthread_mutex_lock(>progress_mutex);
+while (atomic_load_explicit(>progress, memory_order_relaxed) < n)
+pthread_cond_wait(>progress_cond, >progress_mutex);
+pthread_mutex_unlock(>progress_mutex);
+}
diff --git a/libavcodec/threadprogress.h b/libavcodec/threadprogress.h
new file mode 100644
index 00..4f65e7da4d
--- /dev/null
+++ b/libavcodec/threadprogress.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2022 Andreas Rheinhardt 
+ *
+ * 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_THREADPROGRESS_H
+#define AVCODEC_THREADPROGRESS_H
+
+#include 
+
+struct AVCodecContext;
+
+typedef struct ThreadProgress {
+atomic_int progress;
+struct PerThreadContext *owner;
+} ThreadProgress;
+
+void ff_thread_progress_init(ThreadProgress *pro, struct AVCodecContext 
*owner);
+void ff_thread_progress_report2(ThreadProgress *pro, int progress);
+void ff_thread_progress_await2(const ThreadProgress *pro, int progress);
+
+#endif /* AVCODEC_THREADPROGRESS_H */

[FFmpeg-devel] [PATCH 34/42] avcodec/vp9: Replace atomic_store() by atomic_init()

2023-09-19 Thread Andreas Rheinhardt
This part of the code is not slice-threaded and they are
semantically an initialization, so use atomic_init()
instead of the potentially expensive atomic_store()
(which uses sequentially consistent memory ordering).

Also remove the initial initialization directly after
allocating this array.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/vp9.c | 6 +-
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c
index 8eba56b720..62ae0f5882 100644
--- a/libavcodec/vp9.c
+++ b/libavcodec/vp9.c
@@ -54,7 +54,6 @@ DEFINE_OFFSET_ARRAY(VP9Context, vp9_context, pthread_init_cnt,
 
 static int vp9_alloc_entries(AVCodecContext *avctx, int n) {
 VP9Context *s = avctx->priv_data;
-int i;
 
 if (avctx->active_thread_type & FF_THREAD_SLICE)  {
 if (s->entries)
@@ -63,9 +62,6 @@ static int vp9_alloc_entries(AVCodecContext *avctx, int n) {
 s->entries = av_malloc_array(n, sizeof(atomic_int));
 if (!s->entries)
 return AVERROR(ENOMEM);
-
-for (i  = 0; i < n; i++)
-atomic_init(>entries[i], 0);
 }
 return 0;
 }
@@ -1656,7 +1652,7 @@ static int vp9_decode_frame(AVCodecContext *avctx, 
AVFrame *frame,
 #if HAVE_THREADS
 if (avctx->active_thread_type & FF_THREAD_SLICE) {
 for (i = 0; i < s->sb_rows; i++)
-atomic_store(>entries[i], 0);
+atomic_init(>entries[i], 0);
 }
 #endif
 
-- 
2.34.1

___
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".


[FFmpeg-devel] [PATCH 33/42] avcodec/vp9: Simplify replacing VP9Frame

2023-09-19 Thread Andreas Rheinhardt
ff_thread_progress_replace() can handle a blank ProgressFrame
as src (in which case it simply unreferences dst), but not
a NULL one. So add a blank frame to be used as source for
this case, so that we can use the replace functions
to simplify vp9_frame_replace().

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/vp9.c   | 16 +---
 libavcodec/vp9shared.h |  3 ++-
 2 files changed, 7 insertions(+), 12 deletions(-)

diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c
index 87c507bb36..8eba56b720 100644
--- a/libavcodec/vp9.c
+++ b/libavcodec/vp9.c
@@ -146,11 +146,11 @@ fail:
 return ret;
 }
 
-static void vp9_frame_ref(VP9Frame *dst, const VP9Frame *src)
+static void vp9_frame_replace(AVCodecContext *avctx, VP9Frame *dst, const 
VP9Frame *src)
 {
-ff_thread_progress_ref(>tf, >tf);
+ff_thread_progress_replace(avctx, >tf, >tf);
 
-dst->extradata = ff_refstruct_ref(src->extradata);
+ff_refstruct_replace(>extradata, src->extradata);
 
 dst->segmentation_map = src->segmentation_map;
 dst->mv = src->mv;
@@ -160,13 +160,6 @@ static void vp9_frame_ref(VP9Frame *dst, const VP9Frame 
*src)
   src->hwaccel_picture_private);
 }
 
-static void vp9_frame_replace(AVCodecContext *avctx, VP9Frame *dst, const 
VP9Frame *src)
-{
-vp9_frame_unref(avctx, dst);
-if (src && src->tf.f)
-vp9_frame_ref(dst, src);
-}
-
 static int update_size(AVCodecContext *avctx, int w, int h)
 {
 #define HWACCEL_MAX (CONFIG_VP9_DXVA2_HWACCEL + \
@@ -1579,7 +1572,8 @@ static int vp9_decode_frame(AVCodecContext *avctx, 
AVFrame *frame,
 data += ret;
 size -= ret;
 
-src = !s->s.h.keyframe && !s->s.h.intraonly && !s->s.h.errorres ? 
>s.frames[CUR_FRAME] : NULL;
+src = !s->s.h.keyframe && !s->s.h.intraonly && !s->s.h.errorres ?
+  >s.frames[CUR_FRAME] : >s.frames[BLANK_FRAME];
 if (!retain_segmap_ref || s->s.h.keyframe || s->s.h.intraonly)
 vp9_frame_replace(avctx, >s.frames[REF_FRAME_SEGMAP], src);
 vp9_frame_replace(avctx, >s.frames[REF_FRAME_MVPAIR], src);
diff --git a/libavcodec/vp9shared.h b/libavcodec/vp9shared.h
index 805668416f..8a450c26a6 100644
--- a/libavcodec/vp9shared.h
+++ b/libavcodec/vp9shared.h
@@ -168,7 +168,8 @@ typedef struct VP9SharedContext {
 #define CUR_FRAME 0
 #define REF_FRAME_MVPAIR 1
 #define REF_FRAME_SEGMAP 2
-VP9Frame frames[3];
+#define BLANK_FRAME 3
+VP9Frame frames[4];
 } VP9SharedContext;
 
 #endif /* AVCODEC_VP9SHARED_H */
-- 
2.34.1

___
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".


[FFmpeg-devel] [PATCH 32/42] avcodec/vp9: Reduce wait times

2023-09-19 Thread Andreas Rheinhardt
Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/vp9.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c
index 79c4ae0205..87c507bb36 100644
--- a/libavcodec/vp9.c
+++ b/libavcodec/vp9.c
@@ -1564,14 +1564,15 @@ static int vp9_decode_frame(AVCodecContext *avctx, 
AVFrame *frame,
 av_log(avctx, AV_LOG_ERROR, "Requested reference %d not 
available\n", ref);
 return AVERROR_INVALIDDATA;
 }
+for (int i = 0; i < 8; i++)
+ff_thread_progress_replace(avctx, >next_refs[i], >s.refs[i]);
+ff_thread_finish_setup(avctx);
 ff_thread_progress_await(>s.refs[ref], INT_MAX);
 
 if ((ret = av_frame_ref(frame, s->s.refs[ref].f)) < 0)
 return ret;
 frame->pts = pkt->pts;
 frame->pkt_dts = pkt->dts;
-for (int i = 0; i < 8; i++)
-ff_thread_progress_replace(avctx, >next_refs[i], >s.refs[i]);
 *got_frame = 1;
 return pkt->size;
 }
-- 
2.34.1

___
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".


[FFmpeg-devel] [PATCH 31/42] avcodec/vp9: Fix race when attaching side-data for show-existing frame

2023-09-19 Thread Andreas Rheinhardt
When outputting a show-existing frame, the VP9 decoder simply
created a reference to said frame and returned it immediately to
the caller, without waiting for it to have finished decoding.
In case of frame-threading it is possible for the frame to
only be decoded while it was waiting to be output.
This is normally benign.

But there is one case where it is not: If the user wants
video encoding parameters to be exported, said side data
will only be attached to the src AVFrame at the end of
decoding the frame that is actually being shown. Without
synchronisation adding said side data in the decoder thread
and the reads in av_frame_ref() in the output thread
constitute a data race. This happens e.g. when using the
venc_data_dump tool with vp90-2-10-show-existing-frame.webm
from the FATE-suite.

Fix this by actually waiting for the frame to be output.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/vp9.c | 18 +++---
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c
index c940206b94..79c4ae0205 100644
--- a/libavcodec/vp9.c
+++ b/libavcodec/vp9.c
@@ -1564,6 +1564,8 @@ static int vp9_decode_frame(AVCodecContext *avctx, 
AVFrame *frame,
 av_log(avctx, AV_LOG_ERROR, "Requested reference %d not 
available\n", ref);
 return AVERROR_INVALIDDATA;
 }
+ff_thread_progress_await(>s.refs[ref], INT_MAX);
+
 if ((ret = av_frame_ref(frame, s->s.refs[ref].f)) < 0)
 return ret;
 frame->pts = pkt->pts;
@@ -1710,10 +1712,8 @@ static int vp9_decode_frame(AVCodecContext *avctx, 
AVFrame *frame,
 #endif
 {
 ret = decode_tiles(avctx, data, size);
-if (ret < 0) {
-ff_thread_progress_report(>s.frames[CUR_FRAME].tf, INT_MAX);
-return ret;
-}
+if (ret < 0)
+goto fail;
 }
 
 // Sum all counts fields into td[0].counts for tile threading
@@ -1727,18 +1727,19 @@ static int vp9_decode_frame(AVCodecContext *avctx, 
AVFrame *frame,
 ff_thread_finish_setup(avctx);
 }
 } while (s->pass++ == 1);
-ff_thread_progress_report(>s.frames[CUR_FRAME].tf, INT_MAX);
 
 if (s->td->error_info < 0) {
 av_log(avctx, AV_LOG_ERROR, "Failed to decode tile data\n");
 s->td->error_info = 0;
-return AVERROR_INVALIDDATA;
+ret = AVERROR_INVALIDDATA;
+goto fail;
 }
 if (avctx->export_side_data & AV_CODEC_EXPORT_DATA_VIDEO_ENC_PARAMS) {
 ret = vp9_export_enc_params(s, >s.frames[CUR_FRAME]);
 if (ret < 0)
-return ret;
+goto fail;
 }
+ff_thread_progress_report(>s.frames[CUR_FRAME].tf, INT_MAX);
 
 finish:
 // ref frame setup
@@ -1752,6 +1753,9 @@ finish:
 }
 
 return pkt->size;
+fail:
+ff_thread_progress_report(>s.frames[CUR_FRAME].tf, INT_MAX);
+return ret;
 }
 
 static void vp9_decode_flush(AVCodecContext *avctx)
-- 
2.34.1

___
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".


[FFmpeg-devel] [PATCH 30/42] avcodec/vp9: Switch to ProgressFrames

2023-09-19 Thread Andreas Rheinhardt
This already fixes a race in the vp9-encparams test. In this test,
side data is added to the current frame after having been decoded
(and therefore after ff_thread_finish_setup() has been called).
Yet the update_thread_context callback called ff_thread_ref_frame()
and therefore av_frame_ref() with this frame as source frame and
the ensuing read was unsynchronised with adding the side data,
i.e. there was a data race.

By switching to the ProgressFrame API the implicit av_frame_ref()
is removed and the race fixed except if this frame is later reused by
a show-existing-frame which uses an explicit av_frame_ref().
The vp9-encparams test does not cover this, so this commit
already fixes all the races in this test.

This decoder kept multiple references to the same ThreadFrames
in the same context and therefore had lots of implicit av_frame_ref()
even when decoding single-threaded. This incurred lots of small
allocations: When decoding an ordinary 10s video in single-threaded
mode the number of allocations reported by Valgrind went down
from 57,814 to 20,908; for 10 threads it went down from 84,223 to
21,901.

Signed-off-by: Andreas Rheinhardt 
---
Compare this with Anton's earlier patch [1] 
https://patchwork.ffmpeg.org/project/ffmpeg/patch/20220315104932.25496-2-an...@khirnov.net/

 libavcodec/dxva2_vp9.c   |   4 +-
 libavcodec/vp9.c | 137 +++
 libavcodec/vp9_mc_template.c |   2 +-
 libavcodec/vp9block.c|   5 +-
 libavcodec/vp9dec.h  |   4 +-
 libavcodec/vp9lpf.c  |   1 +
 libavcodec/vp9mvs.c  |   4 +-
 libavcodec/vp9recon.c|  19 ++---
 libavcodec/vp9shared.h   |   6 +-
 9 files changed, 68 insertions(+), 114 deletions(-)

diff --git a/libavcodec/dxva2_vp9.c b/libavcodec/dxva2_vp9.c
index eba4df9031..1352b9b7db 100644
--- a/libavcodec/dxva2_vp9.c
+++ b/libavcodec/dxva2_vp9.c
@@ -80,7 +80,7 @@ static int fill_picture_parameters(const AVCodecContext 
*avctx, AVDXVAContext *c
 pp->Reserved8Bits = 0;
 
 for (i = 0; i < 8; i++) {
-if (h->refs[i].f->buf[0]) {
+if (h->refs[i].f) {
 fill_picture_entry(>ref_frame_map[i], 
ff_dxva2_get_surface_index(avctx, ctx, h->refs[i].f), 0);
 pp->ref_frame_coded_width[i]  = h->refs[i].f->width;
 pp->ref_frame_coded_height[i] = h->refs[i].f->height;
@@ -90,7 +90,7 @@ static int fill_picture_parameters(const AVCodecContext 
*avctx, AVDXVAContext *c
 
 for (i = 0; i < 3; i++) {
 uint8_t refidx = h->h.refidx[i];
-if (h->refs[refidx].f->buf[0])
+if (h->refs[refidx].f)
 fill_picture_entry(>frame_refs[i], 
ff_dxva2_get_surface_index(avctx, ctx, h->refs[refidx].f), 0);
 else
 pp->frame_refs[i].bPicEntry = 0xFF;
diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c
index dac81fd712..c940206b94 100644
--- a/libavcodec/vp9.c
+++ b/libavcodec/vp9.c
@@ -30,9 +30,9 @@
 #include "hwaccel_internal.h"
 #include "hwconfig.h"
 #include "profiles.h"
+#include "progressframe.h"
 #include "refstruct.h"
 #include "thread.h"
-#include "threadframe.h"
 #include "pthread_internal.h"
 
 #include "videodsp.h"
@@ -99,7 +99,7 @@ static void vp9_tile_data_free(VP9TileData *td)
 
 static void vp9_frame_unref(AVCodecContext *avctx, VP9Frame *f)
 {
-ff_thread_release_ext_buffer(avctx, >tf);
+ff_thread_progress_unref(avctx, >tf);
 ff_refstruct_unref(>extradata);
 ff_refstruct_unref(>hwaccel_picture_private);
 f->segmentation_map = NULL;
@@ -110,7 +110,7 @@ static int vp9_frame_alloc(AVCodecContext *avctx, VP9Frame 
*f)
 VP9Context *s = avctx->priv_data;
 int ret, sz;
 
-ret = ff_thread_get_ext_buffer(avctx, >tf, AV_GET_BUFFER_FLAG_REF);
+ret = ff_thread_progress_get_buffer(avctx, >tf, AV_GET_BUFFER_FLAG_REF);
 if (ret < 0)
 return ret;
 
@@ -146,13 +146,9 @@ fail:
 return ret;
 }
 
-static int vp9_frame_ref(AVCodecContext *avctx, VP9Frame *dst, VP9Frame *src)
+static void vp9_frame_ref(VP9Frame *dst, const VP9Frame *src)
 {
-int ret;
-
-ret = ff_thread_ref_frame(>tf, >tf);
-if (ret < 0)
-return ret;
+ff_thread_progress_ref(>tf, >tf);
 
 dst->extradata = ff_refstruct_ref(src->extradata);
 
@@ -162,8 +158,13 @@ static int vp9_frame_ref(AVCodecContext *avctx, VP9Frame 
*dst, VP9Frame *src)
 
 ff_refstruct_replace(>hwaccel_picture_private,
   src->hwaccel_picture_private);
+}
 
-return 0;
+static void vp9_frame_replace(AVCodecContext *avctx, VP9Frame *dst, const 
VP9Frame *src)
+{
+vp9_frame_unref(avctx, dst);
+if (src && src->tf.f)
+vp9_frame_ref(dst, src);
 }
 
 static int update_size(AVCodecContext *avctx, int w, int h)
@@ -584,9 +585,9 @@ static int decode_frame_header(AVCodecContext *avctx,
 s->s.h.signbias[1]= get_bits1(>gb) && !s->s.h.errorres;
 s->s.h.refidx[2]  = get_bits(>gb, 3);
 s->s.h.signbias[2]= get_bits1(>gb) && 

[FFmpeg-devel] [PATCH 29/42] avcodec/vp3: Switch to ProgressFrames

2023-09-19 Thread Andreas Rheinhardt
Avoids implicit av_frame_ref() and therefore allocations
and error checks. It also avoids explicitly allocating
the AVFrames (done implicitly when getting the buffer)
and it also allows to reuse the flushing code for freeing
the ProgressFrames.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/vp3.c | 148 +--
 1 file changed, 54 insertions(+), 94 deletions(-)

diff --git a/libavcodec/vp3.c b/libavcodec/vp3.c
index 98dabfc907..e8e1ebff56 100644
--- a/libavcodec/vp3.c
+++ b/libavcodec/vp3.c
@@ -46,8 +46,8 @@
 #include "hpeldsp.h"
 #include "jpegquanttables.h"
 #include "mathops.h"
+#include "progressframe.h"
 #include "thread.h"
-#include "threadframe.h"
 #include "videodsp.h"
 #include "vp3data.h"
 #include "vp4data.h"
@@ -180,9 +180,9 @@ typedef struct Vp3DecodeContext {
 int version;
 int width, height;
 int chroma_x_shift, chroma_y_shift;
-ThreadFrame golden_frame;
-ThreadFrame last_frame;
-ThreadFrame current_frame;
+ProgressFrame golden_frame;
+ProgressFrame last_frame;
+ProgressFrame current_frame;
 int keyframe;
 uint8_t idct_permutation[64];
 uint8_t idct_scantable[64];
@@ -336,12 +336,9 @@ static void vp3_decode_flush(AVCodecContext *avctx)
 {
 Vp3DecodeContext *s = avctx->priv_data;
 
-if (s->golden_frame.f)
-ff_thread_release_ext_buffer(avctx, >golden_frame);
-if (s->last_frame.f)
-ff_thread_release_ext_buffer(avctx, >last_frame);
-if (s->current_frame.f)
-ff_thread_release_ext_buffer(avctx, >current_frame);
+ff_thread_progress_unref(avctx, >golden_frame);
+ff_thread_progress_unref(avctx, >last_frame);
+ff_thread_progress_unref(avctx, >current_frame);
 }
 
 static av_cold int vp3_decode_end(AVCodecContext *avctx)
@@ -355,9 +352,6 @@ static av_cold int vp3_decode_end(AVCodecContext *avctx)
 
 /* release all frames */
 vp3_decode_flush(avctx);
-av_frame_free(>current_frame.f);
-av_frame_free(>last_frame.f);
-av_frame_free(>golden_frame.f);
 
 for (int i = 0; i < FF_ARRAY_ELEMS(s->coeff_vlc); i++)
 ff_vlc_free(>coeff_vlc[i]);
@@ -1899,10 +1893,9 @@ static void vp3_draw_horiz_band(Vp3DecodeContext *s, int 
y)
 /* At the end of the frame, report INT_MAX instead of the height of
  * the frame. This makes the other threads' ff_thread_await_progress()
  * calls cheaper, because they don't have to clip their values. */
-ff_thread_report_progress(>current_frame,
+ff_thread_progress_report(>current_frame,
   y_flipped == s->height ? INT_MAX
- : y_flipped - 1,
-  0);
+ : y_flipped - 1);
 }
 
 if (!s->avctx->draw_horiz_band)
@@ -1933,7 +1926,7 @@ static void vp3_draw_horiz_band(Vp3DecodeContext *s, int 
y)
 static void await_reference_row(Vp3DecodeContext *s, const Vp3Fragment 
*fragment,
 int motion_y, int y)
 {
-const ThreadFrame *ref_frame;
+const ProgressFrame *ref_frame;
 int ref_row;
 int border = motion_y & 1;
 
@@ -1946,7 +1939,7 @@ static void await_reference_row(Vp3DecodeContext *s, 
const Vp3Fragment *fragment
 ref_row = y + (motion_y >> 1);
 ref_row = FFMAX(FFABS(ref_row), ref_row + 8 + border);
 
-ff_thread_await_progress(ref_frame, ref_row, 0);
+ff_thread_progress_await(ref_frame, ref_row);
 }
 
 #if CONFIG_VP4_DECODER
@@ -2057,12 +2050,12 @@ static void render_slice(Vp3DecodeContext *s, int slice)
 int16_t *block = s->block;
 int motion_x = 0xdeadbeef, motion_y = 0xdeadbeef;
 /* When decoding keyframes, the earlier frames may not be available,
- * so to avoid using undefined pointer arithmetic on them we just
- * use the current frame instead. Nothing is ever read from these
- * frames in case of a keyframe. */
-const AVFrame *last_frame   = s->last_frame.f->data[0]   ?
+ * so we just use the current frame in this case instead;
+ * it also avoid using undefined pointer arithmetic. Nothing is
+ * ever read from these frames in case of a keyframe. */
+const AVFrame *last_frame   = s->last_frame.f   ?
   s->last_frame.f   : s->current_frame.f;
-const AVFrame *golden_frame = s->golden_frame.f->data[0] ?
+const AVFrame *golden_frame = s->golden_frame.f ?
   s->golden_frame.f : s->current_frame.f;
 int motion_halfpel_index;
 int first_pixel;
@@ -2302,18 +2295,6 @@ static av_cold int allocate_tables(AVCodecContext *avctx)
 return 0;
 }
 
-static av_cold int init_frames(Vp3DecodeContext *s)
-{
-s->current_frame.f = av_frame_alloc();
-s->last_frame.f= av_frame_alloc();
-s->golden_frame.f  = av_frame_alloc();
-
-if (!s->current_frame.f || !s->last_frame.f || !s->golden_frame.f)
-return 

[FFmpeg-devel] [PATCH 28/42] avcodec/mimic: Switch to ProgressFrames

2023-09-19 Thread Andreas Rheinhardt
Avoids implicit av_frame_ref() and therefore allocations
and error checks.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/mimic.c | 60 --
 1 file changed, 21 insertions(+), 39 deletions(-)

diff --git a/libavcodec/mimic.c b/libavcodec/mimic.c
index a846a07a40..82da20bbf4 100644
--- a/libavcodec/mimic.c
+++ b/libavcodec/mimic.c
@@ -33,8 +33,8 @@
 #include "bswapdsp.h"
 #include "hpeldsp.h"
 #include "idctdsp.h"
+#include "progressframe.h"
 #include "thread.h"
-#include "threadframe.h"
 
 #define MIMIC_HEADER_SIZE   20
 #define MIMIC_VLC_BITS  11
@@ -51,7 +51,7 @@ typedef struct MimicContext {
 int cur_index;
 int prev_index;
 
-ThreadFrame frames [16];
+ProgressFrame   frames[16];
 
 DECLARE_ALIGNED(32, int16_t, dct_block)[64];
 
@@ -104,16 +104,12 @@ static const uint8_t col_zag[64] = {
 static av_cold int mimic_decode_end(AVCodecContext *avctx)
 {
 MimicContext *ctx = avctx->priv_data;
-int i;
 
 av_freep(>swap_buf);
 ctx->swap_buf_size = 0;
 
-for (i = 0; i < FF_ARRAY_ELEMS(ctx->frames); i++) {
-if (ctx->frames[i].f)
-ff_thread_release_ext_buffer(avctx, >frames[i]);
-av_frame_free(>frames[i].f);
-}
+for (int i = 0; i < FF_ARRAY_ELEMS(ctx->frames); i++)
+ff_thread_progress_unref(avctx, >frames[i]);
 
 return 0;
 }
@@ -128,7 +124,6 @@ static av_cold int mimic_decode_init(AVCodecContext *avctx)
 {
 static AVOnce init_static_once = AV_ONCE_INIT;
 MimicContext *ctx = avctx->priv_data;
-int i;
 
 ctx->prev_index = 0;
 ctx->cur_index  = 15;
@@ -139,12 +134,6 @@ static av_cold int mimic_decode_init(AVCodecContext *avctx)
 ff_idctdsp_init(>idsp, avctx);
 ff_permute_scantable(ctx->permutated_scantable, col_zag, 
ctx->idsp.idct_permutation);
 
-for (i = 0; i < FF_ARRAY_ELEMS(ctx->frames); i++) {
-ctx->frames[i].f = av_frame_alloc();
-if (!ctx->frames[i].f)
-return AVERROR(ENOMEM);
-}
-
 ff_thread_once(_static_once, mimic_init_static);
 
 return 0;
@@ -154,7 +143,6 @@ static av_cold int mimic_decode_init(AVCodecContext *avctx)
 static int mimic_decode_update_thread_context(AVCodecContext *avctx, const 
AVCodecContext *avctx_from)
 {
 MimicContext *dst = avctx->priv_data, *src = avctx_from->priv_data;
-int i, ret;
 
 if (avctx == avctx_from)
 return 0;
@@ -162,13 +150,10 @@ static int 
mimic_decode_update_thread_context(AVCodecContext *avctx, const AVCod
 dst->cur_index  = src->next_cur_index;
 dst->prev_index = src->next_prev_index;
 
-for (i = 0; i < FF_ARRAY_ELEMS(dst->frames); i++) {
-ff_thread_release_ext_buffer(avctx, >frames[i]);
-if (i != src->next_cur_index && src->frames[i].f->data[0]) {
-ret = ff_thread_ref_frame(>frames[i], >frames[i]);
-if (ret < 0)
-return ret;
-}
+for (int i = 0; i < FF_ARRAY_ELEMS(dst->frames); i++) {
+ff_thread_progress_unref(avctx, >frames[i]);
+if (i != src->next_cur_index && src->frames[i].f)
+ff_thread_progress_ref(>frames[i], >frames[i]);
 }
 
 return 0;
@@ -291,11 +276,10 @@ static int decode(MimicContext *ctx, int quality, int 
num_coeffs,
 } else {
 unsigned int backref = get_bits(>gb, 4);
 int index= (ctx->cur_index + backref) & 15;
-uint8_t *p   = ctx->frames[index].f->data[0];
 
-if (index != ctx->cur_index && p) {
-ff_thread_await_progress(>frames[index],
- cur_row, 0);
+if (index != ctx->cur_index && ctx->frames[index].f) {
+const uint8_t *p = ctx->frames[index].f->data[0];
+ff_thread_progress_await(>frames[index], 
cur_row);
 p += src -
  ctx->frames[ctx->prev_index].f->data[plane];
 ctx->hdsp.put_pixels_tab[1][0](dst, p, stride, 8);
@@ -305,8 +289,7 @@ static int decode(MimicContext *ctx, int quality, int 
num_coeffs,
 }
 }
 } else {
-ff_thread_await_progress(>frames[ctx->prev_index],
- cur_row, 0);
+ff_thread_progress_await(>frames[ctx->prev_index], 
cur_row);
 ctx->hdsp.put_pixels_tab[1][0](dst, src, stride, 8);
 }
 src += 8;
@@ -315,8 +298,7 @@ static int decode(MimicContext *ctx, int quality, int 
num_coeffs,
 src += (stride - ctx->num_hblocks[plane]) << 3;
 dst += (stride - ctx->num_hblocks[plane]) << 3;
 
-ff_thread_report_progress(>frames[ctx->cur_index],
-

[FFmpeg-devel] [PATCH 27/42] avcodec/pthread_frame: Add new progress API

2023-09-19 Thread Andreas Rheinhardt
Frame-threaded decoders with inter-frame dependencies
use the ThreadFrame API for syncing. It works as follows:

During init each thread allocates an AVFrame for every
ThreadFrame.

Thread A reads the header of its packet and allocates
a buffer for an AVFrame with ff_thread_get_ext_buffer()
(which also allocates a small structure that is shared
with other references to this frame) and sets its fields,
including side data. Then said thread calls ff_thread_finish_setup().
>From that moment onward it is not allowed to change any
of the AVFrame fields at all any more, but it may change
fields which are an indirection away, like the content of
AVFrame.data or already existing side data.

After thread A has called ff_thread_finish_setup(),
another thread (the user one) calls the codec's update_thread_context
callback which in turn calls ff_thread_ref_frame() which
calls av_frame_ref() which reads every field of A's
AVFrame; hence the above restriction on modifications
of the AVFrame (as any modification of the AVFrame by A after
ff_thread_finish_setup() would be a data race). Of course,
this av_frame_ref() also incurs allocations and therefore
needs to be checked. ff_thread_ref_frame() also references
the small structure used for communicating progress.

This av_frame_ref() makes it awkward to propagate values that
only become known during decoding to later threads (in case of
frame reordering or other mechanisms of delayed output (like
show-existing-frames) it's not the decoding thread, but a later
thread that returns the AVFrame). E.g. for VP9 when exporting video
encoding parameters as side data the number of blocks only
becomes known during decoding, so one can't allocate the side data
before ff_thread_finish_setup(). It is currently being done afterwards
and this leads to a data race in the vp9-encparams test when using
frame-threading. Returning decode_error_flags is also complicated
by this.

To perform this exchange a buffer shared between the references
is needed (notice that simply giving the later threads a pointer
to the original AVFrame does not work, because said AVFrame will
be reused lateron when thread A decodes the next packet given to it).
One could extend the buffer already used for progress for this
or use a new one (requiring yet another allocation), yet both
of these approaches have the drawback of being unnatural, ugly
and requiring quite a lot of ad-hoc code. E.g. in case of the VP9
side data mentioned above one could not simply use the helper
that allocates and adds the side data to an AVFrame in one go.

The ProgressFrame API meanwhile offers a different solution to all
of this. It is based around the idea that the most natural
shared object for sharing information about an AVFrame between
decoding threads is the AVFrame itself. To actually implement this
the AVFrame needs to be reference counted. This is achieved by
putting a (ownership) pointer into a shared (and opaque) structure
that is managed by the RefStruct API and which also contains
the stuff necessary for progress reporting.
The users get a pointer to this AVFrame with the understanding
that the owner may set all the fields until it has indicated
that it has finished decoding this AVFrame; then the users are
allowed to read everything. Every decoder may of course employ
a different contract than the one outlined above.

Given that there is no underlying av_frame_ref(), creating
references to a ProgressFrame can't fail. Only
ff_thread_progress_get_buffer() can fail, but given that
it will replace calls to ff_thread_get_ext_buffer() it is
at places where errors are already expected and properly
taken care of.

The ProgressFrames are empty (i.e. the AVFrame pointer is NULL
and the AVFrames are not allocated during init at all)
while not being in use; ff_thread_progress_get_buffer() both
sets up the actual ProgressFrame and already calls
ff_thread_get_buffer(). So instead of checking for
ThreadFrame.f->data[0] or ThreadFrame.f->buf[0] being NULL
for "this reference frame is non-existing" one should check for
ProgressFrame.f.

This also implies that one can only set AVFrame properties
after having allocated the buffer. This restriction is not deep:
if it becomes onerous for any codec, ff_thread_progress_get_buffer()
can be broken up. The user would then have to get a buffer
himself.

In order to avoid unnecessary allocations, the shared structure
is pooled, so that both the structure as well as the AVFrame
itself are reused. This means that there won't be lots of
unnecessary allocations in case of non-frame-threaded decoding.
It might even turn out to have fewer than the current code
(the current code allocates AVFrames for every DPB slot, but
these are often excessively large and not completely used;
the new code allocates them on demand). Pooling relies on the
reset function of the RefStruct pool API, it would be impossible
to implement with the AVBufferPool API.

Finally, ProgressFrames store their owner in the shared, opaque

[FFmpeg-devel] [PATCH 26/42] avcodec/refstruct: Allow to use a dynamic opaque

2023-09-19 Thread Andreas Rheinhardt
This is in preparation for a new ThreadFrame-API
based around RefStruct to allow to pass the AVCodecContext*
to ff_thread_release_buffer().

Signed-off-by: Andreas Rheinhardt 
---
Now that thread-unsafe callbacks are no more, one could
also just use av_frame_unref() instead of ff_thread_release_buffer().
But this is IMO more elegant.

 libavcodec/cbs.c   |  8 ++--
 libavcodec/refstruct.c | 83 +-
 libavcodec/refstruct.h | 83 ++
 3 files changed, 146 insertions(+), 28 deletions(-)

diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c
index 00c462b09d..40235ce647 100644
--- a/libavcodec/cbs.c
+++ b/libavcodec/cbs.c
@@ -903,11 +903,13 @@ static const CodedBitstreamUnitTypeDescriptor
 
 static void *cbs_alloc_content(const CodedBitstreamUnitTypeDescriptor *desc)
 {
+FFRefStructUnrefCB unref_cb;
+unref_cb.unref = desc->content_type == CBS_CONTENT_TYPE_COMPLEX
+? desc->type.complex.content_free
+: cbs_default_free_unit_content;
 return ff_refstruct_alloc_ext_c(desc->content_size, 0,
 (FFRefStructOpaque){ .c = desc },
-desc->content_type == 
CBS_CONTENT_TYPE_COMPLEX
-? desc->type.complex.content_free
-: cbs_default_free_unit_content);
+unref_cb);
 }
 
 int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx,
diff --git a/libavcodec/refstruct.c b/libavcodec/refstruct.c
index 2108ff8163..817a8a455a 100644
--- a/libavcodec/refstruct.c
+++ b/libavcodec/refstruct.c
@@ -20,6 +20,8 @@
 #include 
 #include 
 
+#include "config.h"
+
 #include "internal.h"
 #include "refstruct.h"
 
@@ -37,8 +39,11 @@ typedef struct RefCount {
  */
 atomic_uintptr_t  refcount;
 FFRefStructOpaque opaque;
-void (*free_cb)(FFRefStructOpaque opaque, void *obj);
+FFRefStructUnrefCB free_cb;
 void (*free)(void *ref);
+#if defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 1
+unsigned flags;
+#endif
 } RefCount;
 
 #if __STDC_VERSION__ >= 201112L
@@ -63,16 +68,19 @@ static void *get_userdata(void *buf)
 }
 
 static void refcount_init(RefCount *ref, FFRefStructOpaque opaque,
-  void (*free_cb)(FFRefStructOpaque opaque, void *obj))
+  unsigned flags, FFRefStructUnrefCB free_cb)
 {
 atomic_init(>refcount, 1);
 ref->opaque  = opaque;
 ref->free_cb = free_cb;
 ref->free= av_free;
+#if defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 1
+ref->flags = flags;
+#endif
 }
 
 void *ff_refstruct_alloc_ext_c(size_t size, unsigned flags, FFRefStructOpaque 
opaque,
-   void (*free_cb)(FFRefStructOpaque opaque, void 
*obj))
+   FFRefStructUnrefCB free_cb)
 {
 void *buf, *obj;
 
@@ -81,7 +89,7 @@ void *ff_refstruct_alloc_ext_c(size_t size, unsigned flags, 
FFRefStructOpaque op
 buf = av_malloc(size + REFCOUNT_OFFSET);
 if (!buf)
 return NULL;
-refcount_init(buf, opaque, free_cb);
+refcount_init(buf, opaque, flags, free_cb);
 obj = get_userdata(buf);
 if (!(flags & FF_REFSTRUCT_FLAG_NO_ZEROING))
 memset(obj, 0, size);
@@ -105,9 +113,31 @@ void ff_refstruct_unref(void *objp)
 memcpy(objp, &(void *){ NULL }, sizeof(obj));
 
 ref = get_refcount(obj);
+av_assert1(!(ref->flags & FF_REFSTRUCT_FLAG_DYNAMIC_OPAQUE));
+if (atomic_fetch_sub_explicit(>refcount, 1, memory_order_acq_rel) == 
1) {
+if (ref->free_cb.unref)
+ref->free_cb.unref(ref->opaque, obj);
+ref->free(ref);
+}
+
+return;
+}
+
+void ff_refstruct_unref_ext_c(FFRefStructOpaque opaque, void *objp)
+{
+void *obj;
+RefCount *ref;
+
+memcpy(, objp, sizeof(obj));
+if (!obj)
+return;
+memcpy(objp, &(void *){ NULL }, sizeof(obj));
+
+ref = get_refcount(obj);
+av_assert1(ref->flags & FF_REFSTRUCT_FLAG_DYNAMIC_OPAQUE);
 if (atomic_fetch_sub_explicit(>refcount, 1, memory_order_acq_rel) == 
1) {
-if (ref->free_cb)
-ref->free_cb(ref->opaque, obj);
+if (ref->free_cb.unref_ext)
+ref->free_cb.unref_ext(opaque, ref->opaque, obj);
 ref->free(ref);
 }
 
@@ -161,7 +191,7 @@ struct FFRefStructPool {
 size_t size;
 FFRefStructOpaque opaque;
 int  (*init_cb)(FFRefStructOpaque opaque, void *obj);
-void (*reset_cb)(FFRefStructOpaque opaque, void *obj);
+FFRefStructUnrefCB reset_cb;
 void (*free_entry_cb)(FFRefStructOpaque opaque, void *obj);
 void (*free_cb)(FFRefStructOpaque opaque);
 
@@ -221,14 +251,23 @@ static void pool_reset_entry(FFRefStructOpaque opaque, 
void *entry)
 {
 FFRefStructPool *pool = opaque.nc;
 
-pool->reset_cb(pool->opaque, entry);
+pool->reset_cb.unref(pool->opaque, entry);
+}
+

[FFmpeg-devel] [PATCH 25/42] avcodec/vp9: Join extradata buffer pools

2023-09-19 Thread Andreas Rheinhardt
Up until now each thread had its own buffer pool for extradata
buffers when using frame-threading. Each thread can have at most
three references to extradata and in the long run, each thread's
bufferpool seems to fill up with three entries. But given
that at any given time there can be at most 2 + number of threads
entries used (the oldest thread can have two references to preceding
frames that are not currently decoded and each thread has its own
current frame, but there can be no references to any other frames),
this is wasteful. This commit therefore uses a single buffer pool
that is synced across threads.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/vp9.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c
index 4acfca2b4f..dac81fd712 100644
--- a/libavcodec/vp9.c
+++ b/libavcodec/vp9.c
@@ -1845,6 +1845,8 @@ static int 
vp9_decode_update_thread_context(AVCodecContext *dst, const AVCodecCo
 return ret;
 }
 }
+ff_refstruct_replace(>frame_extradata_pool, ssrc->frame_extradata_pool);
+s->frame_extradata_pool_size = ssrc->frame_extradata_pool_size;
 
 s->s.h.invisible = ssrc->s.h.invisible;
 s->s.h.keyframe = ssrc->s.h.keyframe;
-- 
2.34.1

___
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".


[FFmpeg-devel] [PATCH 24/42] avcodec/refstruct: Allow to share pools

2023-09-19 Thread Andreas Rheinhardt
To do this, make FFRefStructPool itself refcounted according
to the RefStruct API.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/refstruct.c | 29 -
 libavcodec/refstruct.h |  5 -
 2 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/libavcodec/refstruct.c b/libavcodec/refstruct.c
index f8d040874d..2108ff8163 100644
--- a/libavcodec/refstruct.c
+++ b/libavcodec/refstruct.c
@@ -187,7 +187,7 @@ static void pool_free(FFRefStructPool *pool)
 pthread_mutex_destroy(>mutex);
 if (pool->free_cb)
 pool->free_cb(pool->opaque);
-av_free(pool);
+av_free(get_refcount(pool));
 }
 
 static void pool_free_entry(FFRefStructPool *pool, RefCount *ref)
@@ -278,13 +278,17 @@ void *ff_refstruct_pool_get(FFRefStructPool *pool)
 return ret;
 }
 
-void ff_refstruct_pool_uninit(FFRefStructPool **poolp)
+static void pool_unref(void *ref)
 {
-FFRefStructPool *pool = *poolp;
-RefCount *entry;
+FFRefStructPool *pool = get_userdata(ref);
+if (atomic_fetch_sub_explicit(>refcount, 1, memory_order_acq_rel) == 
1)
+pool_free(pool);
+}
 
-if (!pool)
-return;
+static void refstruct_pool_uninit(FFRefStructOpaque unused, void *obj)
+{
+FFRefStructPool *pool = obj;
+RefCount *entry;
 
 pthread_mutex_lock(>mutex);
 av_assert1(!pool->uninited);
@@ -298,11 +302,6 @@ void ff_refstruct_pool_uninit(FFRefStructPool **poolp)
 pool_free_entry(pool, entry);
 entry = next;
 }
-
-if (atomic_fetch_sub_explicit(>refcount, 1, memory_order_acq_rel) == 
1)
-pool_free(pool);
-
-*poolp = NULL;
 }
 
 FFRefStructPool *ff_refstruct_pool_alloc(size_t size, unsigned flags)
@@ -317,11 +316,13 @@ FFRefStructPool *ff_refstruct_pool_alloc_ext_c(size_t 
size, unsigned flags,
void 
(*free_entry_cb)(FFRefStructOpaque opaque, void *obj),
void 
(*free_cb)(FFRefStructOpaque opaque))
 {
-FFRefStructPool *pool = av_mallocz(sizeof(*pool));
+FFRefStructPool *pool = ff_refstruct_alloc_ext(sizeof(*pool), 0, NULL,
+   refstruct_pool_uninit);
 int err;
 
 if (!pool)
 return NULL;
+get_refcount(pool)->free = pool_unref;
 
 pool->size  = size;
 pool->opaque= opaque;
@@ -348,7 +349,9 @@ FFRefStructPool *ff_refstruct_pool_alloc_ext_c(size_t size, 
unsigned flags,
 
 err = pthread_mutex_init(>mutex, NULL);
 if (err) {
-av_free(pool);
+// Don't call ff_refstruct_uninit() on pool, as it hasn't been properly
+// set up and is just a POD right now.
+av_free(get_refcount(pool));
 return NULL;
 }
 return pool;
diff --git a/libavcodec/refstruct.h b/libavcodec/refstruct.h
index ce3830977f..d525be61e8 100644
--- a/libavcodec/refstruct.h
+++ b/libavcodec/refstruct.h
@@ -285,6 +285,9 @@ void *ff_refstruct_pool_get(FFRefStructPool *pool);
  * @param poolp pointer to a pointer to either NULL or a pool to be freed.
  *  `*poolp` will be set to NULL.
  */
-void ff_refstruct_pool_uninit(FFRefStructPool **poolp);
+static inline void ff_refstruct_pool_uninit(FFRefStructPool **poolp)
+{
+ff_refstruct_unref(poolp);
+}
 
 #endif /* AVCODEC_REFSTRUCT_H */
-- 
2.34.1

___
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".


[FFmpeg-devel] [PATCH 23/42] avcodec/vaapi_encode: Use RefStruct pool API, stop abusing AVBuffer API

2023-09-19 Thread Andreas Rheinhardt
Up until now, the VAAPI encoder uses fake data with the
AVBuffer-API: The data pointer does not point to real memory,
but is instead just a VABufferID converted to a pointer.
This has probably been copied from the VAAPI-hwcontext-API
(which presumably does it to avoid allocations).

This commit changes this without causing additional allocations
by switching to the RefStruct-pool API.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/vaapi_encode.c | 60 ---
 libavcodec/vaapi_encode.h |  5 ++--
 2 files changed, 28 insertions(+), 37 deletions(-)

diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c
index 0316fe5c18..3f06d7f21e 100644
--- a/libavcodec/vaapi_encode.c
+++ b/libavcodec/vaapi_encode.c
@@ -16,11 +16,11 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#include "config_components.h"
-
 #include 
 #include 
 
+#include "config.h"
+
 #include "libavutil/avassert.h"
 #include "libavutil/common.h"
 #include "libavutil/internal.h"
@@ -30,6 +30,7 @@
 #include "vaapi_encode.h"
 #include "encode.h"
 #include "avcodec.h"
+#include "refstruct.h"
 
 const AVCodecHWConfigInternal *const ff_vaapi_encode_hw_configs[] = {
 HW_CONFIG_ENCODER_FRAMES(VAAPI, VAAPI),
@@ -309,12 +310,12 @@ static int vaapi_encode_issue(AVCodecContext *avctx,
 pic->recon_surface = (VASurfaceID)(uintptr_t)pic->recon_image->data[3];
 av_log(avctx, AV_LOG_DEBUG, "Recon surface is %#x.\n", pic->recon_surface);
 
-pic->output_buffer_ref = av_buffer_pool_get(ctx->output_buffer_pool);
+pic->output_buffer_ref = ff_refstruct_pool_get(ctx->output_buffer_pool);
 if (!pic->output_buffer_ref) {
 err = AVERROR(ENOMEM);
 goto fail;
 }
-pic->output_buffer = (VABufferID)(uintptr_t)pic->output_buffer_ref->data;
+pic->output_buffer = *pic->output_buffer_ref;
 av_log(avctx, AV_LOG_DEBUG, "Output buffer is %#x.\n",
pic->output_buffer);
 
@@ -645,7 +646,7 @@ fail_at_end:
 av_freep(>slices);
 av_freep(>roi);
 av_frame_free(>recon_image);
-av_buffer_unref(>output_buffer_ref);
+ff_refstruct_unref(>output_buffer_ref);
 pic->output_buffer = VA_INVALID_ID;
 return err;
 }
@@ -713,7 +714,7 @@ static int vaapi_encode_output(AVCodecContext *avctx,
 pic->opaque_ref = NULL;
 }
 
-av_buffer_unref(>output_buffer_ref);
+ff_refstruct_unref(>output_buffer_ref);
 pic->output_buffer = VA_INVALID_ID;
 
 av_log(avctx, AV_LOG_DEBUG, "Output read for pic %"PRId64"/%"PRId64".\n",
@@ -723,7 +724,7 @@ static int vaapi_encode_output(AVCodecContext *avctx,
 fail_mapped:
 vaUnmapBuffer(ctx->hwctx->display, pic->output_buffer);
 fail:
-av_buffer_unref(>output_buffer_ref);
+ff_refstruct_unref(>output_buffer_ref);
 pic->output_buffer = VA_INVALID_ID;
 return err;
 }
@@ -738,7 +739,7 @@ static int vaapi_encode_discard(AVCodecContext *avctx,
"%"PRId64"/%"PRId64".\n",
pic->display_order, pic->encode_order);
 
-av_buffer_unref(>output_buffer_ref);
+ff_refstruct_unref(>output_buffer_ref);
 pic->output_buffer = VA_INVALID_ID;
 }
 
@@ -2420,28 +2421,25 @@ static av_cold int vaapi_encode_init_roi(AVCodecContext 
*avctx)
 return 0;
 }
 
-static void vaapi_encode_free_output_buffer(void *opaque,
-uint8_t *data)
+static void vaapi_encode_free_output_buffer(FFRefStructOpaque opaque,
+void *obj)
 {
-AVCodecContext   *avctx = opaque;
+AVCodecContext   *avctx = opaque.nc;
 VAAPIEncodeContext *ctx = avctx->priv_data;
-VABufferID buffer_id;
-
-buffer_id = (VABufferID)(uintptr_t)data;
+VABufferID *buffer_id_ref = obj;
+VABufferID buffer_id = *buffer_id_ref;
 
 vaDestroyBuffer(ctx->hwctx->display, buffer_id);
 
 av_log(avctx, AV_LOG_DEBUG, "Freed output buffer %#x\n", buffer_id);
 }
 
-static AVBufferRef *vaapi_encode_alloc_output_buffer(void *opaque,
- size_t size)
+static int vaapi_encode_alloc_output_buffer(FFRefStructOpaque opaque, void 
*obj)
 {
-AVCodecContext   *avctx = opaque;
+AVCodecContext   *avctx = opaque.nc;
 VAAPIEncodeContext *ctx = avctx->priv_data;
-VABufferID buffer_id;
+VABufferID *buffer_id = obj;
 VAStatus vas;
-AVBufferRef *ref;
 
 // The output buffer size is fixed, so it needs to be large enough
 // to hold the largest possible compressed frame.  We assume here
@@ -2450,25 +2448,16 @@ static AVBufferRef 
*vaapi_encode_alloc_output_buffer(void *opaque,
 vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context,
  VAEncCodedBufferType,
  3 * ctx->surface_width * ctx->surface_height +
- (1 << 16), 1, 0, _id);
+ (1 << 16), 1, 0, buffer_id);
 if (vas != VA_STATUS_SUCCESS) {
  

[FFmpeg-devel] [PATCH 22/42] avcodec/vp9: Use RefStruct-pool API for extradata

2023-09-19 Thread Andreas Rheinhardt
It avoids allocations and corresponding error checks.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/vp9.c   | 24 +---
 libavcodec/vp9dec.h|  3 +--
 libavcodec/vp9shared.h |  2 +-
 3 files changed, 11 insertions(+), 18 deletions(-)

diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c
index c9cc81ec94..4acfca2b4f 100644
--- a/libavcodec/vp9.c
+++ b/libavcodec/vp9.c
@@ -100,7 +100,7 @@ static void vp9_tile_data_free(VP9TileData *td)
 static void vp9_frame_unref(AVCodecContext *avctx, VP9Frame *f)
 {
 ff_thread_release_ext_buffer(avctx, >tf);
-av_buffer_unref(>extradata);
+ff_refstruct_unref(>extradata);
 ff_refstruct_unref(>hwaccel_picture_private);
 f->segmentation_map = NULL;
 }
@@ -116,8 +116,9 @@ static int vp9_frame_alloc(AVCodecContext *avctx, VP9Frame 
*f)
 
 sz = 64 * s->sb_cols * s->sb_rows;
 if (sz != s->frame_extradata_pool_size) {
-av_buffer_pool_uninit(>frame_extradata_pool);
-s->frame_extradata_pool = av_buffer_pool_init(sz * (1 + 
sizeof(VP9mvrefPair)), NULL);
+ff_refstruct_pool_uninit(>frame_extradata_pool);
+s->frame_extradata_pool = ff_refstruct_pool_alloc(sz * (1 + 
sizeof(VP9mvrefPair)),
+  
FF_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME);
 if (!s->frame_extradata_pool) {
 s->frame_extradata_pool_size = 0;
 ret = AVERROR(ENOMEM);
@@ -125,15 +126,14 @@ static int vp9_frame_alloc(AVCodecContext *avctx, 
VP9Frame *f)
 }
 s->frame_extradata_pool_size = sz;
 }
-f->extradata = av_buffer_pool_get(s->frame_extradata_pool);
+f->extradata = ff_refstruct_pool_get(s->frame_extradata_pool);
 if (!f->extradata) {
 ret = AVERROR(ENOMEM);
 goto fail;
 }
-memset(f->extradata->data, 0, f->extradata->size);
 
-f->segmentation_map = f->extradata->data;
-f->mv = (VP9mvrefPair *) (f->extradata->data + sz);
+f->segmentation_map = f->extradata;
+f->mv = (VP9mvrefPair *) ((char*)f->extradata + sz);
 
 ret = ff_hwaccel_frame_priv_alloc(avctx, >hwaccel_picture_private);
 if (ret < 0)
@@ -154,9 +154,7 @@ static int vp9_frame_ref(AVCodecContext *avctx, VP9Frame 
*dst, VP9Frame *src)
 if (ret < 0)
 return ret;
 
-dst->extradata = av_buffer_ref(src->extradata);
-if (!dst->extradata)
-goto fail;
+dst->extradata = ff_refstruct_ref(src->extradata);
 
 dst->segmentation_map = src->segmentation_map;
 dst->mv = src->mv;
@@ -166,10 +164,6 @@ static int vp9_frame_ref(AVCodecContext *avctx, VP9Frame 
*dst, VP9Frame *src)
   src->hwaccel_picture_private);
 
 return 0;
-
-fail:
-vp9_frame_unref(avctx, dst);
-return AVERROR(ENOMEM);
 }
 
 static int update_size(AVCodecContext *avctx, int w, int h)
@@ -1245,7 +1239,7 @@ static av_cold int vp9_decode_free(AVCodecContext *avctx)
 vp9_frame_unref(avctx, >s.frames[i]);
 av_frame_free(>s.frames[i].tf.f);
 }
-av_buffer_pool_uninit(>frame_extradata_pool);
+ff_refstruct_pool_uninit(>frame_extradata_pool);
 for (i = 0; i < 8; i++) {
 ff_thread_release_ext_buffer(avctx, >s.refs[i]);
 av_frame_free(>s.refs[i].f);
diff --git a/libavcodec/vp9dec.h b/libavcodec/vp9dec.h
index de7aba0458..013aac49eb 100644
--- a/libavcodec/vp9dec.h
+++ b/libavcodec/vp9dec.h
@@ -28,7 +28,6 @@
 #include 
 #include 
 
-#include "libavutil/buffer.h"
 #include "libavutil/mem_internal.h"
 #include "libavutil/thread.h"
 #include "libavutil/internal.h"
@@ -161,7 +160,7 @@ typedef struct VP9Context {
 uint8_t mvstep[3][2];
 
 // frame specific buffer pools
-AVBufferPool *frame_extradata_pool;
+struct FFRefStructPool *frame_extradata_pool;
 int frame_extradata_pool_size;
 } VP9Context;
 
diff --git a/libavcodec/vp9shared.h b/libavcodec/vp9shared.h
index e54f23544e..b445a2a746 100644
--- a/libavcodec/vp9shared.h
+++ b/libavcodec/vp9shared.h
@@ -64,7 +64,7 @@ typedef struct VP9mvrefPair {
 
 typedef struct VP9Frame {
 ThreadFrame tf;
-AVBufferRef *extradata;
+void *extradata;   ///< RefStruct reference
 uint8_t *segmentation_map;
 VP9mvrefPair *mv;
 int uses_2pass;
-- 
2.34.1

___
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".


[FFmpeg-devel] [PATCH 21/42] avcodec/refstruct: Allow to always return zeroed pool entries

2023-09-19 Thread Andreas Rheinhardt
This is in preparation for the following commit.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/refstruct.c | 10 ++
 libavcodec/refstruct.h |  8 
 2 files changed, 18 insertions(+)

diff --git a/libavcodec/refstruct.c b/libavcodec/refstruct.c
index 7539b7942e..f8d040874d 100644
--- a/libavcodec/refstruct.c
+++ b/libavcodec/refstruct.c
@@ -262,6 +262,10 @@ static int refstruct_pool_get_ext(void *datap, 
FFRefStructPool *pool)
 }
 }
 atomic_fetch_add_explicit(>refcount, 1, memory_order_relaxed);
+
+if (pool->pool_flags & FF_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME)
+memset(ret, 0, pool->size);
+
 memcpy(datap, , sizeof(ret));
 
 return 0;
@@ -334,6 +338,12 @@ FFRefStructPool *ff_refstruct_pool_alloc_ext_c(size_t 
size, unsigned flags,
 flags &= ~FF_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR;
 pool->pool_flags= flags;
 
+if (flags & FF_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME) {
+// We will zero the buffer before every use, so zeroing
+// upon allocating the buffer is unnecessary.
+pool->entry_flags |= FF_REFSTRUCT_FLAG_NO_ZEROING;
+}
+
 atomic_init(>refcount, 1);
 
 err = pthread_mutex_init(>mutex, NULL);
diff --git a/libavcodec/refstruct.h b/libavcodec/refstruct.h
index e2fe45e77d..ce3830977f 100644
--- a/libavcodec/refstruct.h
+++ b/libavcodec/refstruct.h
@@ -207,6 +207,14 @@ typedef struct FFRefStructPool FFRefStructPool;
  * the callbacks applied earlier (init_cb potentially followed by reset_cb).
  */
 #define FF_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR(1 << 17)
+/**
+ * If this flag is set, the entries will be zeroed before
+ * being returned to the user (after the init or reset callbacks
+ * have been called (if provided)). Furthermore, it also makes
+ * the pool behave as if the FF_REFSTRUCT_POOL_FLAG_NO_ZEROING
+ * flag had been provided.
+ */
+#define FF_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME   (1 << 18)
 
 /**
  * Equivalent to ff_refstruct_pool_alloc(size, flags, NULL, NULL, NULL, NULL, 
NULL)
-- 
2.34.1

___
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".


[FFmpeg-devel] [PATCH 20/42] avcodec/nvdec: Use RefStruct-pool API for decoder pool

2023-09-19 Thread Andreas Rheinhardt
It involves less allocations, in particular no allocations
after the entry has been created. Therefore creating a new
reference from an existing one can't fail and therefore
need not be checked. It also avoids indirections and casts.

Also note that nvdec_decoder_frame_init() (the callback
to initialize new entries from the pool) does not use
atomics to read and replace the number of entries
currently used by the pool. This relies on nvdec (like
most other hwaccels) not being run in a truely frame-threaded
way.

Signed-off-by: Andreas Rheinhardt 
---
Notice that the AVBufferPool API serializes creating new entries
as well as getting an already existing entry from the pool,
so not using atomics here would be fine for it even if nvdec
were run in a truely multithreaded way.

 libavcodec/nvdec.c | 49 +++---
 libavcodec/nvdec.h |  6 +++---
 2 files changed, 27 insertions(+), 28 deletions(-)

diff --git a/libavcodec/nvdec.c b/libavcodec/nvdec.c
index 0ec8e896a6..27be644356 100644
--- a/libavcodec/nvdec.c
+++ b/libavcodec/nvdec.c
@@ -237,21 +237,22 @@ fail:
 return ret;
 }
 
-static AVBufferRef *nvdec_decoder_frame_alloc(void *opaque, size_t size)
+static int nvdec_decoder_frame_init(FFRefStructOpaque opaque, void *obj)
 {
-NVDECFramePool *pool = opaque;
-AVBufferRef *ret;
+NVDECFramePool *pool = opaque.nc;
+unsigned int *intp = obj;
 
 if (pool->nb_allocated >= pool->dpb_size)
-return NULL;
+return AVERROR(ENOMEM);
 
-ret = av_buffer_alloc(sizeof(unsigned int));
-if (!ret)
-return NULL;
+*intp = pool->nb_allocated++;
 
-*(unsigned int*)ret->data = pool->nb_allocated++;
+return 0;
+}
 
-return ret;
+static void nvdec_decoder_frame_pool_free(FFRefStructOpaque opaque)
+{
+av_free(opaque.nc);
 }
 
 int ff_nvdec_decode_uninit(AVCodecContext *avctx)
@@ -268,7 +269,7 @@ int ff_nvdec_decode_uninit(AVCodecContext *avctx)
 ctx->slice_offsets_allocated = 0;
 
 ff_refstruct_unref(>decoder);
-av_buffer_pool_uninit(>decoder_pool);
+ff_refstruct_pool_uninit(>decoder_pool);
 
 return 0;
 }
@@ -424,8 +425,9 @@ int ff_nvdec_decode_init(AVCodecContext *avctx)
 }
 pool->dpb_size = frames_ctx->initial_pool_size;
 
-ctx->decoder_pool = av_buffer_pool_init2(sizeof(int), pool,
- nvdec_decoder_frame_alloc, 
av_free);
+ctx->decoder_pool = ff_refstruct_pool_alloc_ext(sizeof(unsigned int), 0, 
pool,
+nvdec_decoder_frame_init,
+NULL, NULL, 
nvdec_decoder_frame_pool_free);
 if (!ctx->decoder_pool) {
 ret = AVERROR(ENOMEM);
 goto fail;
@@ -444,8 +446,8 @@ static void nvdec_fdd_priv_free(void *priv)
 if (!cf)
 return;
 
-av_buffer_unref(>idx_ref);
-av_buffer_unref(>ref_idx_ref);
+ff_refstruct_unref(>idx_ref);
+ff_refstruct_unref(>ref_idx_ref);
 ff_refstruct_unref(>decoder);
 
 av_freep();
@@ -469,8 +471,8 @@ static void nvdec_unmap_mapped_frame(void *opaque, uint8_t 
*data)
 CHECK_CU(decoder->cudl->cuCtxPopCurrent());
 
 finish:
-av_buffer_unref(_data->idx_ref);
-av_buffer_unref(_data->ref_idx_ref);
+ff_refstruct_unref(_data->idx_ref);
+ff_refstruct_unref(_data->ref_idx_ref);
 ff_refstruct_unref(_data->decoder);
 av_free(unmap_data);
 }
@@ -526,10 +528,7 @@ static int nvdec_retrieve_data(void *logctx, AVFrame 
*frame)
 goto copy_fail;
 
 unmap_data->idx = cf->idx;
-if (!(unmap_data->idx_ref = av_buffer_ref(cf->idx_ref))) {
-ret = AVERROR(ENOMEM);
-goto copy_fail;
-}
+unmap_data->idx_ref = ff_refstruct_ref(cf->idx_ref);
 unmap_data->decoder = ff_refstruct_ref(cf->decoder);
 
 av_pix_fmt_get_chroma_sub_sample(hwctx->sw_format, _h, _v);
@@ -577,13 +576,13 @@ int ff_nvdec_start_frame(AVCodecContext *avctx, AVFrame 
*frame)
 
 cf->decoder = ff_refstruct_ref(ctx->decoder);
 
-cf->idx_ref = av_buffer_pool_get(ctx->decoder_pool);
+cf->idx_ref = ff_refstruct_pool_get(ctx->decoder_pool);
 if (!cf->idx_ref) {
 av_log(avctx, AV_LOG_ERROR, "No decoder surfaces left\n");
 ret = AVERROR(ENOMEM);
 goto fail;
 }
-cf->ref_idx = cf->idx = *(unsigned int*)cf->idx_ref->data;
+cf->ref_idx = cf->idx = *cf->idx_ref;
 
 fdd->hwaccel_priv  = cf;
 fdd->hwaccel_priv_free = nvdec_fdd_priv_free;
@@ -611,16 +610,16 @@ int ff_nvdec_start_frame_sep_ref(AVCodecContext *avctx, 
AVFrame *frame, int has_
 
 if (has_sep_ref) {
 if (!cf->ref_idx_ref) {
-cf->ref_idx_ref = av_buffer_pool_get(ctx->decoder_pool);
+cf->ref_idx_ref = ff_refstruct_pool_get(ctx->decoder_pool);
 if (!cf->ref_idx_ref) {
 av_log(avctx, AV_LOG_ERROR, "No decoder surfaces left\n");
 ret = AVERROR(ENOMEM);
 goto fail;

[FFmpeg-devel] [PATCH 19/42] avcodec/hevcdec: Use RefStruct-pool API instead of AVBufferPool API

2023-09-19 Thread Andreas Rheinhardt
It involves less allocations and therefore has the nice property
that deriving a reference from a reference can't fail,
simplifying hevc_ref_frame().

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/hevc_refs.c | 16 ++--
 libavcodec/hevcdec.c   | 25 ++---
 libavcodec/hevcdec.h   | 10 --
 3 files changed, 16 insertions(+), 35 deletions(-)

diff --git a/libavcodec/hevc_refs.c b/libavcodec/hevc_refs.c
index ae464e8e6d..fa53b273c7 100644
--- a/libavcodec/hevc_refs.c
+++ b/libavcodec/hevc_refs.c
@@ -42,13 +42,11 @@ void ff_hevc_unref_frame(HEVCContext *s, HEVCFrame *frame, 
int flags)
 ff_thread_release_buffer(s->avctx, frame->frame_grain);
 frame->needs_fg = 0;
 
-av_buffer_unref(>tab_mvf_buf);
-frame->tab_mvf = NULL;
+ff_refstruct_unref(>tab_mvf);
 
 ff_refstruct_unref(>rpl);
 frame->nb_rpl_elems = 0;
-av_buffer_unref(>rpl_tab_buf);
-frame->rpl_tab= NULL;
+ff_refstruct_unref(>rpl_tab);
 frame->refPicList = NULL;
 
 frame->collocated_ref = NULL;
@@ -101,15 +99,13 @@ static HEVCFrame *alloc_frame(HEVCContext *s)
 goto fail;
 frame->nb_rpl_elems = s->pkt.nb_nals;
 
-frame->tab_mvf_buf = av_buffer_pool_get(s->tab_mvf_pool);
-if (!frame->tab_mvf_buf)
+frame->tab_mvf = ff_refstruct_pool_get(s->tab_mvf_pool);
+if (!frame->tab_mvf)
 goto fail;
-frame->tab_mvf = (MvField *)frame->tab_mvf_buf->data;
 
-frame->rpl_tab_buf = av_buffer_pool_get(s->rpl_tab_pool);
-if (!frame->rpl_tab_buf)
+frame->rpl_tab = ff_refstruct_pool_get(s->rpl_tab_pool);
+if (!frame->rpl_tab)
 goto fail;
-frame->rpl_tab   = (RefPicListTab **)frame->rpl_tab_buf->data;
 frame->ctb_count = s->ps.sps->ctb_width * s->ps.sps->ctb_height;
 for (j = 0; j < frame->ctb_count; j++)
 frame->rpl_tab[j] = frame->rpl;
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index 44561de821..23cc543f82 100644
--- a/libavcodec/hevcdec.c
+++ b/libavcodec/hevcdec.c
@@ -86,8 +86,8 @@ static void pic_arrays_free(HEVCContext *s)
 av_freep(>sh.size);
 av_freep(>sh.offset);
 
-av_buffer_pool_uninit(>tab_mvf_pool);
-av_buffer_pool_uninit(>rpl_tab_pool);
+ff_refstruct_pool_uninit(>tab_mvf_pool);
+ff_refstruct_pool_uninit(>rpl_tab_pool);
 }
 
 /* allocate arrays that depend on frame dimensions */
@@ -133,10 +133,8 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS 
*sps)
 if (!s->horizontal_bs || !s->vertical_bs)
 goto fail;
 
-s->tab_mvf_pool = av_buffer_pool_init(min_pu_size * sizeof(MvField),
-  av_buffer_allocz);
-s->rpl_tab_pool = av_buffer_pool_init(ctb_count * sizeof(RefPicListTab),
-  av_buffer_allocz);
+s->tab_mvf_pool = ff_refstruct_pool_alloc(min_pu_size * sizeof(MvField), 
0);
+s->rpl_tab_pool = ff_refstruct_pool_alloc(ctb_count * 
sizeof(RefPicListTab), 0);
 if (!s->tab_mvf_pool || !s->rpl_tab_pool)
 goto fail;
 
@@ -3394,16 +3392,8 @@ static int hevc_ref_frame(HEVCContext *s, HEVCFrame 
*dst, HEVCFrame *src)
 dst->needs_fg = 1;
 }
 
-dst->tab_mvf_buf = av_buffer_ref(src->tab_mvf_buf);
-if (!dst->tab_mvf_buf)
-goto fail;
-dst->tab_mvf = src->tab_mvf;
-
-dst->rpl_tab_buf = av_buffer_ref(src->rpl_tab_buf);
-if (!dst->rpl_tab_buf)
-goto fail;
-dst->rpl_tab = src->rpl_tab;
-
+dst->tab_mvf = ff_refstruct_ref(src->tab_mvf);
+dst->rpl_tab = ff_refstruct_ref(src->rpl_tab);
 dst->rpl = ff_refstruct_ref(src->rpl);
 dst->nb_rpl_elems = src->nb_rpl_elems;
 
@@ -3416,9 +3406,6 @@ static int hevc_ref_frame(HEVCContext *s, HEVCFrame *dst, 
HEVCFrame *src)
   src->hwaccel_picture_private);
 
 return 0;
-fail:
-ff_hevc_unref_frame(s, dst, ~0);
-return AVERROR(ENOMEM);
 }
 
 static av_cold int hevc_decode_free(AVCodecContext *avctx)
diff --git a/libavcodec/hevcdec.h b/libavcodec/hevcdec.h
index c13406f0a8..edf2f188cf 100644
--- a/libavcodec/hevcdec.h
+++ b/libavcodec/hevcdec.h
@@ -408,15 +408,13 @@ typedef struct HEVCFrame {
 AVFrame *frame_grain;
 ThreadFrame tf;
 int needs_fg; /* 1 if grain needs to be applied by the decoder */
-MvField *tab_mvf;
+MvField *tab_mvf;  ///< RefStruct reference
 RefPicList *refPicList;
-RefPicListTab **rpl_tab;
+RefPicListTab **rpl_tab;   ///< RefStruct reference
 int ctb_count;
 int poc;
 struct HEVCFrame *collocated_ref;
 
-AVBufferRef *tab_mvf_buf;
-AVBufferRef *rpl_tab_buf;
 RefPicListTab *rpl;///< RefStruct reference
 int nb_rpl_elems;
 
@@ -517,8 +515,8 @@ typedef struct HEVCContext {
 HEVCSEI sei;
 struct AVMD5 *md5_ctx;
 
-AVBufferPool *tab_mvf_pool;
-AVBufferPool *rpl_tab_pool;
+struct 

[FFmpeg-devel] [PATCH 18/42] avcodec/h264dec: Use RefStruct-pool API instead of AVBufferPool API

2023-09-19 Thread Andreas Rheinhardt
It involves less allocations and therefore has the nice property
that deriving a reference from a reference can't fail.
This allows for considerable simplifications in
ff_h264_(ref|replace)_picture().
Switching to the RefStruct API also allows to make H264Picture
smaller, because some AVBufferRef* pointers could be removed
without replacement.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/h264_picture.c | 72 +++
 libavcodec/h264_slice.c   | 44 
 libavcodec/h264dec.c  | 19 ++-
 libavcodec/h264dec.h  | 23 ++---
 4 files changed, 62 insertions(+), 96 deletions(-)

diff --git a/libavcodec/h264_picture.c b/libavcodec/h264_picture.c
index 9353e4b445..c1df9b8d05 100644
--- a/libavcodec/h264_picture.c
+++ b/libavcodec/h264_picture.c
@@ -48,29 +48,39 @@ void ff_h264_unref_picture(H264Context *h, H264Picture *pic)
 ff_thread_release_buffer(h->avctx, pic->f_grain);
 ff_refstruct_unref(>hwaccel_picture_private);
 
-av_buffer_unref(>qscale_table_buf);
-av_buffer_unref(>mb_type_buf);
+ff_refstruct_unref(>qscale_table_base);
+ff_refstruct_unref(>mb_type_base);
 ff_refstruct_unref(>pps);
 for (i = 0; i < 2; i++) {
-av_buffer_unref(>motion_val_buf[i]);
-av_buffer_unref(>ref_index_buf[i]);
+ff_refstruct_unref(>motion_val_base[i]);
+ff_refstruct_unref(>ref_index[i]);
 }
-av_buffer_unref(>decode_error_flags);
+ff_refstruct_unref(>decode_error_flags);
 
 memset((uint8_t*)pic + off, 0, sizeof(*pic) - off);
 }
 
 static void h264_copy_picture_params(H264Picture *dst, const H264Picture *src)
 {
+ff_refstruct_replace(>qscale_table_base, src->qscale_table_base);
+ff_refstruct_replace(>mb_type_base,  src->mb_type_base);
 ff_refstruct_replace(>pps, src->pps);
 
+for (int i = 0; i < 2; i++) {
+ff_refstruct_replace(>motion_val_base[i], 
src->motion_val_base[i]);
+ff_refstruct_replace(>ref_index[i],   src->ref_index[i]);
+}
+
+ff_refstruct_replace(>hwaccel_picture_private,
+  src->hwaccel_picture_private);
+
+ff_refstruct_replace(>decode_error_flags, src->decode_error_flags);
+
 dst->qscale_table = src->qscale_table;
 dst->mb_type  = src->mb_type;
 
-for (int i = 0; i < 2; i++) {
+for (int i = 0; i < 2; i++)
 dst->motion_val[i] = src->motion_val[i];
-dst->ref_index[i]  = src->ref_index[i];
-}
 
 for (int i = 0; i < 2; i++)
 dst->field_poc[i] = src->field_poc[i];
@@ -96,7 +106,7 @@ static void h264_copy_picture_params(H264Picture *dst, const 
H264Picture *src)
 
 int ff_h264_ref_picture(H264Context *h, H264Picture *dst, H264Picture *src)
 {
-int ret, i;
+int ret;
 
 av_assert0(!dst->f->buf[0]);
 av_assert0(src->f->buf[0]);
@@ -113,29 +123,6 @@ int ff_h264_ref_picture(H264Context *h, H264Picture *dst, 
H264Picture *src)
 goto fail;
 }
 
-dst->qscale_table_buf = av_buffer_ref(src->qscale_table_buf);
-dst->mb_type_buf  = av_buffer_ref(src->mb_type_buf);
-if (!dst->qscale_table_buf || !dst->mb_type_buf) {
-ret = AVERROR(ENOMEM);
-goto fail;
-}
-
-for (i = 0; i < 2; i++) {
-dst->motion_val_buf[i] = av_buffer_ref(src->motion_val_buf[i]);
-dst->ref_index_buf[i]  = av_buffer_ref(src->ref_index_buf[i]);
-if (!dst->motion_val_buf[i] || !dst->ref_index_buf[i]) {
-ret = AVERROR(ENOMEM);
-goto fail;
-}
-}
-
-ff_refstruct_replace(>hwaccel_picture_private,
-  src->hwaccel_picture_private);
-
-ret = av_buffer_replace(>decode_error_flags, src->decode_error_flags);
-if (ret < 0)
-goto fail;
-
 h264_copy_picture_params(dst, src);
 
 return 0;
@@ -146,7 +133,7 @@ fail:
 
 int ff_h264_replace_picture(H264Context *h, H264Picture *dst, const 
H264Picture *src)
 {
-int ret, i;
+int ret;
 
 if (!src->f || !src->f->buf[0]) {
 ff_h264_unref_picture(h, dst);
@@ -167,25 +154,6 @@ int ff_h264_replace_picture(H264Context *h, H264Picture 
*dst, const H264Picture
 goto fail;
 }
 
-ret  = av_buffer_replace(>qscale_table_buf, src->qscale_table_buf);
-ret |= av_buffer_replace(>mb_type_buf, src->mb_type_buf);
-if (ret < 0)
-goto fail;
-
-for (i = 0; i < 2; i++) {
-ret  = av_buffer_replace(>motion_val_buf[i], 
src->motion_val_buf[i]);
-ret |= av_buffer_replace(>ref_index_buf[i], 
src->ref_index_buf[i]);
-if (ret < 0)
-goto fail;
-}
-
-ff_refstruct_replace(>hwaccel_picture_private,
-  src->hwaccel_picture_private);
-
-ret = av_buffer_replace(>decode_error_flags, src->decode_error_flags);
-if (ret < 0)
-goto fail;
-
 h264_copy_picture_params(dst, src);
 
 return 0;
diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index 

[FFmpeg-devel] [PATCH 17/42] avcodec/refstruct: Add RefStruct pool API

2023-09-19 Thread Andreas Rheinhardt
Very similar to the AVBufferPool API, but with some differences:
1. Reusing an already existing entry does not incur an allocation
at all any more (the AVBufferPool API needs to allocate an AVBufferRef).
2. The tasks done while holding the lock are smaller; e.g.
allocating new entries is now performed without holding the lock.
The same goes for freeing.
3. The entries are freed as soon as possible (the AVBufferPool API
frees them in two batches: The first in av_buffer_pool_uninit() and
the second immediately before the pool is freed when the last
outstanding entry is returned to the pool).
4. The API is designed for objects and not naked buffers and
therefore has a reset callback. This is called whenever an object
is returned to the pool.
5. Just like with the RefStruct API, custom allocators are not
supported.

(If desired, the FFRefStructPool struct itself could be made
reference counted via the RefStruct API; an FFRefStructPool
would then be freed via ff_refstruct_unref().)

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/refstruct.c | 194 -
 libavcodec/refstruct.h | 128 +++
 2 files changed, 321 insertions(+), 1 deletion(-)

diff --git a/libavcodec/refstruct.c b/libavcodec/refstruct.c
index 604938922a..7539b7942e 100644
--- a/libavcodec/refstruct.c
+++ b/libavcodec/refstruct.c
@@ -23,8 +23,11 @@
 #include "internal.h"
 #include "refstruct.h"
 
+#include "libavutil/avassert.h"
+#include "libavutil/error.h"
 #include "libavutil/macros.h"
 #include "libavutil/mem.h"
+#include "libavutil/thread.h"
 
 typedef struct RefCount {
 /**
@@ -35,6 +38,7 @@ typedef struct RefCount {
 atomic_uintptr_t  refcount;
 FFRefStructOpaque opaque;
 void (*free_cb)(FFRefStructOpaque opaque, void *obj);
+void (*free)(void *ref);
 } RefCount;
 
 #if __STDC_VERSION__ >= 201112L
@@ -64,6 +68,7 @@ static void refcount_init(RefCount *ref, FFRefStructOpaque 
opaque,
 atomic_init(>refcount, 1);
 ref->opaque  = opaque;
 ref->free_cb = free_cb;
+ref->free= av_free;
 }
 
 void *ff_refstruct_alloc_ext_c(size_t size, unsigned flags, FFRefStructOpaque 
opaque,
@@ -103,7 +108,7 @@ void ff_refstruct_unref(void *objp)
 if (atomic_fetch_sub_explicit(>refcount, 1, memory_order_acq_rel) == 
1) {
 if (ref->free_cb)
 ref->free_cb(ref->opaque, obj);
-av_free(ref);
+ref->free(ref);
 }
 
 return;
@@ -151,3 +156,190 @@ int ff_refstruct_exclusive(const void *data)
  * accept const atomics in C11 (see also N1807). */
 return atomic_load_explicit((atomic_uintptr_t*)>refcount, 
memory_order_acquire) == 1;
 }
+
+struct FFRefStructPool {
+size_t size;
+FFRefStructOpaque opaque;
+int  (*init_cb)(FFRefStructOpaque opaque, void *obj);
+void (*reset_cb)(FFRefStructOpaque opaque, void *obj);
+void (*free_entry_cb)(FFRefStructOpaque opaque, void *obj);
+void (*free_cb)(FFRefStructOpaque opaque);
+
+int uninited;
+unsigned entry_flags;
+unsigned pool_flags;
+
+/** The number of outstanding entries not in available_entries. */
+atomic_uintptr_t refcount;
+/**
+ * This is a linked list of available entries;
+ * the RefCount's opaque pointer is used as next pointer
+ * for available entries.
+ * While the entries are in use, the opaque is a pointer
+ * to the corresponding FFRefStructPool.
+ */
+RefCount *available_entries;
+pthread_mutex_t mutex;
+};
+
+static void pool_free(FFRefStructPool *pool)
+{
+pthread_mutex_destroy(>mutex);
+if (pool->free_cb)
+pool->free_cb(pool->opaque);
+av_free(pool);
+}
+
+static void pool_free_entry(FFRefStructPool *pool, RefCount *ref)
+{
+if (pool->free_entry_cb)
+pool->free_entry_cb(pool->opaque, get_userdata(ref));
+av_free(ref);
+}
+
+static void pool_return_entry(void *ref_)
+{
+RefCount *ref = ref_;
+FFRefStructPool *pool = ref->opaque.nc;
+
+pthread_mutex_lock(>mutex);
+if (!pool->uninited) {
+ref->opaque.nc = pool->available_entries;
+pool->available_entries = ref;
+ref = NULL;
+}
+pthread_mutex_unlock(>mutex);
+
+if (ref)
+pool_free_entry(pool, ref);
+
+if (atomic_fetch_sub_explicit(>refcount, 1, memory_order_acq_rel) == 
1)
+pool_free(pool);
+}
+
+static void pool_reset_entry(FFRefStructOpaque opaque, void *entry)
+{
+FFRefStructPool *pool = opaque.nc;
+
+pool->reset_cb(pool->opaque, entry);
+}
+
+static int refstruct_pool_get_ext(void *datap, FFRefStructPool *pool)
+{
+void *ret = NULL;
+
+memcpy(datap, &(void *){ NULL }, sizeof(void*));
+
+pthread_mutex_lock(>mutex);
+av_assert1(!pool->uninited);
+if (pool->available_entries) {
+RefCount *ref = pool->available_entries;
+ret = get_userdata(ref);
+pool->available_entries = ref->opaque.nc;
+ref->opaque.nc = pool;
+atomic_init(>refcount, 1);
+}
+

[FFmpeg-devel] [PATCH 16/42] avcodec/nvdec: Use RefStruct API for decoder_ref

2023-09-19 Thread Andreas Rheinhardt
Avoids allocations and error checks as well as the boilerplate
code for creating an AVBuffer with a custom free callback.
Also increases type safety.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/nvdec.c | 50 ++
 libavcodec/nvdec.h |  4 ++--
 2 files changed, 21 insertions(+), 33 deletions(-)

diff --git a/libavcodec/nvdec.c b/libavcodec/nvdec.c
index a477449d14..0ec8e896a6 100644
--- a/libavcodec/nvdec.c
+++ b/libavcodec/nvdec.c
@@ -35,6 +35,7 @@
 #include "decode.h"
 #include "nvdec.h"
 #include "internal.h"
+#include "refstruct.h"
 
 #if !NVDECAPI_CHECK_VERSION(9, 0)
 #define cudaVideoSurfaceFormat_YUV444 2
@@ -161,9 +162,9 @@ static int nvdec_test_capabilities(NVDECDecoder *decoder,
 return 0;
 }
 
-static void nvdec_decoder_free(void *opaque, uint8_t *data)
+static void nvdec_decoder_free(FFRefStructOpaque unused, void *obj)
 {
-NVDECDecoder *decoder = (NVDECDecoder*)data;
+NVDECDecoder *decoder = obj;
 
 if (decoder->decoder) {
 void *logctx = decoder->hw_device_ref->data;
@@ -177,33 +178,24 @@ static void nvdec_decoder_free(void *opaque, uint8_t 
*data)
 av_buffer_unref(>hw_device_ref);
 
 cuvid_free_functions(>cvdl);
-
-av_freep();
 }
 
-static int nvdec_decoder_create(AVBufferRef **out, AVBufferRef *hw_device_ref,
+static int nvdec_decoder_create(NVDECDecoder **out, AVBufferRef *hw_device_ref,
 CUVIDDECODECREATEINFO *params, void *logctx)
 {
 AVHWDeviceContext  *hw_device_ctx = 
(AVHWDeviceContext*)hw_device_ref->data;
 AVCUDADeviceContext *device_hwctx = hw_device_ctx->hwctx;
 
-AVBufferRef *decoder_ref;
 NVDECDecoder *decoder;
 
 CUcontext dummy;
 int ret;
 
-decoder = av_mallocz(sizeof(*decoder));
+decoder = ff_refstruct_alloc_ext(sizeof(*decoder), 0,
+ NULL, nvdec_decoder_free);
 if (!decoder)
 return AVERROR(ENOMEM);
 
-decoder_ref = av_buffer_create((uint8_t*)decoder, sizeof(*decoder),
-   nvdec_decoder_free, NULL, 
AV_BUFFER_FLAG_READONLY);
-if (!decoder_ref) {
-av_freep();
-return AVERROR(ENOMEM);
-}
-
 decoder->hw_device_ref = av_buffer_ref(hw_device_ref);
 if (!decoder->hw_device_ref) {
 ret = AVERROR(ENOMEM);
@@ -237,11 +229,11 @@ static int nvdec_decoder_create(AVBufferRef **out, 
AVBufferRef *hw_device_ref,
 goto fail;
 }
 
-*out = decoder_ref;
+*out = decoder;
 
 return 0;
 fail:
-av_buffer_unref(_ref);
+ff_refstruct_unref();
 return ret;
 }
 
@@ -275,7 +267,7 @@ int ff_nvdec_decode_uninit(AVCodecContext *avctx)
 ctx->nb_slices   = 0;
 ctx->slice_offsets_allocated = 0;
 
-av_buffer_unref(>decoder_ref);
+ff_refstruct_unref(>decoder);
 av_buffer_pool_uninit(>decoder_pool);
 
 return 0;
@@ -408,7 +400,7 @@ int ff_nvdec_decode_init(AVCodecContext *avctx)
 params.ulNumDecodeSurfaces = frames_ctx->initial_pool_size;
 params.ulNumOutputSurfaces = unsafe_output ? frames_ctx->initial_pool_size 
: 1;
 
-ret = nvdec_decoder_create(>decoder_ref, frames_ctx->device_ref, 
, avctx);
+ret = nvdec_decoder_create(>decoder, frames_ctx->device_ref, , 
avctx);
 if (ret < 0) {
 if (params.ulNumDecodeSurfaces > 32) {
 av_log(avctx, AV_LOG_WARNING, "Using more than 32 (%d) decode 
surfaces might cause nvdec to fail.\n",
@@ -420,7 +412,7 @@ int ff_nvdec_decode_init(AVCodecContext *avctx)
 return ret;
 }
 
-decoder = (NVDECDecoder*)ctx->decoder_ref->data;
+decoder = ctx->decoder;
 decoder->unsafe_output = unsafe_output;
 decoder->real_hw_frames_ref = real_hw_frames_ref;
 real_hw_frames_ref = NULL;
@@ -453,8 +445,8 @@ static void nvdec_fdd_priv_free(void *priv)
 return;
 
 av_buffer_unref(>idx_ref);
-av_buffer_unref(>decoder_ref);
 av_buffer_unref(>ref_idx_ref);
+ff_refstruct_unref(>decoder);
 
 av_freep();
 }
@@ -462,7 +454,7 @@ static void nvdec_fdd_priv_free(void *priv)
 static void nvdec_unmap_mapped_frame(void *opaque, uint8_t *data)
 {
 NVDECFrame *unmap_data = (NVDECFrame*)data;
-NVDECDecoder *decoder = (NVDECDecoder*)unmap_data->decoder_ref->data;
+NVDECDecoder *decoder = unmap_data->decoder;
 void *logctx = decoder->hw_device_ref->data;
 CUdeviceptr devptr = (CUdeviceptr)opaque;
 int ret;
@@ -478,8 +470,8 @@ static void nvdec_unmap_mapped_frame(void *opaque, uint8_t 
*data)
 
 finish:
 av_buffer_unref(_data->idx_ref);
-av_buffer_unref(_data->decoder_ref);
 av_buffer_unref(_data->ref_idx_ref);
+ff_refstruct_unref(_data->decoder);
 av_free(unmap_data);
 }
 
@@ -487,7 +479,7 @@ static int nvdec_retrieve_data(void *logctx, AVFrame *frame)
 {
 FrameDecodeData  *fdd = (FrameDecodeData*)frame->private_ref->data;
 NVDECFrame*cf = (NVDECFrame*)fdd->hwaccel_priv;
-NVDECDecoder *decoder = 

[FFmpeg-devel] [PATCH 15/42] avcodec/pthread_frame: Use RefStruct API for ThreadFrame.progress

2023-09-19 Thread Andreas Rheinhardt
Avoids allocations and error checks and allows to remove
cleanup code for earlier allocations. Also avoids casts
and indirections.

Signed-off-by: Andreas Rheinhardt 
---
I actually intend to remove the ThreadFrame API in the not-so
long-term.

 libavcodec/h264_mb.c   |  4 ++--
 libavcodec/pthread_frame.c | 23 ---
 libavcodec/threadframe.h   |  4 +---
 libavcodec/utils.c | 14 --
 4 files changed, 19 insertions(+), 26 deletions(-)

diff --git a/libavcodec/h264_mb.c b/libavcodec/h264_mb.c
index 32d29cfb4d..4e94136313 100644
--- a/libavcodec/h264_mb.c
+++ b/libavcodec/h264_mb.c
@@ -66,7 +66,7 @@ static inline void get_lowest_part_y(const H264Context *h, 
H264SliceContext *sl,
 // Error resilience puts the current picture in the ref list.
 // Don't try to wait on these as it will cause a deadlock.
 // Fields can wait on each other, though.
-if (ref->parent->tf.progress->data != h->cur_pic.tf.progress->data ||
+if (ref->parent->tf.progress != h->cur_pic.tf.progress ||
 (ref->reference & 3) != h->picture_structure) {
 my = get_lowest_part_list_y(sl, n, height, y_offset, 0);
 if (refs[0][ref_n] < 0)
@@ -79,7 +79,7 @@ static inline void get_lowest_part_y(const H264Context *h, 
H264SliceContext *sl,
 int ref_n= sl->ref_cache[1][scan8[n]];
 H264Ref *ref = >ref_list[1][ref_n];
 
-if (ref->parent->tf.progress->data != h->cur_pic.tf.progress->data ||
+if (ref->parent->tf.progress != h->cur_pic.tf.progress ||
 (ref->reference & 3) != h->picture_structure) {
 my = get_lowest_part_list_y(sl, n, height, y_offset, 1);
 if (refs[1][ref_n] < 0)
diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index 7e274b0559..282f3fad58 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -66,6 +66,10 @@ enum {
 INITIALIZED,///< Thread has been properly set up
 };
 
+typedef struct ThreadFrameProgress {
+atomic_int progress[2];
+} ThreadFrameProgress;
+
 /**
  * Context used by codec threads and stored in their AVCodecInternal 
thread_ctx.
  */
@@ -585,7 +589,7 @@ finish:
 void ff_thread_report_progress(ThreadFrame *f, int n, int field)
 {
 PerThreadContext *p;
-atomic_int *progress = f->progress ? (atomic_int*)f->progress->data : NULL;
+atomic_int *progress = f->progress ? f->progress->progress : NULL;
 
 if (!progress ||
 atomic_load_explicit([field], memory_order_relaxed) >= n)
@@ -608,7 +612,7 @@ void ff_thread_report_progress(ThreadFrame *f, int n, int 
field)
 void ff_thread_await_progress(const ThreadFrame *f, int n, int field)
 {
 PerThreadContext *p;
-atomic_int *progress = f->progress ? (atomic_int*)f->progress->data : NULL;
+atomic_int *progress = f->progress ? f->progress->progress : NULL;
 
 if (!progress ||
 atomic_load_explicit([field], memory_order_acquire) >= n)
@@ -991,20 +995,17 @@ int ff_thread_get_ext_buffer(AVCodecContext *avctx, 
ThreadFrame *f, int flags)
 return ff_get_buffer(avctx, f->f, flags);
 
 if (ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_ALLOCATE_PROGRESS) 
{
-atomic_int *progress;
-f->progress = av_buffer_alloc(2 * sizeof(*progress));
-if (!f->progress) {
+f->progress = ff_refstruct_allocz(sizeof(*f->progress));
+if (!f->progress)
 return AVERROR(ENOMEM);
-}
-progress = (atomic_int*)f->progress->data;
 
-atomic_init([0], -1);
-atomic_init([1], -1);
+atomic_init(>progress->progress[0], -1);
+atomic_init(>progress->progress[1], -1);
 }
 
 ret = ff_thread_get_buffer(avctx, f->f, flags);
 if (ret)
-av_buffer_unref(>progress);
+ff_refstruct_unref(>progress);
 return ret;
 }
 
@@ -1021,7 +1022,7 @@ void ff_thread_release_buffer(AVCodecContext *avctx, 
AVFrame *f)
 
 void ff_thread_release_ext_buffer(AVCodecContext *avctx, ThreadFrame *f)
 {
-av_buffer_unref(>progress);
+ff_refstruct_unref(>progress);
 f->owner[0] = f->owner[1] = NULL;
 ff_thread_release_buffer(avctx, f->f);
 }
diff --git a/libavcodec/threadframe.h b/libavcodec/threadframe.h
index a8403c8976..7b52e6f6d5 100644
--- a/libavcodec/threadframe.h
+++ b/libavcodec/threadframe.h
@@ -27,9 +27,7 @@
 typedef struct ThreadFrame {
 AVFrame *f;
 AVCodecContext *owner[2];
-// progress->data is an array of 2 ints holding progress for top/bottom
-// fields
-AVBufferRef *progress;
+struct ThreadFrameProgress *progress;
 } ThreadFrame;
 
 /**
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 3cb3828228..90efa28ee6 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -38,6 +38,7 @@
 #include "codec_internal.h"
 #include "decode.h"
 #include "hwconfig.h"
+#include "refstruct.h"
 #include "thread.h"
 #include "threadframe.h"
 #include "internal.h"
@@ -878,11 +879,8 @@ int 

[FFmpeg-devel] [PATCH 14/42] avcodec/hevcdec: Use RefStruct API for RefPicListTap buffer

2023-09-19 Thread Andreas Rheinhardt
Given that the RefStruct API relies on the user to know
the size of the objects and does not provide a way to get it,
we need to store the number of elements allocated ourselves;
but this is actually better than deriving it from the size
in bytes.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/hevc_refs.c | 14 --
 libavcodec/hevcdec.c   |  5 ++---
 libavcodec/hevcdec.h   |  3 ++-
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/libavcodec/hevc_refs.c b/libavcodec/hevc_refs.c
index 8f49704b54..ae464e8e6d 100644
--- a/libavcodec/hevc_refs.c
+++ b/libavcodec/hevc_refs.c
@@ -45,7 +45,8 @@ void ff_hevc_unref_frame(HEVCContext *s, HEVCFrame *frame, 
int flags)
 av_buffer_unref(>tab_mvf_buf);
 frame->tab_mvf = NULL;
 
-av_buffer_unref(>rpl_buf);
+ff_refstruct_unref(>rpl);
+frame->nb_rpl_elems = 0;
 av_buffer_unref(>rpl_tab_buf);
 frame->rpl_tab= NULL;
 frame->refPicList = NULL;
@@ -95,9 +96,10 @@ static HEVCFrame *alloc_frame(HEVCContext *s)
 if (ret < 0)
 return NULL;
 
-frame->rpl_buf = av_buffer_allocz(s->pkt.nb_nals * 
sizeof(RefPicListTab));
-if (!frame->rpl_buf)
+frame->rpl = ff_refstruct_allocz(s->pkt.nb_nals * sizeof(*frame->rpl));
+if (!frame->rpl)
 goto fail;
+frame->nb_rpl_elems = s->pkt.nb_nals;
 
 frame->tab_mvf_buf = av_buffer_pool_get(s->tab_mvf_pool);
 if (!frame->tab_mvf_buf)
@@ -110,7 +112,7 @@ static HEVCFrame *alloc_frame(HEVCContext *s)
 frame->rpl_tab   = (RefPicListTab **)frame->rpl_tab_buf->data;
 frame->ctb_count = s->ps.sps->ctb_width * s->ps.sps->ctb_height;
 for (j = 0; j < frame->ctb_count; j++)
-frame->rpl_tab[j] = (RefPicListTab *)frame->rpl_buf->data;
+frame->rpl_tab[j] = frame->rpl;
 
 if (s->sei.picture_timing.picture_struct == 
AV_PICTURE_STRUCTURE_TOP_FIELD)
 frame->frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
@@ -295,11 +297,11 @@ static int init_slice_rpl(HEVCContext *s)
 int ctb_addr_ts  = s->ps.pps->ctb_addr_rs_to_ts[s->sh.slice_segment_addr];
 int i;
 
-if (s->slice_idx >= frame->rpl_buf->size / sizeof(RefPicListTab))
+if (s->slice_idx >= frame->nb_rpl_elems)
 return AVERROR_INVALIDDATA;
 
 for (i = ctb_addr_ts; i < ctb_count; i++)
-frame->rpl_tab[i] = (RefPicListTab *)frame->rpl_buf->data + 
s->slice_idx;
+frame->rpl_tab[i] = frame->rpl + s->slice_idx;
 
 frame->refPicList = (RefPicList *)frame->rpl_tab[ctb_addr_ts];
 
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index 8316a815e7..44561de821 100644
--- a/libavcodec/hevcdec.c
+++ b/libavcodec/hevcdec.c
@@ -3404,9 +3404,8 @@ static int hevc_ref_frame(HEVCContext *s, HEVCFrame *dst, 
HEVCFrame *src)
 goto fail;
 dst->rpl_tab = src->rpl_tab;
 
-dst->rpl_buf = av_buffer_ref(src->rpl_buf);
-if (!dst->rpl_buf)
-goto fail;
+dst->rpl = ff_refstruct_ref(src->rpl);
+dst->nb_rpl_elems = src->nb_rpl_elems;
 
 dst->poc= src->poc;
 dst->ctb_count  = src->ctb_count;
diff --git a/libavcodec/hevcdec.h b/libavcodec/hevcdec.h
index 1d29fc24d7..c13406f0a8 100644
--- a/libavcodec/hevcdec.h
+++ b/libavcodec/hevcdec.h
@@ -417,7 +417,8 @@ typedef struct HEVCFrame {
 
 AVBufferRef *tab_mvf_buf;
 AVBufferRef *rpl_tab_buf;
-AVBufferRef *rpl_buf;
+RefPicListTab *rpl;///< RefStruct reference
+int nb_rpl_elems;
 
 void *hwaccel_picture_private; ///< RefStruct reference
 
-- 
2.34.1

___
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".


[FFmpeg-devel] [PATCH 13/42] avcodec/vulkan_decode: Use RefStruct API for shared_ref

2023-09-19 Thread Andreas Rheinhardt
Avoids allocations, error checks and indirections.
Also increases type-safety.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/vulkan_av1.c|  2 +-
 libavcodec/vulkan_decode.c | 49 --
 libavcodec/vulkan_decode.h |  2 +-
 libavcodec/vulkan_h264.c   |  2 +-
 libavcodec/vulkan_hevc.c   |  2 +-
 5 files changed, 24 insertions(+), 33 deletions(-)

diff --git a/libavcodec/vulkan_av1.c b/libavcodec/vulkan_av1.c
index 7c8dda7798..4998bf7ebc 100644
--- a/libavcodec/vulkan_av1.c
+++ b/libavcodec/vulkan_av1.c
@@ -106,7 +106,7 @@ static int vk_av1_create_params(AVCodecContext *avctx, 
AVBufferRef **buf)
 {
 const AV1DecContext *s = avctx->priv_data;
 FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
-FFVulkanDecodeShared *ctx = (FFVulkanDecodeShared *)dec->shared_ref->data;
+FFVulkanDecodeShared *ctx = dec->shared_ctx;
 
 const AV1RawSequenceHeader *seq = s->raw_seq;
 
diff --git a/libavcodec/vulkan_decode.c b/libavcodec/vulkan_decode.c
index ef4a1c3809..e6a0646139 100644
--- a/libavcodec/vulkan_decode.c
+++ b/libavcodec/vulkan_decode.c
@@ -16,6 +16,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "refstruct.h"
 #include "vulkan_video.h"
 #include "vulkan_decode.h"
 #include "config_components.h"
@@ -71,7 +72,7 @@ int ff_vk_update_thread_context(AVCodecContext *dst, const 
AVCodecContext *src)
 FFVulkanDecodeContext *dst_ctx = dst->internal->hwaccel_priv_data;
 
 if (!dst_ctx->exec_pool.cmd_bufs) {
-FFVulkanDecodeShared *ctx = (FFVulkanDecodeShared 
*)src_ctx->shared_ref->data;
+FFVulkanDecodeShared *ctx = src_ctx->shared_ctx;
 
 const VkVideoProfileInfoKHR *profile = get_video_profile(ctx, 
dst->codec_id);
 if (!profile) {
@@ -89,9 +90,7 @@ int ff_vk_update_thread_context(AVCodecContext *dst, const 
AVCodecContext *src)
 return err;
 }
 
-err = av_buffer_replace(_ctx->shared_ref, src_ctx->shared_ref);
-if (err < 0)
-return err;
+ff_refstruct_replace(_ctx->shared_ctx, src_ctx->shared_ctx);
 
 if (src_ctx->session_params) {
 err = av_buffer_replace(_ctx->session_params, 
src_ctx->session_params);
@@ -175,7 +174,7 @@ int ff_vk_decode_prepare_frame(FFVulkanDecodeContext *dec, 
AVFrame *pic,
int alloc_dpb)
 {
 int err;
-FFVulkanDecodeShared *ctx = (FFVulkanDecodeShared *)dec->shared_ref->data;
+FFVulkanDecodeShared *ctx = dec->shared_ctx;
 FFVulkanFunctions *vk = >s.vkfn;
 
 vkpic->slices_size = 0;
@@ -239,7 +238,7 @@ int ff_vk_decode_add_slice(AVCodecContext *avctx, 
FFVulkanDecodePicture *vp,
uint32_t *nb_slices, const uint32_t **offsets)
 {
 FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
-FFVulkanDecodeShared *ctx = (FFVulkanDecodeShared *)dec->shared_ref->data;
+FFVulkanDecodeShared *ctx = dec->shared_ctx;
 
 static const uint8_t startcode_prefix[3] = { 0x0, 0x0, 0x1 };
 const size_t startcode_len = add_startcode ? sizeof(startcode_prefix) : 0;
@@ -299,7 +298,7 @@ int ff_vk_decode_add_slice(AVCodecContext *avctx, 
FFVulkanDecodePicture *vp,
 void ff_vk_decode_flush(AVCodecContext *avctx)
 {
 FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
-FFVulkanDecodeShared *ctx = (FFVulkanDecodeShared *)dec->shared_ref->data;
+FFVulkanDecodeShared *ctx = dec->shared_ctx;
 
 FFVulkanFunctions *vk = >s.vkfn;
 VkVideoBeginCodingInfoKHR decode_start = {
@@ -336,7 +335,7 @@ int ff_vk_decode_frame(AVCodecContext *avctx,
 FFVkVideoBuffer *sd_buf;
 
 FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
-FFVulkanDecodeShared *ctx = (FFVulkanDecodeShared *)dec->shared_ref->data;
+FFVulkanDecodeShared *ctx = dec->shared_ctx;
 FFVulkanFunctions *vk = >s.vkfn;
 
 /* Output */
@@ -586,9 +585,9 @@ void ff_vk_decode_free_frame(AVHWDeviceContext *dev_ctx, 
FFVulkanDecodePicture *
 av_frame_free(>dpb_frame);
 }
 
-static void free_common(void *opaque, uint8_t *data)
+static void free_common(FFRefStructOpaque unused, void *obj)
 {
-FFVulkanDecodeShared *ctx = (FFVulkanDecodeShared *)data;
+FFVulkanDecodeShared *ctx = obj;
 FFVulkanContext *s = >s;
 FFVulkanFunctions *vk = >s.vkfn;
 
@@ -613,8 +612,6 @@ static void free_common(void *opaque, uint8_t *data)
   s->hwctx->alloc);
 
 ff_vk_uninit(s);
-
-av_free(ctx);
 }
 
 static int vulkan_decode_bootstrap(AVCodecContext *avctx, AVBufferRef 
*frames_ref)
@@ -626,21 +623,15 @@ static int vulkan_decode_bootstrap(AVCodecContext *avctx, 
AVBufferRef *frames_re
 AVVulkanDeviceContext *hwctx = device->hwctx;
 FFVulkanDecodeShared *ctx;
 
-if (dec->shared_ref)
+if (dec->shared_ctx)
 return 0;
 
-ctx = av_mallocz(sizeof(*ctx));
-if (!ctx)
+dec->shared_ctx = ff_refstruct_alloc_ext(sizeof(*ctx), 0, NULL,
+   

[FFmpeg-devel] [PATCH 12/42] avcodec/decode: Use RefStruct API for hwaccel_picture_private

2023-09-19 Thread Andreas Rheinhardt
Avoids allocations and therefore error checks: Syncing
hwaccel_picture_private across threads can't fail any more.
Also gets rid of an unnecessary pointer in structures and
in the parameter list of ff_hwaccel_frame_priv_alloc().

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/av1dec.c   | 15 ---
 libavcodec/av1dec.h   |  4 +---
 libavcodec/decode.c   | 28 ++--
 libavcodec/decode.h   | 10 +++---
 libavcodec/h264_picture.c | 19 +--
 libavcodec/h264_slice.c   |  3 +--
 libavcodec/h264dec.h  |  1 -
 libavcodec/hevc_refs.c|  7 +++
 libavcodec/hevcdec.c  | 11 ++-
 libavcodec/hevcdec.h  |  3 +--
 libavcodec/hwaccel_internal.h |  3 ++-
 libavcodec/mpegpicture.c  | 18 +-
 libavcodec/mpegpicture.h  |  1 -
 libavcodec/vp8.c  | 14 --
 libavcodec/vp8.h  |  4 +---
 libavcodec/vp9.c  | 15 +--
 libavcodec/vp9shared.h|  3 +--
 libavcodec/vulkan_av1.c   |  9 +++--
 libavcodec/vulkan_h264.c  |  9 +++--
 libavcodec/vulkan_hevc.c  |  9 +++--
 20 files changed, 53 insertions(+), 133 deletions(-)

diff --git a/libavcodec/av1dec.c b/libavcodec/av1dec.c
index 87056520dd..c02408548c 100644
--- a/libavcodec/av1dec.c
+++ b/libavcodec/av1dec.c
@@ -27,7 +27,6 @@
 #include "libavutil/opt.h"
 #include "avcodec.h"
 #include "av1_parse.h"
-#include "decode.h"
 #include "av1dec.h"
 #include "atsc_a53.h"
 #include "bytestream.h"
@@ -640,8 +639,7 @@ static int get_pixel_format(AVCodecContext *avctx)
 static void av1_frame_unref(AVCodecContext *avctx, AV1Frame *f)
 {
 ff_thread_release_buffer(avctx, f->f);
-av_buffer_unref(>hwaccel_priv_buf);
-f->hwaccel_picture_private = NULL;
+ff_refstruct_unref(>hwaccel_picture_private);
 ff_refstruct_unref(>header_ref);
 f->raw_frame_header = NULL;
 f->spatial_id = f->temporal_id = 0;
@@ -666,12 +664,8 @@ static int av1_frame_ref(AVCodecContext *avctx, AV1Frame 
*dst, const AV1Frame *s
 if (ret < 0)
 goto fail;
 
-if (src->hwaccel_picture_private) {
-dst->hwaccel_priv_buf = av_buffer_ref(src->hwaccel_priv_buf);
-if (!dst->hwaccel_priv_buf)
-goto fail;
-dst->hwaccel_picture_private = dst->hwaccel_priv_buf->data;
-}
+ff_refstruct_replace(>hwaccel_picture_private,
+  src->hwaccel_picture_private);
 
 dst->spatial_id = src->spatial_id;
 dst->temporal_id = src->temporal_id;
@@ -915,8 +909,7 @@ static int av1_frame_alloc(AVCodecContext *avctx, AV1Frame 
*f)
 break;
 }
 
-ret = ff_hwaccel_frame_priv_alloc(avctx, >hwaccel_picture_private,
-  >hwaccel_priv_buf);
+ret = ff_hwaccel_frame_priv_alloc(avctx, >hwaccel_picture_private);
 if (ret < 0)
 goto fail;
 
diff --git a/libavcodec/av1dec.h b/libavcodec/av1dec.h
index acbeec4af3..b6a0c08e48 100644
--- a/libavcodec/av1dec.h
+++ b/libavcodec/av1dec.h
@@ -24,7 +24,6 @@
 #include 
 
 #include "libavutil/fifo.h"
-#include "libavutil/buffer.h"
 #include "libavutil/frame.h"
 #include "libavutil/pixfmt.h"
 #include "avcodec.h"
@@ -35,8 +34,7 @@
 typedef struct AV1Frame {
 AVFrame *f;
 
-AVBufferRef *hwaccel_priv_buf;
-void *hwaccel_picture_private;
+void *hwaccel_picture_private; ///< RefStruct reference
 
 AV1RawOBU *header_ref; ///< RefStruct reference backing raw_frame_header.
 AV1RawFrameHeader *raw_frame_header;
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 169ee79acd..7abfe7f0ce 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -28,18 +28,13 @@
 #endif
 
 #include "libavutil/avassert.h"
-#include "libavutil/avstring.h"
-#include "libavutil/bprint.h"
 #include "libavutil/channel_layout.h"
 #include "libavutil/common.h"
 #include "libavutil/emms.h"
-#include "libavutil/fifo.h"
 #include "libavutil/frame.h"
 #include "libavutil/hwcontext.h"
 #include "libavutil/imgutils.h"
 #include "libavutil/internal.h"
-#include "libavutil/intmath.h"
-#include "libavutil/opt.h"
 
 #include "avcodec.h"
 #include "avcodec_internal.h"
@@ -51,6 +46,7 @@
 #include "hwconfig.h"
 #include "internal.h"
 #include "packet_internal.h"
+#include "refstruct.h"
 #include "thread.h"
 
 typedef struct DecodeContext {
@@ -1790,34 +1786,22 @@ int ff_copy_palette(void *dst, const AVPacket *src, 
void *logctx)
 return 0;
 }
 
-int ff_hwaccel_frame_priv_alloc(AVCodecContext *avctx, void 
**hwaccel_picture_private,
-AVBufferRef **hwaccel_priv_buf)
+int ff_hwaccel_frame_priv_alloc(AVCodecContext *avctx, void 
**hwaccel_picture_private)
 {
 const FFHWAccel *hwaccel = ffhwaccel(avctx->hwaccel);
-AVBufferRef *ref;
 AVHWFramesContext *frames_ctx;
-uint8_t *data;
 
 if (!hwaccel || !hwaccel->frame_priv_data_size)
 return 0;
 
 

[FFmpeg-devel] [PATCH 11/42] avcodec/cbs_sei: Use RefStruct API for SEI messages

2023-09-19 Thread Andreas Rheinhardt
The SEI message code uses the AVBuffer API for its SEI messages
and contained buffers (like the extension buffer for HEVC
or the user data (un)registered payload buffers).

Contrary to the ordinary CBS code (where some of these
contained buffer references are actually references
to the provided AVPacket's data so that one can't replace
them with the RefStruct API), the CBS SEI code never uses
outside buffers at all and can therefore be switched entirely
to the RefStruct API. This avoids the overhead inherent
in the AVBuffer API (namely the separate allocations etc.).

Notice that the refcounting here is actually currently unused;
the refcounts are always one (or zero in case of no refcounting);
its only advantage is the flexibility provided by custom
free functions.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/cbs_h2645.c   | 19 +++--
 libavcodec/cbs_sei.c | 61 
 libavcodec/cbs_sei.h | 20 -
 libavcodec/cbs_sei_syntax_template.c |  5 +++
 4 files changed, 54 insertions(+), 51 deletions(-)

diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c
index e071442c31..c1f67fefb9 100644
--- a/libavcodec/cbs_h2645.c
+++ b/libavcodec/cbs_h2645.c
@@ -357,18 +357,31 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext 
*gbc)
 #define bit_position(rw)   (get_bits_count(rw))
 #define byte_alignment(rw) (get_bits_count(rw) % 8)
 
+/* The CBS SEI code uses the refstruct API for the allocation
+ * of its child buffers. */
 #define allocate(name, size) do { \
-name ## _ref = av_buffer_allocz(size + \
+name  = ff_refstruct_allocz(size + \
 AV_INPUT_BUFFER_PADDING_SIZE); \
-if (!name ## _ref) \
+if (!name) \
 return AVERROR(ENOMEM); \
-name = name ## _ref->data; \
 } while (0)
 
 #define FUNC(name) FUNC_SEI(name)
 #include "cbs_sei_syntax_template.c"
 #undef FUNC
 
+#undef allocate
+
+/* The other code uses the refstruct API for the allocation
+ * of its child buffers. */
+#define allocate(name, size) do { \
+name ## _ref = av_buffer_allocz(size + \
+AV_INPUT_BUFFER_PADDING_SIZE); \
+if (!name ## _ref) \
+return AVERROR(ENOMEM); \
+name = name ## _ref->data; \
+} while (0)
+
 #define FUNC(name) FUNC_H264(name)
 #include "cbs_h264_syntax_template.c"
 #undef FUNC
diff --git a/libavcodec/cbs_sei.c b/libavcodec/cbs_sei.c
index bd7f6f4938..e28c2f9093 100644
--- a/libavcodec/cbs_sei.c
+++ b/libavcodec/cbs_sei.c
@@ -22,25 +22,25 @@
 #include "cbs_h265.h"
 #include "cbs_h266.h"
 #include "cbs_sei.h"
+#include "refstruct.h"
 
-static void cbs_free_user_data_registered(void *opaque, uint8_t *data)
+static void cbs_free_user_data_registered(FFRefStructOpaque unused, void *obj)
 {
-SEIRawUserDataRegistered *udr = (SEIRawUserDataRegistered*)data;
-av_buffer_unref(>data_ref);
-av_free(udr);
+SEIRawUserDataRegistered *udr = obj;
+ff_refstruct_unref(>data);
 }
 
-static void cbs_free_user_data_unregistered(void *opaque, uint8_t *data)
+static void cbs_free_user_data_unregistered(FFRefStructOpaque unused, void 
*obj)
 {
-SEIRawUserDataUnregistered *udu = (SEIRawUserDataUnregistered*)data;
-av_buffer_unref(>data_ref);
-av_free(udu);
+SEIRawUserDataUnregistered *udu = obj;
+ff_refstruct_unref(>data);
 }
 
 int ff_cbs_sei_alloc_message_payload(SEIRawMessage *message,
  const SEIMessageTypeDescriptor *desc)
 {
-void (*free_func)(void*, uint8_t*);
+void (*free_func)(FFRefStructOpaque, void*);
+unsigned flags = 0;
 
 av_assert0(message->payload == NULL &&
message->payload_ref == NULL);
@@ -50,24 +50,16 @@ int ff_cbs_sei_alloc_message_payload(SEIRawMessage *message,
 free_func = _free_user_data_registered;
 else if (desc->type == SEI_TYPE_USER_DATA_UNREGISTERED)
 free_func = _free_user_data_unregistered;
-else
+else {
 free_func = NULL;
-
-if (free_func) {
-message->payload = av_mallocz(desc->size);
-if (!message->payload)
-return AVERROR(ENOMEM);
-message->payload_ref =
-av_buffer_create(message->payload, desc->size,
- free_func, NULL, 0);
-} else {
-message->payload_ref = av_buffer_alloc(desc->size);
+flags = FF_REFSTRUCT_FLAG_NO_ZEROING;
 }
-if (!message->payload_ref) {
-av_freep(>payload);
+
+message->payload_ref = ff_refstruct_alloc_ext(desc->size, flags,
+  NULL, free_func);
+if (!message->payload_ref)
 return AVERROR(ENOMEM);
-}
-message->payload = message->payload_ref->data;
+message->payload = message->payload_ref;
 
 return 0;
 }
@@ -101,8 +93,8 @@ void ff_cbs_sei_free_message_list(SEIRawMessageList *list)
 {
 for (int i = 0; 

[FFmpeg-devel] [PATCH 10/42] avcodec/cbs: Use RefStruct-API for unit content

2023-09-19 Thread Andreas Rheinhardt
This avoids allocations and error checks etc. as well
as duplicate pointer lists in the CodedBitstreamFooContexts.
It also avoids casting const away for use as opaque,
as the RefStruct API supports const opaques.

The fact that some of the units are not refcounted
(i.e. they are sometimes part of an encoding context
like VAAPIEncodeH264Context) meant that CodedBitstreamUnit
still contains two pointers, one to the content
and another ownership pointer, replacing the AVBufferRef* pointer.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/av1dec.c   |  49 +++--
 libavcodec/av1dec.h   |  10 +--
 libavcodec/cbs.c  | 101 --
 libavcodec/cbs.h  |  12 +--
 libavcodec/cbs_av1.c  |  32 +++-
 libavcodec/cbs_av1.h  |   3 +-
 libavcodec/cbs_h264.h |   6 +-
 libavcodec/cbs_h2645.c|  94 
 libavcodec/cbs_h265.h |   9 +--
 libavcodec/cbs_h266.h |  11 +--
 libavcodec/cbs_h266_syntax_template.c |  10 +--
 libavcodec/cbs_internal.h |   7 +-
 12 files changed, 129 insertions(+), 215 deletions(-)

diff --git a/libavcodec/av1dec.c b/libavcodec/av1dec.c
index 39ccad5bf6..87056520dd 100644
--- a/libavcodec/av1dec.c
+++ b/libavcodec/av1dec.c
@@ -37,6 +37,7 @@
 #include "internal.h"
 #include "hwconfig.h"
 #include "profiles.h"
+#include "refstruct.h"
 #include "thread.h"
 
 /**< same with Div_Lut defined in spec 7.11.3.7 */
@@ -641,7 +642,7 @@ static void av1_frame_unref(AVCodecContext *avctx, AV1Frame 
*f)
 ff_thread_release_buffer(avctx, f->f);
 av_buffer_unref(>hwaccel_priv_buf);
 f->hwaccel_picture_private = NULL;
-av_buffer_unref(>header_ref);
+ff_refstruct_unref(>header_ref);
 f->raw_frame_header = NULL;
 f->spatial_id = f->temporal_id = 0;
 memset(f->skip_mode_frame_idx, 0,
@@ -654,9 +655,7 @@ static int av1_frame_ref(AVCodecContext *avctx, AV1Frame 
*dst, const AV1Frame *s
 {
 int ret;
 
-ret = av_buffer_replace(>header_ref, src->header_ref);
-if (ret < 0)
-return ret;
+ff_refstruct_replace(>header_ref, src->header_ref);
 
 dst->raw_frame_header = src->raw_frame_header;
 
@@ -712,10 +711,10 @@ static av_cold int av1_decode_free(AVCodecContext *avctx)
 av1_frame_unref(avctx, >cur_frame);
 av_frame_free(>cur_frame.f);
 
-av_buffer_unref(>seq_ref);
-av_buffer_unref(>header_ref);
-av_buffer_unref(>cll_ref);
-av_buffer_unref(>mdcv_ref);
+ff_refstruct_unref(>seq_ref);
+ff_refstruct_unref(>header_ref);
+ff_refstruct_unref(>cll_ref);
+ff_refstruct_unref(>mdcv_ref);
 av_freep(>tile_group_info);
 
 while (s->itut_t35_fifo && av_fifo_read(s->itut_t35_fifo, _t35, 1) >= 
0)
@@ -1160,9 +1159,7 @@ static int get_current_frame(AVCodecContext *avctx)
 
 av1_frame_unref(avctx, >cur_frame);
 
-s->cur_frame.header_ref = av_buffer_ref(s->header_ref);
-if (!s->cur_frame.header_ref)
-return AVERROR(ENOMEM);
+s->cur_frame.header_ref = ff_refstruct_ref(s->header_ref);
 
 s->cur_frame.raw_frame_header = s->raw_frame_header;
 
@@ -1214,12 +1211,7 @@ static int av1_receive_frame_internal(AVCodecContext 
*avctx, AVFrame *frame)
 
 switch (unit->type) {
 case AV1_OBU_SEQUENCE_HEADER:
-av_buffer_unref(>seq_ref);
-s->seq_ref = av_buffer_ref(unit->content_ref);
-if (!s->seq_ref) {
-ret = AVERROR(ENOMEM);
-goto end;
-}
+ff_refstruct_replace(>seq_ref, unit->content_ref);
 
 s->raw_seq = >obu.sequence_header;
 
@@ -1264,12 +1256,7 @@ static int av1_receive_frame_internal(AVCodecContext 
*avctx, AVFrame *frame)
 goto end;
 }
 
-av_buffer_unref(>header_ref);
-s->header_ref = av_buffer_ref(unit->content_ref);
-if (!s->header_ref) {
-ret = AVERROR(ENOMEM);
-goto end;
-}
+ff_refstruct_replace(>header_ref, unit->content_ref);
 
 if (unit->type == AV1_OBU_FRAME)
 s->raw_frame_header = >obu.frame.header;
@@ -1356,23 +1343,11 @@ static int av1_receive_frame_internal(AVCodecContext 
*avctx, AVFrame *frame)
 case AV1_OBU_METADATA:
 switch (obu->obu.metadata.metadata_type) {
 case AV1_METADATA_TYPE_HDR_CLL:
-av_buffer_unref(>cll_ref);
-s->cll_ref = av_buffer_ref(unit->content_ref);
-if (!s->cll_ref) {
-s->cll = NULL;
-ret = AVERROR(ENOMEM);
-goto end;
-}
+ff_refstruct_replace(>cll_ref, unit->content_ref);
 s->cll = >obu.metadata.metadata.hdr_cll;
 break;
 case AV1_METADATA_TYPE_HDR_MDCV:
-

[FFmpeg-devel] [PATCH 09/42] avcodec/refstruct: Allow checking for exclusive ownership

2023-09-19 Thread Andreas Rheinhardt
This is the analog of av_buffer_is_writable();
it will be used in the next commit.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/refstruct.c | 14 ++
 libavcodec/refstruct.h |  9 +
 2 files changed, 23 insertions(+)

diff --git a/libavcodec/refstruct.c b/libavcodec/refstruct.c
index 917cf6b7ac..604938922a 100644
--- a/libavcodec/refstruct.c
+++ b/libavcodec/refstruct.c
@@ -48,6 +48,11 @@ static RefCount *get_refcount(void *obj)
 return (RefCount*)((char*)obj - REFCOUNT_OFFSET);
 }
 
+static const RefCount *cget_refcount(const void *data)
+{
+return (const RefCount*)((const char*)data - REFCOUNT_OFFSET);
+}
+
 static void *get_userdata(void *buf)
 {
 return (char*)buf + REFCOUNT_OFFSET;
@@ -137,3 +142,12 @@ void ff_refstruct_replace(void *dstp, const void *src)
 memcpy(dstp, , sizeof(dst));
 }
 }
+
+int ff_refstruct_exclusive(const void *data)
+{
+const RefCount *ref = cget_refcount(data);
+/* Casting const away here is safe, because it is a load.
+ * It is necessary because atomic_load_explicit() does not
+ * accept const atomics in C11 (see also N1807). */
+return atomic_load_explicit((atomic_uintptr_t*)>refcount, 
memory_order_acquire) == 1;
+}
diff --git a/libavcodec/refstruct.h b/libavcodec/refstruct.h
index 0086717c17..ee6936d77a 100644
--- a/libavcodec/refstruct.h
+++ b/libavcodec/refstruct.h
@@ -142,4 +142,13 @@ const void *ff_refstruct_ref_c(const void *obj);
  */
 void ff_refstruct_replace(void *dstp, const void *src);
 
+/**
+ * Check whether the reference count of an object managed
+ * via this API is 1.
+ *
+ * @param obj A pointer to an object managed via this API.
+ * @return 1 if the reference count of obj is 1; 0 otherwise.
+ */
+int ff_refstruct_exclusive(const void *obj);
+
 #endif /* AVCODEC_REFSTRUCT_H */
-- 
2.34.1

___
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".


[FFmpeg-devel] [PATCH 08/42] avcodec/dovi_rpu: Use RefStruct API for Vdr data

2023-09-19 Thread Andreas Rheinhardt
It avoids allocations and the corresponding error checks.
Also avoids casts and indirections.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/dovi_rpu.c | 54 ++-
 libavcodec/dovi_rpu.h |  4 ++--
 libavcodec/hevcdec.c  |  4 +---
 3 files changed, 26 insertions(+), 36 deletions(-)

diff --git a/libavcodec/dovi_rpu.c b/libavcodec/dovi_rpu.c
index dd38936552..794fa878a7 100644
--- a/libavcodec/dovi_rpu.c
+++ b/libavcodec/dovi_rpu.c
@@ -26,6 +26,7 @@
 #include "dovi_rpu.h"
 #include "golomb.h"
 #include "get_bits.h"
+#include "refstruct.h"
 
 enum {
 RPU_COEFF_FIXED = 0,
@@ -35,15 +36,15 @@ enum {
 /**
  * Private contents of vdr_ref.
  */
-typedef struct DOVIVdrRef {
+typedef struct DOVIVdr {
 AVDOVIDataMapping mapping;
 AVDOVIColorMetadata color;
-} DOVIVdrRef;
+} DOVIVdr;
 
 void ff_dovi_ctx_unref(DOVIContext *s)
 {
-for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr_ref); i++)
-av_buffer_unref(>vdr_ref[i]);
+for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr); i++)
+ff_refstruct_unref(>vdr[i]);
 
 *s = (DOVIContext) {
 .logctx = s->logctx,
@@ -52,8 +53,8 @@ void ff_dovi_ctx_unref(DOVIContext *s)
 
 void ff_dovi_ctx_flush(DOVIContext *s)
 {
-for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr_ref); i++)
-av_buffer_unref(>vdr_ref[i]);
+for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr); i++)
+ff_refstruct_unref(>vdr[i]);
 
 *s = (DOVIContext) {
 .logctx = s->logctx,
@@ -61,23 +62,14 @@ void ff_dovi_ctx_flush(DOVIContext *s)
 };
 }
 
-int ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0)
+void ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0)
 {
-int ret;
 s->logctx = s0->logctx;
 s->mapping = s0->mapping;
 s->color = s0->color;
 s->dv_profile = s0->dv_profile;
-for (int i = 0; i < DOVI_MAX_DM_ID; i++) {
-if ((ret = av_buffer_replace(>vdr_ref[i], s0->vdr_ref[i])) < 0)
-goto fail;
-}
-
-return 0;
-
-fail:
-ff_dovi_ctx_unref(s);
-return ret;
+for (int i = 0; i < DOVI_MAX_DM_ID; i++)
+ff_refstruct_replace(>vdr[i], s0->vdr[i]);
 }
 
 void ff_dovi_update_cfg(DOVIContext *s, const AVDOVIDecoderConfigurationRecord 
*cfg)
@@ -195,7 +187,7 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, 
size_t rpu_size)
 {
 AVDOVIRpuDataHeader *hdr = >header;
 GetBitContext *gb = &(GetBitContext){0};
-DOVIVdrRef *vdr;
+DOVIVdr *vdr;
 int ret;
 
 uint8_t nal_prefix;
@@ -278,23 +270,23 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, 
size_t rpu_size)
 if (use_prev_vdr_rpu) {
 int prev_vdr_rpu_id = get_ue_golomb_31(gb);
 VALIDATE(prev_vdr_rpu_id, 0, DOVI_MAX_DM_ID);
-if (!s->vdr_ref[prev_vdr_rpu_id]) {
+if (!s->vdr[prev_vdr_rpu_id]) {
 av_log(s->logctx, AV_LOG_ERROR, "Unknown previous RPU ID: %u\n",
prev_vdr_rpu_id);
 goto fail;
 }
-vdr = (DOVIVdrRef *) s->vdr_ref[prev_vdr_rpu_id]->data;
+vdr = s->vdr[prev_vdr_rpu_id];
 s->mapping = >mapping;
 } else {
 int vdr_rpu_id = get_ue_golomb_31(gb);
 VALIDATE(vdr_rpu_id, 0, DOVI_MAX_DM_ID);
-if (!s->vdr_ref[vdr_rpu_id]) {
-s->vdr_ref[vdr_rpu_id] = av_buffer_allocz(sizeof(DOVIVdrRef));
-if (!s->vdr_ref[vdr_rpu_id])
+if (!s->vdr[vdr_rpu_id]) {
+s->vdr[vdr_rpu_id] = ff_refstruct_allocz(sizeof(DOVIVdr));
+if (!s->vdr[vdr_rpu_id])
 return AVERROR(ENOMEM);
 }
 
-vdr = (DOVIVdrRef *) s->vdr_ref[vdr_rpu_id]->data;
+vdr = s->vdr[vdr_rpu_id];
 s->mapping = >mapping;
 
 vdr->mapping.vdr_rpu_id = vdr_rpu_id;
@@ -390,24 +382,24 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, 
size_t rpu_size)
 int current_dm_id = get_ue_golomb_31(gb);
 VALIDATE(affected_dm_id, 0, DOVI_MAX_DM_ID);
 VALIDATE(current_dm_id, 0, DOVI_MAX_DM_ID);
-if (!s->vdr_ref[affected_dm_id]) {
-s->vdr_ref[affected_dm_id] = av_buffer_allocz(sizeof(DOVIVdrRef));
-if (!s->vdr_ref[affected_dm_id])
+if (!s->vdr[affected_dm_id]) {
+s->vdr[affected_dm_id] = ff_refstruct_allocz(sizeof(DOVIVdr));
+if (!s->vdr[affected_dm_id])
 return AVERROR(ENOMEM);
 }
 
-if (!s->vdr_ref[current_dm_id]) {
+if (!s->vdr[current_dm_id]) {
 av_log(s->logctx, AV_LOG_ERROR, "Unknown previous RPU DM ID: %u\n",
current_dm_id);
 goto fail;
 }
 
 /* Update current pointer based on current_dm_id */
-vdr = (DOVIVdrRef *) s->vdr_ref[current_dm_id]->data;
+vdr = s->vdr[current_dm_id];
 s->color = >color;
 
 /* Update values of affected_dm_id */
-vdr = (DOVIVdrRef *) s->vdr_ref[affected_dm_id]->data;
+vdr = s->vdr[affected_dm_id];
 color = >color;
   

[FFmpeg-devel] [PATCH 07/42] avcodec/wavpack: Use RefStruct API for DSD context

2023-09-19 Thread Andreas Rheinhardt
It avoids allocations and the corresponding error checks.
It also avoids indirections and casts.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/wavpack.c | 25 -
 1 file changed, 8 insertions(+), 17 deletions(-)

diff --git a/libavcodec/wavpack.c b/libavcodec/wavpack.c
index 966f4b83db..97705c8854 100644
--- a/libavcodec/wavpack.c
+++ b/libavcodec/wavpack.c
@@ -28,6 +28,7 @@
 #include "bytestream.h"
 #include "codec_internal.h"
 #include "get_bits.h"
+#include "refstruct.h"
 #include "thread.h"
 #include "threadframe.h"
 #include "unary.h"
@@ -110,8 +111,7 @@ typedef struct WavpackContext {
 ThreadFrame curr_frame, prev_frame;
 Modulation modulation;
 
-AVBufferRef *dsd_ref;
-DSDContext *dsdctx;
+DSDContext *dsdctx; ///< RefStruct reference
 int dsd_channels;
 } WavpackContext;
 
@@ -990,9 +990,8 @@ static int wv_dsd_reset(WavpackContext *s, int channels)
 {
 int i;
 
-s->dsdctx = NULL;
 s->dsd_channels = 0;
-av_buffer_unref(>dsd_ref);
+ff_refstruct_unref(>dsdctx);
 
 if (!channels)
 return 0;
@@ -1000,10 +999,9 @@ static int wv_dsd_reset(WavpackContext *s, int channels)
 if (channels > INT_MAX / sizeof(*s->dsdctx))
 return AVERROR(EINVAL);
 
-s->dsd_ref = av_buffer_allocz(channels * sizeof(*s->dsdctx));
-if (!s->dsd_ref)
+s->dsdctx = ff_refstruct_allocz(channels * sizeof(*s->dsdctx));
+if (!s->dsdctx)
 return AVERROR(ENOMEM);
-s->dsdctx = (DSDContext*)s->dsd_ref->data;
 s->dsd_channels = channels;
 
 for (i = 0; i < channels; i++)
@@ -1028,15 +1026,8 @@ static int update_thread_context(AVCodecContext *dst, 
const AVCodecContext *src)
 return ret;
 }
 
-fdst->dsdctx = NULL;
-fdst->dsd_channels = 0;
-ret = av_buffer_replace(>dsd_ref, fsrc->dsd_ref);
-if (ret < 0)
-return ret;
-if (fsrc->dsd_ref) {
-fdst->dsdctx = (DSDContext*)fdst->dsd_ref->data;
-fdst->dsd_channels = fsrc->dsd_channels;
-}
+ff_refstruct_replace(>dsdctx, fsrc->dsdctx);
+fdst->dsd_channels = fsrc->dsd_channels;
 
 return 0;
 }
@@ -1076,7 +1067,7 @@ static av_cold int wavpack_decode_end(AVCodecContext 
*avctx)
 ff_thread_release_ext_buffer(avctx, >prev_frame);
 av_frame_free(>prev_frame.f);
 
-av_buffer_unref(>dsd_ref);
+ff_refstruct_unref(>dsdctx);
 
 return 0;
 }
-- 
2.34.1

___
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".


[FFmpeg-devel] [PATCH 06/42] avcodec/vp8: Use RefStruct API for seg_map

2023-09-19 Thread Andreas Rheinhardt
Avoids allocations and error checks when syncing the buffers.
Also avoids indirections.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/vp8.c | 23 +--
 libavcodec/vp8.h |  2 +-
 2 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c
index 64b1c7f60e..db325dc90b 100644
--- a/libavcodec/vp8.c
+++ b/libavcodec/vp8.c
@@ -34,6 +34,7 @@
 #include "hwaccel_internal.h"
 #include "hwconfig.h"
 #include "mathops.h"
+#include "refstruct.h"
 #include "thread.h"
 #include "threadframe.h"
 #include "vp8.h"
@@ -105,10 +106,8 @@ static int vp8_alloc_frame(VP8Context *s, VP8Frame *f, int 
ref)
 if ((ret = ff_thread_get_ext_buffer(s->avctx, >tf,
 ref ? AV_GET_BUFFER_FLAG_REF : 0)) < 0)
 return ret;
-if (!(f->seg_map = av_buffer_allocz(s->mb_width * s->mb_height))) {
-ret = AVERROR(ENOMEM);
+if (!(f->seg_map = ff_refstruct_allocz(s->mb_width * s->mb_height)))
 goto fail;
-}
 ret = ff_hwaccel_frame_priv_alloc(s->avctx, >hwaccel_picture_private,
   >hwaccel_priv_buf);
 if (ret < 0)
@@ -117,14 +116,14 @@ static int vp8_alloc_frame(VP8Context *s, VP8Frame *f, 
int ref)
 return 0;
 
 fail:
-av_buffer_unref(>seg_map);
+ff_refstruct_unref(>seg_map);
 ff_thread_release_ext_buffer(s->avctx, >tf);
 return ret;
 }
 
 static void vp8_release_frame(VP8Context *s, VP8Frame *f)
 {
-av_buffer_unref(>seg_map);
+ff_refstruct_unref(>seg_map);
 av_buffer_unref(>hwaccel_priv_buf);
 f->hwaccel_picture_private = NULL;
 ff_thread_release_ext_buffer(s->avctx, >tf);
@@ -139,11 +138,7 @@ static int vp8_ref_frame(VP8Context *s, VP8Frame *dst, 
const VP8Frame *src)
 
 if ((ret = ff_thread_ref_frame(>tf, >tf)) < 0)
 return ret;
-if (src->seg_map &&
-!(dst->seg_map = av_buffer_ref(src->seg_map))) {
-vp8_release_frame(s, dst);
-return AVERROR(ENOMEM);
-}
+ff_refstruct_replace(>seg_map, src->seg_map);
 if (src->hwaccel_picture_private) {
 dst->hwaccel_priv_buf = av_buffer_ref(src->hwaccel_priv_buf);
 if (!dst->hwaccel_priv_buf)
@@ -2334,9 +2329,9 @@ int vp78_decode_mv_mb_modes(AVCodecContext *avctx, 
VP8Frame *curframe,
 if (mb_y == 0)
 AV_WN32A((mb - s->mb_width - 1)->intra4x4_pred_mode_top,
  DC_PRED * 0x01010101);
-decode_mb_mode(s, >mv_bounds, mb, mb_x, mb_y, 
curframe->seg_map->data + mb_xy,
+decode_mb_mode(s, >mv_bounds, mb, mb_x, mb_y, curframe->seg_map 
+ mb_xy,
prev_frame && prev_frame->seg_map ?
-   prev_frame->seg_map->data + mb_xy : NULL, 1, 
is_vp7);
+   prev_frame->seg_map + mb_xy : NULL, 1, is_vp7);
 s->mv_bounds.mv_min.x -= 64;
 s->mv_bounds.mv_max.x -= 64;
 }
@@ -2467,9 +2462,9 @@ static av_always_inline int 
decode_mb_row_no_filter(AVCodecContext *avctx, void
  dst[2] - dst[1], 2);
 
 if (!s->mb_layout)
-decode_mb_mode(s, >mv_bounds, mb, mb_x, mb_y, 
curframe->seg_map->data + mb_xy,
+decode_mb_mode(s, >mv_bounds, mb, mb_x, mb_y, 
curframe->seg_map + mb_xy,
prev_frame && prev_frame->seg_map ?
-   prev_frame->seg_map->data + mb_xy : NULL, 0, 
is_vp7);
+   prev_frame->seg_map + mb_xy : NULL, 0, is_vp7);
 
 prefetch_motion(s, mb, mb_x, mb_y, mb_xy, VP8_FRAME_PREVIOUS);
 
diff --git a/libavcodec/vp8.h b/libavcodec/vp8.h
index 6f29156b53..cb752d4498 100644
--- a/libavcodec/vp8.h
+++ b/libavcodec/vp8.h
@@ -152,7 +152,7 @@ typedef struct VP8ThreadData {
 
 typedef struct VP8Frame {
 ThreadFrame tf;
-AVBufferRef *seg_map;
+uint8_t *seg_map; ///< RefStruct reference
 
 AVBufferRef *hwaccel_priv_buf;
 void *hwaccel_picture_private;
-- 
2.34.1

___
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".


[FFmpeg-devel] [PATCH 05/42] avcodec/hevc_ps: Use RefStruct API for parameter sets

2023-09-19 Thread Andreas Rheinhardt
Avoids allocations and error checks for these allocations;
e.g. syncing buffers across threads can't fail any more
and needn't be checked. It also gets rid of casts and
indirections.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/hevc_parser.c   |  8 ++--
 libavcodec/hevc_ps.c   | 80 --
 libavcodec/hevc_ps.h   | 10 ++---
 libavcodec/hevc_sei.c  |  5 +--
 libavcodec/hevcdec.c   | 36 +++--
 libavcodec/mediacodecdec.c |  6 +--
 libavcodec/videotoolbox.c  |  4 +-
 libavcodec/vulkan_hevc.c   | 16 
 8 files changed, 72 insertions(+), 93 deletions(-)

diff --git a/libavcodec/hevc_parser.c b/libavcodec/hevc_parser.c
index 59f9a0ff3e..87270cffb4 100644
--- a/libavcodec/hevc_parser.c
+++ b/libavcodec/hevc_parser.c
@@ -77,15 +77,15 @@ static int hevc_parse_slice_header(AVCodecParserContext *s, 
H2645NAL *nal,
 av_log(avctx, AV_LOG_ERROR, "PPS id out of range: %d\n", pps_id);
 return AVERROR_INVALIDDATA;
 }
-ps->pps = (HEVCPPS*)ps->pps_list[pps_id]->data;
+ps->pps = ps->pps_list[pps_id];
 
 if (ps->pps->sps_id >= HEVC_MAX_SPS_COUNT || 
!ps->sps_list[ps->pps->sps_id]) {
 av_log(avctx, AV_LOG_ERROR, "SPS id out of range: %d\n", 
ps->pps->sps_id);
 return AVERROR_INVALIDDATA;
 }
-if (ps->sps != (HEVCSPS*)ps->sps_list[ps->pps->sps_id]->data) {
-ps->sps = (HEVCSPS*)ps->sps_list[ps->pps->sps_id]->data;
-ps->vps = (HEVCVPS*)ps->vps_list[ps->sps->vps_id]->data;
+if (ps->sps != ps->sps_list[ps->pps->sps_id]) {
+ps->sps  = ps->sps_list[ps->pps->sps_id];
+ps->vps  = ps->vps_list[ps->sps->vps_id];
 }
 ow  = >sps->output_window;
 
diff --git a/libavcodec/hevc_ps.c b/libavcodec/hevc_ps.c
index 7507d2bf9c..a6b64b92e3 100644
--- a/libavcodec/hevc_ps.c
+++ b/libavcodec/hevc_ps.c
@@ -28,6 +28,7 @@
 #include "h2645_vui.h"
 #include "hevc_data.h"
 #include "hevc_ps.h"
+#include "refstruct.h"
 
 static const uint8_t default_scaling_list_intra[] = {
 16, 16, 16, 16, 17, 18, 21, 24,
@@ -61,40 +62,40 @@ static const uint8_t hevc_sub_height_c[] = {
 
 static void remove_pps(HEVCParamSets *s, int id)
 {
-if (s->pps_list[id] && s->pps == (const HEVCPPS*)s->pps_list[id]->data)
+if (s->pps == s->pps_list[id])
 s->pps = NULL;
-av_buffer_unref(>pps_list[id]);
+ff_refstruct_unref(>pps_list[id]);
 }
 
 static void remove_sps(HEVCParamSets *s, int id)
 {
 int i;
 if (s->sps_list[id]) {
-if (s->sps == (const HEVCSPS*)s->sps_list[id]->data)
+if (s->sps == s->sps_list[id])
 s->sps = NULL;
 
 /* drop all PPS that depend on this SPS */
 for (i = 0; i < FF_ARRAY_ELEMS(s->pps_list); i++)
-if (s->pps_list[i] && ((HEVCPPS*)s->pps_list[i]->data)->sps_id == 
id)
+if (s->pps_list[i] && s->pps_list[i]->sps_id == id)
 remove_pps(s, i);
 
-av_assert0(!(s->sps_list[id] && s->sps == 
(HEVCSPS*)s->sps_list[id]->data));
+av_assert0(!(s->sps_list[id] && s->sps == s->sps_list[id]));
+ff_refstruct_unref(>sps_list[id]);
 }
-av_buffer_unref(>sps_list[id]);
 }
 
 static void remove_vps(HEVCParamSets *s, int id)
 {
 int i;
 if (s->vps_list[id]) {
-if (s->vps == (const HEVCVPS*)s->vps_list[id]->data)
+if (s->vps == s->vps_list[id])
 s->vps = NULL;
 
 for (i = 0; i < FF_ARRAY_ELEMS(s->sps_list); i++)
-if (s->sps_list[i] && ((HEVCSPS*)s->sps_list[i]->data)->vps_id == 
id)
+if (s->sps_list[i] && s->sps_list[i]->vps_id == id)
 remove_sps(s, i);
+ff_refstruct_unref(>vps_list[id]);
 }
-av_buffer_unref(>vps_list[id]);
 }
 
 int ff_hevc_decode_short_term_rps(GetBitContext *gb, AVCodecContext *avctx,
@@ -442,12 +443,10 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, 
AVCodecContext *avctx,
 int i,j;
 int vps_id = 0;
 ptrdiff_t nal_size;
-HEVCVPS *vps;
-AVBufferRef *vps_buf = av_buffer_allocz(sizeof(*vps));
+HEVCVPS *vps = ff_refstruct_allocz(sizeof(*vps));
 
-if (!vps_buf)
+if (!vps)
 return AVERROR(ENOMEM);
-vps = (HEVCVPS*)vps_buf->data;
 
 av_log(avctx, AV_LOG_DEBUG, "Decoding VPS\n");
 
@@ -553,17 +552,17 @@ int ff_hevc_decode_nal_vps(GetBitContext *gb, 
AVCodecContext *avctx,
 }
 
 if (ps->vps_list[vps_id] &&
-!memcmp(ps->vps_list[vps_id]->data, vps_buf->data, vps_buf->size)) {
-av_buffer_unref(_buf);
+!memcmp(ps->vps_list[vps_id], vps, sizeof(*vps))) {
+ff_refstruct_unref();
 } else {
 remove_vps(ps, vps_id);
-ps->vps_list[vps_id] = vps_buf;
+ps->vps_list[vps_id] = vps;
 }
 
 return 0;
 
 err:
-av_buffer_unref(_buf);
+ff_refstruct_unref();
 return AVERROR_INVALIDDATA;
 }
 
@@ -851,7 +850,8 @@ static int map_pixel_format(AVCodecContext *avctx, HEVCSPS 
*sps)
 }
 
 int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, 

[FFmpeg-devel] [PATCH 04/42] avcodec/h264_ps: Use RefStruct API for SPS/PPS

2023-09-19 Thread Andreas Rheinhardt
Avoids allocations and error checks for these allocations;
e.g. syncing buffers across threads can't fail any more
and needn't be checked. It also avoids having to keep
H264ParamSets.pps and H264ParamSets.pps_ref and PPS.sps
and PPS.sps_ref in sync and gets rid of casts and indirections.

(The removal of these checks and the syncing code even more
than offset the additional code for RefStruct.)

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/h264_parser.c   |  9 ++
 libavcodec/h264_picture.c  | 10 +++
 libavcodec/h264_ps.c   | 57 +-
 libavcodec/h264_ps.h   | 13 -
 libavcodec/h264_refs.c |  2 +-
 libavcodec/h264_sei.c  |  2 +-
 libavcodec/h264_slice.c| 41 ---
 libavcodec/h264dec.h   |  1 -
 libavcodec/mediacodecdec.c |  4 +--
 libavcodec/vulkan_h264.c   |  4 +--
 10 files changed, 50 insertions(+), 93 deletions(-)

diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c
index 43abc45f9c..3574010a64 100644
--- a/libavcodec/h264_parser.c
+++ b/libavcodec/h264_parser.c
@@ -47,6 +47,7 @@
 #include "h264data.h"
 #include "mpegutils.h"
 #include "parser.h"
+#include "refstruct.h"
 #include "startcode.h"
 
 typedef struct H264ParseContext {
@@ -373,13 +374,7 @@ static inline int parse_nal_units(AVCodecParserContext *s,
 goto fail;
 }
 
-av_buffer_unref(>ps.pps_ref);
-p->ps.pps = NULL;
-p->ps.sps = NULL;
-p->ps.pps_ref = av_buffer_ref(p->ps.pps_list[pps_id]);
-if (!p->ps.pps_ref)
-goto fail;
-p->ps.pps = (const PPS*)p->ps.pps_ref->data;
+ff_refstruct_replace(>ps.pps, p->ps.pps_list[pps_id]);
 p->ps.sps = p->ps.pps->sps;
 sps   = p->ps.sps;
 
diff --git a/libavcodec/h264_picture.c b/libavcodec/h264_picture.c
index 31b5e231c2..25d0d96ddb 100644
--- a/libavcodec/h264_picture.c
+++ b/libavcodec/h264_picture.c
@@ -32,6 +32,7 @@
 #include "h264dec.h"
 #include "hwaccel_internal.h"
 #include "mpegutils.h"
+#include "refstruct.h"
 #include "thread.h"
 #include "threadframe.h"
 
@@ -49,7 +50,7 @@ void ff_h264_unref_picture(H264Context *h, H264Picture *pic)
 
 av_buffer_unref(>qscale_table_buf);
 av_buffer_unref(>mb_type_buf);
-av_buffer_unref(>pps_buf);
+ff_refstruct_unref(>pps);
 for (i = 0; i < 2; i++) {
 av_buffer_unref(>motion_val_buf[i]);
 av_buffer_unref(>ref_index_buf[i]);
@@ -61,9 +62,10 @@ void ff_h264_unref_picture(H264Context *h, H264Picture *pic)
 
 static void h264_copy_picture_params(H264Picture *dst, const H264Picture *src)
 {
+ff_refstruct_replace(>pps, src->pps);
+
 dst->qscale_table = src->qscale_table;
 dst->mb_type  = src->mb_type;
-dst->pps  = src->pps;
 
 for (int i = 0; i < 2; i++) {
 dst->motion_val[i] = src->motion_val[i];
@@ -113,8 +115,7 @@ int ff_h264_ref_picture(H264Context *h, H264Picture *dst, 
H264Picture *src)
 
 dst->qscale_table_buf = av_buffer_ref(src->qscale_table_buf);
 dst->mb_type_buf  = av_buffer_ref(src->mb_type_buf);
-dst->pps_buf  = av_buffer_ref(src->pps_buf);
-if (!dst->qscale_table_buf || !dst->mb_type_buf || !dst->pps_buf) {
+if (!dst->qscale_table_buf || !dst->mb_type_buf) {
 ret = AVERROR(ENOMEM);
 goto fail;
 }
@@ -174,7 +175,6 @@ int ff_h264_replace_picture(H264Context *h, H264Picture 
*dst, const H264Picture
 
 ret  = av_buffer_replace(>qscale_table_buf, src->qscale_table_buf);
 ret |= av_buffer_replace(>mb_type_buf, src->mb_type_buf);
-ret |= av_buffer_replace(>pps_buf, src->pps_buf);
 if (ret < 0)
 goto fail;
 
diff --git a/libavcodec/h264_ps.c b/libavcodec/h264_ps.c
index 53446e9aab..dcc51b96db 100644
--- a/libavcodec/h264_ps.c
+++ b/libavcodec/h264_ps.c
@@ -34,6 +34,7 @@
 #include "h2645_vui.h"
 #include "h264_ps.h"
 #include "golomb.h"
+#include "refstruct.h"
 
 #define MIN_LOG2_MAX_FRAME_NUM4
 
@@ -85,7 +86,7 @@ static const int level_max_dpb_mbs[][2] = {
 
 static void remove_pps(H264ParamSets *s, int id)
 {
-av_buffer_unref(>pps_list[id]);
+ff_refstruct_unref(>pps_list[id]);
 }
 
 static void remove_sps(H264ParamSets *s, int id)
@@ -95,11 +96,11 @@ static void remove_sps(H264ParamSets *s, int id)
 if (s->sps_list[id]) {
 /* drop all PPS that depend on this SPS */
 for (i = 0; i < FF_ARRAY_ELEMS(s->pps_list); i++)
-if (s->pps_list[i] && ((PPS*)s->pps_list[i]->data)->sps_id == id)
+if (s->pps_list[i] && s->pps_list[i]->sps_id == id)
 remove_pps(s, i);
 }
 #endif
-av_buffer_unref(>sps_list[id]);
+ff_refstruct_unref(>sps_list[id]);
 }
 
 static inline int decode_hrd_parameters(GetBitContext *gb, void *logctx,
@@ -271,31 +272,27 @@ void ff_h264_ps_uninit(H264ParamSets *ps)
 int i;
 
 for (i = 0; i < MAX_SPS_COUNT; i++)
-av_buffer_unref(>sps_list[i]);
+  

[FFmpeg-devel] [PATCH 03/42] avcodec/get_buffer: Use RefStruct API for FramePool

2023-09-19 Thread Andreas Rheinhardt
Avoids allocations and frees and error checks for said allocations;
also avoids a few indirections and casts.

Signed-off-by: Andreas Rheinhardt 
---
 libavcodec/avcodec.c   |  3 ++-
 libavcodec/get_buffer.c| 44 ++
 libavcodec/internal.h  |  2 +-
 libavcodec/pthread_frame.c |  7 +++---
 4 files changed, 17 insertions(+), 39 deletions(-)

diff --git a/libavcodec/avcodec.c b/libavcodec/avcodec.c
index 131834b6de..6365ab87a6 100644
--- a/libavcodec/avcodec.c
+++ b/libavcodec/avcodec.c
@@ -43,6 +43,7 @@
 #include "frame_thread_encoder.h"
 #include "hwconfig.h"
 #include "internal.h"
+#include "refstruct.h"
 #include "thread.h"
 
 /**
@@ -458,7 +459,7 @@ av_cold int avcodec_close(AVCodecContext *avctx)
 av_frame_free(>in_frame);
 av_frame_free(>recon_frame);
 
-av_buffer_unref(>pool);
+ff_refstruct_unref(>pool);
 
 ff_hwaccel_uninit(avctx);
 
diff --git a/libavcodec/get_buffer.c b/libavcodec/get_buffer.c
index a04fd878de..647f8a3df7 100644
--- a/libavcodec/get_buffer.c
+++ b/libavcodec/get_buffer.c
@@ -32,6 +32,7 @@
 
 #include "avcodec.h"
 #include "internal.h"
+#include "refstruct.h"
 
 typedef struct FramePool {
 /**
@@ -52,40 +53,18 @@ typedef struct FramePool {
 int samples;
 } FramePool;
 
-static void frame_pool_free(void *opaque, uint8_t *data)
+static void frame_pool_free(FFRefStructOpaque unused, void *obj)
 {
-FramePool *pool = (FramePool*)data;
+FramePool *pool = obj;
 int i;
 
 for (i = 0; i < FF_ARRAY_ELEMS(pool->pools); i++)
 av_buffer_pool_uninit(>pools[i]);
-
-av_freep();
-}
-
-static AVBufferRef *frame_pool_alloc(void)
-{
-FramePool *pool = av_mallocz(sizeof(*pool));
-AVBufferRef *buf;
-
-if (!pool)
-return NULL;
-
-buf = av_buffer_create((uint8_t*)pool, sizeof(*pool),
-   frame_pool_free, NULL, 0);
-if (!buf) {
-av_freep();
-return NULL;
-}
-
-return buf;
 }
 
 static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame)
 {
-FramePool *pool = avctx->internal->pool ?
-  (FramePool*)avctx->internal->pool->data : NULL;
-AVBufferRef *pool_buf;
+FramePool *pool = avctx->internal->pool;
 int i, ret, ch, planes;
 
 if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) {
@@ -109,10 +88,9 @@ FF_ENABLE_DEPRECATION_WARNINGS
 return 0;
 }
 
-pool_buf = frame_pool_alloc();
-if (!pool_buf)
+pool = ff_refstruct_alloc_ext(sizeof(*pool), 0, NULL, frame_pool_free);
+if (!pool)
 return AVERROR(ENOMEM);
-pool = (FramePool*)pool_buf->data;
 
 switch (avctx->codec_type) {
 case AVMEDIA_TYPE_VIDEO: {
@@ -189,18 +167,18 @@ FF_ENABLE_DEPRECATION_WARNINGS
 default: av_assert0(0);
 }
 
-av_buffer_unref(>internal->pool);
-avctx->internal->pool = pool_buf;
+ff_refstruct_unref(>internal->pool);
+avctx->internal->pool = pool;
 
 return 0;
 fail:
-av_buffer_unref(_buf);
+ff_refstruct_unref();
 return ret;
 }
 
 static int audio_get_buffer(AVCodecContext *avctx, AVFrame *frame)
 {
-FramePool *pool = (FramePool*)avctx->internal->pool->data;
+FramePool *pool = avctx->internal->pool;
 int planes = pool->planes;
 int i;
 
@@ -245,7 +223,7 @@ fail:
 
 static int video_get_buffer(AVCodecContext *s, AVFrame *pic)
 {
-FramePool *pool = (FramePool*)s->internal->pool->data;
+FramePool *pool = s->internal->pool;
 int i;
 
 if (pic->data[0] || pic->data[1] || pic->data[2] || pic->data[3]) {
diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index 83e0bc3fb2..eb9e0d707c 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -62,7 +62,7 @@ typedef struct AVCodecInternal {
  */
 int pad_samples;
 
-AVBufferRef *pool;
+struct FramePool *pool;
 
 void *thread_ctx;
 
diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index 138576778d..7e274b0559 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -35,6 +35,7 @@
 #include "hwconfig.h"
 #include "internal.h"
 #include "pthread_internal.h"
+#include "refstruct.h"
 #include "thread.h"
 #include "threadframe.h"
 #include "version_major.h"
@@ -329,9 +330,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
 
 dst->hwaccel_flags = src->hwaccel_flags;
 
-err = av_buffer_replace(>internal->pool, src->internal->pool);
-if (err < 0)
-return err;
+ff_refstruct_replace(>internal->pool, src->internal->pool);
 }
 
 if (for_user) {
@@ -740,7 +739,7 @@ void ff_frame_thread_free(AVCodecContext *avctx, int 
thread_count)
 av_freep(>priv_data);
 }
 
-av_buffer_unref(>internal->pool);
+ff_refstruct_unref(>internal->pool);
 av_packet_free(>internal->last_pkt_props);
 av_freep(>internal);
 av_buffer_unref(>hw_frames_ctx);
-- 
2.34.1


[FFmpeg-devel] [PATCH 02/42] avcodec/refstruct: Add simple API for refcounted objects

2023-09-19 Thread Andreas Rheinhardt
For now, this API is supposed to replace all the internal uses
of reference counted objects in libavcodec; "internal" here
means that the object is created in libavcodec and is never
put directly in the hands of anyone outside of it.

It is intended to be made public eventually, but for now
I enjoy the ability to modify it freely.

Several shortcomings of the AVBuffer API motivated this API:
a) The unnecessary allocations (and ensuing error checks)
when using the API. Besides the need for runtime checks it
imposes upon the developer the burden of thinking through
what happens in case an error happens. Furthermore, these
error paths are typically not covered by FATE.
b) The AVBuffer API is designed with buffers and not with
objects in mind: The type for the actual buffers used
is uint8_t*; it pretends to be able to make buffers
writable, but this is wrong in case the buffer is not a POD.
Another instance of this thinking is the lack of a reset
callback in the AVBufferPool API.
c) The AVBuffer API incurs unnecessary indirections by
going through the AVBufferRef.data pointer. In case the user
tries to avoid this indirection and stores a pointer to
AVBuffer.data separately (which also allows to use the correct
type), the user has to keep these two pointers in sync
in case they can change (and in any case has two pointers
occupying space in the containing context). See the following
commit using this API for H.264 parameter sets for an example
of the removal of such syncing code as well as the casts
involved in the parts where only the AVBufferRef* pointer
was stored.
d) Given that the AVBuffer API allows custom allocators,
creating refcounted objects with dedicated free functions
often involves a lot of boilerplate like this:
obj = av_mallocz(sizeof(*obj));
ref = av_buffer_create((uint8_t*)obj, sizeof(*obj), free_func, opaque, 0);
if (!ref) {
av_free(obj);
return AVERROR(ENOMEM);
}
(There is also a corresponding av_free() at the end of free_func().)
This is now just
obj = ff_refstruct_alloc_ext(sizeof(*obj), 0, opaque, free_func);
if (!obj)
return AVERROR(ENOMEM);
See the subsequent patch for the framepool (i.e. get_buffer.c)
for an example.

This API does things differently; it is designed to be lightweight*
as well as geared to the common case where the allocator of the
underlying object does not matter as long as it is big enough and
suitably aligned. This allows to allocate the user data together
with the API's bookkeeping data which avoids an allocation as well
as the need for separate pointers to the user data and the API's
bookkeeping data. This entails that the actual allocation of the
object is performed by refstruct, not the user. This is responsible
for avoiding the boilerplate code mentioned in d).

As a downside, custom allocators are not supported, but it will
become apparent in subsequent commits that there are enough
usecases to make it worthwhile.

Another advantage of this API is that one only needs to include
the relevant header if one uses the API and not when one includes
the header or some other component that uses it. This is because there
is no refstruct type analog of AVBufferRef. This brings with it
one further downside: It is not apparent from the pointer itself
whether the underlying object is managed by the refstruct API
or whether this pointer is a reference to it (or merely a pointer
to it).

Finally, this API supports const-qualified opaque pointees;
this will allow to avoid casting const away by the CBS code.

*: Basically the only exception to the you-only-pay-for-what-you-use
rule is that it always uses atomics for the refcount.

Signed-off-by: Andreas Rheinhardt 
---
I am the most unsure about whether to use FFRefStructOpaque
at all or not just a void*; the only beneficiary of this
is CBS where it saves casting one const away.

I am also open to other naming suggestions like RefObject
(RefObj?) for this API.

 libavcodec/Makefile|   1 +
 libavcodec/refstruct.c | 139 +++
 libavcodec/refstruct.h | 145 +
 3 files changed, 285 insertions(+)
 create mode 100644 libavcodec/refstruct.c
 create mode 100644 libavcodec/refstruct.h

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index bf3b0a93f9..7541f38535 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -55,6 +55,7 @@ OBJS = ac3_parser.o   
  \
profiles.o   \
qsv_api.o\
raw.o\
+   refstruct.o  \
utils.o  \
version.o\
vlc.o\
diff --git 

[FFmpeg-devel] [PATCH 01/42] tests/fate-run: Ensure that THREADS=random is actually random

2023-09-19 Thread Andreas Rheinhardt
>From the documentation of GNU awk [1]:
"In most awk implementations, including gawk, rand() starts generating
numbers from the same starting number, or seed, each time you run awk.45
Thus, a program generates the same results each time you run it. The
numbers are random within one awk run but predictable from run to run.
This is convenient for debugging, but if you want a program to do
different things each time it is used, you must change the seed to a
value that is different in each run. To do this, use srand()."

This commit does exactly this.

[1]: 
https://www.gnu.org/software/gawk/manual/html_node/Numeric-Functions.html#index-rand_0028_0029-function

Signed-off-by: Andreas Rheinhardt 
---
 tests/fate-run.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/fate-run.sh b/tests/fate-run.sh
index 743d9b3620..8efb1586b8 100755
--- a/tests/fate-run.sh
+++ b/tests/fate-run.sh
@@ -37,7 +37,7 @@ case $threads in
 random*)
 threads_max=${threads#random}
 [ -z "$threads_max" ] && threads_max=16
-threads=$(awk "BEGIN { print 1+int(rand() * $threads_max) }" < 
/dev/null)
+threads=$(awk "BEGIN { srand(); print 1+int(rand() * $threads_max) }" 
< /dev/null)
 ;;
 esac
 
-- 
2.34.1

___
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".


[FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames

2023-09-19 Thread Andreas Rheinhardt
This patchset initially grew out of my dissatisfaction with the fact
that the AVBuffer API contains implicit allocations in av_buffer_ref()
that need to be checked. Later this combined with my dissatisfaction
with the current ThreadFrame API (which contains an implicit
av_frame_ref()) which forbids decoders to set any AVFrame field
of a frame that is used for syncing after having called
ff_thread_finish_setup(). This leads to a race in the vp9-encparams
test that is fixed in this patchset.

Andreas Rheinhardt (42):
  tests/fate-run: Ensure that THREADS=random is actually random
  avcodec/refstruct: Add simple API for refcounted objects
  avcodec/get_buffer: Use RefStruct API for FramePool
  avcodec/h264_ps: Use RefStruct API for SPS/PPS
  avcodec/hevc_ps: Use RefStruct API for parameter sets
  avcodec/vp8: Use RefStruct API for seg_map
  avcodec/wavpack: Use RefStruct API for DSD context
  avcodec/dovi_rpu: Use RefStruct API for Vdr data
  avcodec/refstruct: Allow checking for exclusive ownership
  avcodec/cbs: Use RefStruct-API for unit content
  avcodec/cbs_sei: Use RefStruct API for SEI messages
  avcodec/decode: Use RefStruct API for hwaccel_picture_private
  avcodec/vulkan_decode: Use RefStruct API for shared_ref
  avcodec/hevcdec: Use RefStruct API for RefPicListTap buffer
  avcodec/pthread_frame: Use RefStruct API for ThreadFrame.progress
  avcodec/nvdec: Use RefStruct API for decoder_ref
  avcodec/refstruct: Add RefStruct pool API
  avcodec/h264dec: Use RefStruct-pool API instead of AVBufferPool API
  avcodec/hevcdec: Use RefStruct-pool API instead of AVBufferPool API
  avcodec/nvdec: Use RefStruct-pool API for decoder pool
  avcodec/refstruct: Allow to always return zeroed pool entries
  avcodec/vp9: Use RefStruct-pool API for extradata
  avcodec/vaapi_encode: Use RefStruct pool API, stop abusing AVBuffer
API
  avcodec/refstruct: Allow to share pools
  avcodec/vp9: Join extradata buffer pools
  avcodec/refstruct: Allow to use a dynamic opaque
  avcodec/pthread_frame: Add new progress API
  avcodec/mimic: Switch to ProgressFrames
  avcodec/vp3: Switch to ProgressFrames
  avcodec/vp9: Switch to ProgressFrames
  avcodec/vp9: Fix race when attaching side-data for show-existing frame
  avcodec/vp9: Reduce wait times
  avcodec/vp9: Simplify replacing VP9Frame
  avcodec/vp9: Replace atomic_store() by atomic_init()
  avcodec/threadprogress: Add new API for frame-threaded progress
  avcodec/wavpack: Use ThreadProgress API
  avcodec/vp8: Convert to ProgressFrame API
  avcodec/codec_internal: Remove FF_CODEC_CAP_ALLOCATE_PROGRESS
  avcodec/hevcdec: Move collocated_ref to HEVCContext
  avcodec/hevcdec: Switch to ProgressFrames
  avcodec/pngdec: Switch to ProgressFrames
  avcodec/ffv1dec: Switch to ProgressFrames

 doc/multithreading.txt|   8 +-
 libavcodec/Makefile   |   1 +
 libavcodec/av1dec.c   |  64 +---
 libavcodec/av1dec.h   |  14 +-
 libavcodec/avcodec.c  |   4 +-
 libavcodec/cbs.c  | 103 +++
 libavcodec/cbs.h  |  12 +-
 libavcodec/cbs_av1.c  |  32 +-
 libavcodec/cbs_av1.h  |   3 +-
 libavcodec/cbs_h264.h |   6 +-
 libavcodec/cbs_h2645.c| 113 +++
 libavcodec/cbs_h265.h |   9 +-
 libavcodec/cbs_h266.h |  11 +-
 libavcodec/cbs_h266_syntax_template.c |  10 +-
 libavcodec/cbs_internal.h |   7 +-
 libavcodec/cbs_sei.c  |  61 ++--
 libavcodec/cbs_sei.h  |  20 +-
 libavcodec/cbs_sei_syntax_template.c  |   5 +
 libavcodec/codec_internal.h   |   7 +-
 libavcodec/decode.c   | 146 +++--
 libavcodec/decode.h   |  10 +-
 libavcodec/dovi_rpu.c |  54 ++--
 libavcodec/dovi_rpu.h |   4 +-
 libavcodec/dxva2_vp9.c|   4 +-
 libavcodec/ffv1.c |   1 -
 libavcodec/ffv1.h |   4 +-
 libavcodec/ffv1dec.c  |  82 +++---
 libavcodec/get_buffer.c   |  44 +--
 libavcodec/h264_mb.c  |   4 +-
 libavcodec/h264_parser.c  |   9 +-
 libavcodec/h264_picture.c |  91 ++
 libavcodec/h264_ps.c  |  57 ++--
 libavcodec/h264_ps.h  |  13 +-
 libavcodec/h264_refs.c|   2 +-
 libavcodec/h264_sei.c |   2 +-
 libavcodec/h264_slice.c   |  88 +++---
 libavcodec/h264dec.c  |  21 +-
 libavcodec/h264dec.h  |  25 +-
 libavcodec/hevc_filter.c  |   8 +-
 libavcodec/hevc_mvs.c |   8 +-
 libavcodec/hevc_parser.c  |   8 +-
 libavcodec/hevc_ps.c  |  80 +++--
 libavcodec/hevc_ps.h  |  10 +-
 libavcodec/hevc_refs.c|  64 ++--
 libavcodec/hevc_sei.c |   5 +-
 libavcodec/hevcdec.c  

[FFmpeg-devel] [PATCH 26/27] WIP fftools/ffmpeg_mux: convert to the scheduler

2023-09-19 Thread Anton Khirnov
---
 fftools/ffmpeg.c  |  26 --
 fftools/ffmpeg.h  |   8 --
 fftools/ffmpeg_mux.c  | 184 --
 fftools/ffmpeg_mux.h  |  14 ++-
 fftools/ffmpeg_mux_init.c |  33 +++
 fftools/ffmpeg_opt.c  |   6 +-
 6 files changed, 80 insertions(+), 191 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 69e73b84ed..e82d88b3e0 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -806,38 +806,12 @@ int trigger_fix_sub_duration_heartbeat(OutputStream *ost, 
const AVPacket *pkt)
 static int process_input_packet(InputStream *ist, const AVPacket *pkt, int 
no_eof)
 {
 InputFile *f = input_files[ist->file_index];
-int64_t dts_est = AV_NOPTS_VALUE;
 int ret = 0;
 int eof_reached = 0;
 
 if (ret == AVERROR_EOF || (!pkt && !ist->decoding_needed))
 eof_reached = 1;
 
-if (pkt && pkt->opaque_ref) {
-DemuxPktData *pd = (DemuxPktData*)pkt->opaque_ref->data;
-dts_est = pd->dts_est;
-}
-
-if (f->recording_time != INT64_MAX) {
-int64_t start_time = 0;
-if (copy_ts) {
-start_time += f->start_time != AV_NOPTS_VALUE ? f->start_time : 0;
-start_time += start_at_zero ? 0 : f->start_time_effective;
-}
-if (dts_est >= f->recording_time + start_time)
-pkt = NULL;
-}
-
-for (int oidx = 0; oidx < ist->nb_outputs; oidx++) {
-OutputStream *ost = ist->outputs[oidx];
-if (ost->enc || (!pkt && no_eof))
-continue;
-
-ret = of_streamcopy(ost, pkt, dts_est);
-if (ret < 0)
-return ret;
-}
-
 return !eof_reached;
 }
 
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 66b5e398bc..e3aea75415 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -665,7 +665,6 @@ extern FilterGraph **filtergraphs;
 extern intnb_filtergraphs;
 
 extern char *vstats_filename;
-extern char *sdp_filename;
 
 extern float dts_delta_threshold;
 extern float dts_error_threshold;
@@ -813,13 +812,6 @@ void of_free(OutputFile **pof);
 
 void of_enc_stats_close(void);
 
-int of_output_packet(OutputFile *of, OutputStream *ost, AVPacket *pkt);
-
-/**
- * @param dts predicted packet dts in AV_TIME_BASE_Q
- */
-int of_streamcopy(OutputStream *ost, const AVPacket *pkt, int64_t dts);
-
 int64_t of_filesize(OutputFile *of);
 
 int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch);
diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c
index 9628728d95..ba90079266 100644
--- a/fftools/ffmpeg_mux.c
+++ b/fftools/ffmpeg_mux.c
@@ -22,16 +22,13 @@
 
 #include "ffmpeg.h"
 #include "ffmpeg_mux.h"
-#include "objpool.h"
 #include "sync_queue.h"
-#include "thread_queue.h"
 
 #include "libavutil/fifo.h"
 #include "libavutil/intreadwrite.h"
 #include "libavutil/log.h"
 #include "libavutil/mem.h"
 #include "libavutil/timestamp.h"
-#include "libavutil/thread.h"
 
 #include "libavcodec/packet.h"
 
@@ -42,8 +39,6 @@ typedef struct MuxThreadContext {
 AVPacket *pkt;
 } MuxThreadContext;
 
-int want_sdp = 1;
-
 static Muxer *mux_from_of(OutputFile *of)
 {
 return (Muxer*)of;
@@ -254,19 +249,22 @@ void *muxer_thread(void *arg)
 OutputStream *ost;
 int stream_idx, stream_eof = 0;
 
-ret = tq_receive(mux->tq, _idx, mt.pkt);
+ret = sch_mux_receive(mux->sch, of->index, mt.pkt);
+stream_idx = mt.pkt->stream_index;
 if (stream_idx < 0) {
 av_log(mux, AV_LOG_VERBOSE, "All streams finished\n");
 ret = 0;
 break;
 }
 
-ost = of->streams[stream_idx];
+ost = of->streams[mux->sch_stream_idx[stream_idx]];
+mt.pkt->stream_index = ost->index;
+
 ret = sync_queue_process(mux, ost, ret < 0 ? NULL : mt.pkt, 
_eof);
 av_packet_unref(mt.pkt);
 if (ret == AVERROR_EOF) {
 if (stream_eof) {
-tq_receive_finish(mux->tq, stream_idx);
+sch_mux_receive_finish(mux->sch, of->index, stream_idx);
 } else {
 av_log(mux, AV_LOG_VERBOSE, "Muxer returned EOF\n");
 ret = 0;
@@ -278,17 +276,19 @@ void *muxer_thread(void *arg)
 }
 }
 
+// XXX move av_write_trailer() here?
+
 finish:
 mux_thread_uninit();
 
-for (unsigned int i = 0; i < mux->fc->nb_streams; i++)
-tq_receive_finish(mux->tq, i);
+sch_mux_receive_finish(mux->sch, of->index, -1);
 
 av_log(mux, AV_LOG_VERBOSE, "Terminating muxer thread\n");
 
 return (void*)(intptr_t)ret;
 }
 
+#if 0
 static int thread_submit_packet(Muxer *mux, OutputStream *ost, AVPacket *pkt)
 {
 int ret = 0;
@@ -296,7 +296,8 @@ static int thread_submit_packet(Muxer *mux, OutputStream 
*ost, AVPacket *pkt)
 if (!pkt || ost->finished & MUXER_FINISHED)
 goto finish;
 
-ret = tq_send(mux->tq, ost->index, pkt);
+// XXX
+//ret = tq_send(mux->tq, ost->index, pkt);
 if (ret < 0)
 goto finish;
 

[FFmpeg-devel] [PATCH 27/27] WIP: ffmpeg: switch to scheduler

2023-09-19 Thread Anton Khirnov
---
 fftools/ffmpeg.c | 237 ++-
 fftools/ffmpeg.h |   6 --
 2 files changed, 10 insertions(+), 233 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index e82d88b3e0..f3e150e453 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -137,6 +137,8 @@ static struct termios oldtty;
 static int restore_tty;
 #endif
 
+// XXX should be triggered from the demuxer after every input packets
+#if 0
 /* sub2video hack:
Convert subtitles to video with alpha to insert them in filter graphs.
This is a temporary solution until libavfilter gets real subtitles support.
@@ -160,6 +162,7 @@ static void sub2video_heartbeat(InputFile *infile, int64_t 
pts, AVRational tb)
 }
 
 /* end of sub2video hack */
+#endif
 
 static void term_exit_sigsafe(void)
 {
@@ -802,19 +805,6 @@ int trigger_fix_sub_duration_heartbeat(OutputStream *ost, 
const AVPacket *pkt)
 return 0;
 }
 
-/* pkt = NULL means EOF (needed to flush decoder buffers) */
-static int process_input_packet(InputStream *ist, const AVPacket *pkt, int 
no_eof)
-{
-InputFile *f = input_files[ist->file_index];
-int ret = 0;
-int eof_reached = 0;
-
-if (ret == AVERROR_EOF || (!pkt && !ist->decoding_needed))
-eof_reached = 1;
-
-return !eof_reached;
-}
-
 static void print_stream_maps(void)
 {
 av_log(NULL, AV_LOG_INFO, "Stream mapping:\n");
@@ -891,43 +881,6 @@ static void print_stream_maps(void)
 }
 }
 
-/**
- * Select the output stream to process.
- *
- * @retval 0 an output stream was selected
- * @retval AVERROR(EAGAIN) need to wait until more input is available
- * @retval AVERROR_EOF no more streams need output
- */
-static int choose_output(OutputStream **post)
-{
-int64_t opts_min = INT64_MAX;
-OutputStream *ost_min = NULL;
-
-for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost)) {
-int64_t opts;
-
-if (ost->filter && ost->filter->last_pts != AV_NOPTS_VALUE) {
-opts = ost->filter->last_pts;
-} else {
-opts = ost->last_mux_dts == AV_NOPTS_VALUE ?
-   INT64_MIN : ost->last_mux_dts;
-}
-
-if (!ost->initialized && !ost->finished) {
-ost_min = ost;
-break;
-}
-if (!ost->finished && opts < opts_min) {
-opts_min = opts;
-ost_min  = ost;
-}
-}
-if (!ost_min)
-return AVERROR_EOF;
-*post = ost_min;
-return ost_min->unavailable ? AVERROR(EAGAIN) : 0;
-}
-
 static void set_tty_echo(int on)
 {
 #if HAVE_TERMIOS_H
@@ -999,153 +952,22 @@ static int check_keyboard_interaction(int64_t cur_time)
 return 0;
 }
 
-static void reset_eagain(void)
-{
-for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost))
-ost->unavailable = 0;
-}
-
-#if 0
-static void decode_flush(InputFile *ifile)
-{
-for (int i = 0; i < ifile->nb_streams; i++) {
-InputStream *ist = ifile->streams[i];
-
-if (ist->discard || !ist->decoding_needed)
-continue;
-
-dec_packet(ist, NULL, 1);
-}
-}
-#endif
-
-/*
- * Return
- * - 0 -- one packet was read and processed
- * - AVERROR(EAGAIN) -- no packets were available for selected file,
- *   this function should be called again
- * - AVERROR_EOF -- this function should not be called again
- */
-static int process_input(int file_index, AVPacket *pkt)
-{
-InputFile *ifile = input_files[file_index];
-InputStream *ist;
-int ret, i;
-
-ret = 0;
-
-#if 0
-if (ret == 1) {
-/* the input file is looped: flush the decoders */
-decode_flush(ifile);
-return AVERROR(EAGAIN);
-}
-#endif
-if (ret < 0) {
-if (ret != AVERROR_EOF) {
-av_log(ifile, AV_LOG_ERROR,
-   "Error retrieving a packet from demuxer: %s\n", 
av_err2str(ret));
-if (exit_on_error)
-return ret;
-}
-
-for (i = 0; i < ifile->nb_streams; i++) {
-ist = ifile->streams[i];
-if (!ist->discard) {
-ret = process_input_packet(ist, NULL, 0);
-if (ret>0)
-return 0;
-else if (ret < 0)
-return ret;
-}
-
-/* mark all outputs that don't go through lavfi as finished */
-for (int oidx = 0; oidx < ist->nb_outputs; oidx++) {
-OutputStream *ost = ist->outputs[oidx];
-OutputFile*of = output_files[ost->file_index];
-
-ret = of_output_packet(of, ost, NULL);
-if (ret < 0)
-return ret;
-}
-}
-
-ifile->eof_reached = 1;
-return AVERROR(EAGAIN);
-}
-
-reset_eagain();
-
-ist = ifile->streams[pkt->stream_index];
-
-sub2video_heartbeat(ifile, pkt->pts, pkt->time_base);
-
-ret = process_input_packet(ist, pkt, 0);
-
-av_packet_unref(pkt);
-
-return ret < 0 ? ret : 

[FFmpeg-devel] [PATCH 24/27] WIP fftools/ffmpeg_filter: convert to the scheduler

2023-09-19 Thread Anton Khirnov
---
 fftools/ffmpeg.h|  22 --
 fftools/ffmpeg_filter.c | 533 
 2 files changed, 152 insertions(+), 403 deletions(-)

diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 841f8d0d68..eb4e8e27a9 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -312,9 +312,6 @@ typedef struct OutputFilter {
 
 enum AVMediaType type;
 
-/* pts of the last frame received from this filter, in AV_TIME_BASE_Q */
-int64_t last_pts;
-
 uint64_t nb_frames_dup;
 uint64_t nb_frames_drop;
 } OutputFilter;
@@ -745,8 +742,6 @@ int subtitle_wrap_frame(AVFrame *frame, AVSubtitle 
*subtitle, int copy);
  */
 FrameData *frame_data(AVFrame *frame);
 
-int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame, int 
keep_reference);
-int ifilter_send_eof(InputFilter *ifilter, int64_t pts, AVRational tb);
 void ifilter_sub2video_heartbeat(InputFilter *ifilter, int64_t pts, AVRational 
tb);
 
 /**
@@ -769,26 +764,9 @@ int fg_create(FilterGraph **pfg, char *graph_desc, 
Scheduler *sch);
 
 void fg_free(FilterGraph **pfg);
 
-/**
- * Perform a step of transcoding for the specified filter graph.
- *
- * @param[in]  graph filter graph to consider
- * @param[out] best_ist  input stream where a frame would allow to continue
- * @return  0 for success, <0 for error
- */
-int fg_transcode_step(FilterGraph *graph, InputStream **best_ist);
-
 void fg_send_command(FilterGraph *fg, double time, const char *target,
  const char *command, const char *arg, int all_filters);
 
-/**
- * Get and encode new output from specified filtergraph, without causing
- * activity.
- *
- * @return  0 for success, <0 for severe errors
- */
-int reap_filters(FilterGraph *fg, int flush);
-
 int ffmpeg_parse_options(int argc, char **argv, Scheduler *sch);
 
 void enc_stats_write(OutputStream *ost, EncStats *es,
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index e8e78f5454..c588dde452 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -21,7 +21,6 @@
 #include 
 
 #include "ffmpeg.h"
-#include "thread_queue.h"
 
 #include "libavfilter/avfilter.h"
 #include "libavfilter/buffersink.h"
@@ -46,7 +45,6 @@ enum FrameOpaque {
 FRAME_OPAQUE_REAP_FILTERS = 1,
 FRAME_OPAQUE_CHOOSE_INPUT,
 FRAME_OPAQUE_SUB_HEARTBEAT,
-FRAME_OPAQUE_EOF,
 FRAME_OPAQUE_SEND_COMMAND,
 };
 
@@ -62,8 +60,7 @@ typedef struct FilterGraphPriv {
 int is_meta;
 int disable_conversions;
 
-int nb_inputs_bound;
-int nb_outputs_bound;
+unsigned nb_outputs_done;
 
 const char *graph_desc;
 
@@ -75,14 +72,10 @@ typedef struct FilterGraphPriv {
 Scheduler   *sch;
 unsigned sch_idx;
 
-pthread_tthread;
 /**
  * Queue for sending frames from the main thread to the filtergraph. Has
  * nb_inputs+1 streams - the first nb_inputs stream correspond to
  * filtergraph inputs. Frames on those streams may have their opaque set to
- * - FRAME_OPAQUE_EOF: frame contains no data, but pts+timebase of the
- *   EOF event for the correspondint stream. Will be immediately followed 
by
- *   this stream being send-closed.
  * - FRAME_OPAQUE_SUB_HEARTBEAT: frame contains no data, but pts+timebase 
of
  *   a subtitle heartbeat event. Will only be sent for sub2video streams.
  *
@@ -96,7 +89,7 @@ typedef struct FilterGraphPriv {
  *   available the terminating empty frame's opaque will contain the 
index+1
  *   of the filtergraph input to which more input frames should be 
supplied.
  */
-ThreadQueue *queue_in;
+
 /**
  * Queue for sending frames from the filtergraph back to the main thread.
  * Has nb_outputs+1 streams - the first nb_outputs stream correspond to
@@ -105,7 +98,7 @@ typedef struct FilterGraphPriv {
  * The last stream is "control" - see documentation for queue_in for more
  * details.
  */
-ThreadQueue *queue_out;
+//ThreadQueue *queue_out;
 // submitting frames to filter thread returned EOF
 // this only happens on thread exit, so is not per-input
 int  eof_in;
@@ -130,6 +123,7 @@ typedef struct FilterGraphThread {
 // The output index is stored in frame opaque.
 AVFifo  *frame_queue_out;
 
+// set to 1 after at least one frame passed through this output
 int  got_frame;
 
 // EOF status of each input/output, as received by the thread
@@ -260,9 +254,6 @@ typedef struct OutputFilterPriv {
 int64_t ts_offset;
 int64_t next_pts;
 FPSConvContext fps;
-
-// set to 1 after at least one frame passed through this output
-int got_frame;
 } OutputFilterPriv;
 
 static OutputFilterPriv *ofp_from_ofilter(OutputFilter *ofilter)
@@ -660,57 +651,6 @@ static int ifilter_has_all_input_formats(FilterGraph *fg)
 
 static void *filter_thread(void *arg);
 
-// start the filtering thread once all inputs and outputs are bound
-static int 

[FFmpeg-devel] [PATCH 25/27] WIP fftools/ffmpeg_enc: convert to the scheduler

2023-09-19 Thread Anton Khirnov
---
 fftools/ffmpeg.c  |   1 -
 fftools/ffmpeg.h  |   4 +-
 fftools/ffmpeg_dec.c  |   1 +
 fftools/ffmpeg_enc.c  | 231 ++
 fftools/ffmpeg_mux_init.c |  43 ++-
 5 files changed, 45 insertions(+), 235 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index a09a9e1200..69e73b84ed 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -1228,7 +1228,6 @@ static int transcode(Scheduler *sch, int 
*err_rate_exceeded)
 } else if (err_rate)
 av_log(ist, AV_LOG_VERBOSE, "Decode error rate %g\n", err_rate);
 }
-ret = err_merge(ret, enc_flush());
 
 term_exit();
 
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index eb4e8e27a9..66b5e398bc 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -797,10 +797,8 @@ int enc_alloc(Encoder **penc, const AVCodec *codec,
   Scheduler *sch, unsigned sch_idx);
 void enc_free(Encoder **penc);
 
-int enc_open(OutputStream *ost, const AVFrame *frame);
+int enc_open(void *opaque, const AVFrame *frame);
 int enc_subtitle(OutputFile *of, OutputStream *ost, const AVSubtitle *sub);
-int enc_frame(OutputStream *ost, AVFrame *frame);
-int enc_flush(void);
 
 /*
  * Initialize muxing state for the given stream, should be called
diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c
index 400fa666b9..d2dc27303d 100644
--- a/fftools/ffmpeg_dec.c
+++ b/fftools/ffmpeg_dec.c
@@ -377,6 +377,7 @@ static int process_subtitle(InputStream *ist, AVFrame 
*frame)
 if (!ost->enc || ost->type != AVMEDIA_TYPE_SUBTITLE)
 continue;
 
+// XXX
 ret = enc_subtitle(output_files[ost->file_index], ost, subtitle);
 if (ret < 0)
 return ret;
diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c
index 9bede78a1e..0944cddf1f 100644
--- a/fftools/ffmpeg_enc.c
+++ b/fftools/ffmpeg_enc.c
@@ -57,21 +57,6 @@ struct Encoder {
 
 Scheduler  *sch;
 unsignedsch_idx;
-
-pthread_t   thread;
-/**
- * Queue for sending frames from the main thread to
- * the encoder thread.
- */
-ThreadQueue*queue_in;
-/**
- * Queue for sending encoded packets from the encoder thread
- * to the main thread.
- *
- * An empty packet is sent to signal that a previously sent
- * frame has been fully processed.
- */
-ThreadQueue*queue_out;
 };
 
 // data that is local to the decoder thread and not visible outside of it
@@ -80,24 +65,6 @@ typedef struct EncoderThread {
 AVPacket  *pkt;
 } EncoderThread;
 
-static int enc_thread_stop(Encoder *e)
-{
-void *ret;
-
-if (!e->queue_in)
-return 0;
-
-tq_send_finish(e->queue_in, 0);
-tq_receive_finish(e->queue_out, 0);
-
-pthread_join(e->thread, );
-
-tq_free(>queue_in);
-tq_free(>queue_out);
-
-return (int)(intptr_t)ret;
-}
-
 void enc_free(Encoder **penc)
 {
 Encoder *enc = *penc;
@@ -105,8 +72,6 @@ void enc_free(Encoder **penc)
 if (!enc)
 return;
 
-enc_thread_stop(enc);
-
 av_frame_free(>sq_frame);
 av_frame_free(>sub_frame);
 
@@ -223,52 +188,9 @@ static int set_encoder_id(OutputFile *of, OutputStream 
*ost)
 return 0;
 }
 
-static int enc_thread_start(OutputStream *ost)
-{
-Encoder *e = ost->enc;
-ObjPool *op;
-int ret = 0;
-
-op = objpool_alloc_frames();
-if (!op)
-return AVERROR(ENOMEM);
-
-e->queue_in = tq_alloc(1, 1, op, frame_move);
-if (!e->queue_in) {
-objpool_free();
-return AVERROR(ENOMEM);
-}
-
-op = objpool_alloc_packets();
-if (!op)
-goto fail;
-
-e->queue_out = tq_alloc(1, 4, op, pkt_move);
-if (!e->queue_out) {
-objpool_free();
-goto fail;
-}
-
-ret = pthread_create(>thread, NULL, encoder_thread, ost);
-if (ret) {
-ret = AVERROR(ret);
-av_log(ost, AV_LOG_ERROR, "pthread_create() failed: %s\n",
-   av_err2str(ret));
-goto fail;
-}
-
-return 0;
-fail:
-if (ret >= 0)
-ret = AVERROR(ENOMEM);
-
-tq_free(>queue_in);
-tq_free(>queue_out);
-return ret;
-}
-
-int enc_open(OutputStream *ost, const AVFrame *frame)
+int enc_open(void *opaque, const AVFrame *frame)
 {
+OutputStream *ost = opaque;
 InputStream *ist = ost->ist;
 Encoder  *e = ost->enc;
 AVCodecContext *enc_ctx = ost->enc_ctx;
@@ -276,6 +198,7 @@ int enc_open(OutputStream *ost, const AVFrame *frame)
 const AVCodec  *enc = enc_ctx->codec;
 OutputFile  *of = output_files[ost->file_index];
 FrameData *fd;
+int frame_samples = 0;
 int ret;
 
 if (e->opened)
@@ -425,11 +348,8 @@ int enc_open(OutputStream *ost, const AVFrame *frame)
 return AVERROR(ENOMEM);
 }
 
-if (ost->enc_ctx->frame_size) {
-av_assert0(ost->sq_idx_encode >= 0);
-sq_frame_samples(output_files[ost->file_index]->sq_encode,
- 

[FFmpeg-devel] [PATCH 23/27] WIP fftools/ffmpeg_dec: convert to the scheduler

2023-09-19 Thread Anton Khirnov
---
 fftools/ffmpeg.c |   9 +--
 fftools/ffmpeg.h |  11 ---
 fftools/ffmpeg_dec.c | 189 +--
 3 files changed, 42 insertions(+), 167 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 00e57c4382..a09a9e1200 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -810,11 +810,6 @@ static int process_input_packet(InputStream *ist, const 
AVPacket *pkt, int no_eo
 int ret = 0;
 int eof_reached = 0;
 
-if (ist->decoding_needed) {
-ret = dec_packet(ist, pkt, no_eof);
-if (ret < 0 && ret != AVERROR_EOF)
-return ret;
-}
 if (ret == AVERROR_EOF || (!pkt && !ist->decoding_needed))
 eof_reached = 1;
 
@@ -1036,6 +1031,7 @@ static void reset_eagain(void)
 ost->unavailable = 0;
 }
 
+#if 0
 static void decode_flush(InputFile *ifile)
 {
 for (int i = 0; i < ifile->nb_streams; i++) {
@@ -1047,6 +1043,7 @@ static void decode_flush(InputFile *ifile)
 dec_packet(ist, NULL, 1);
 }
 }
+#endif
 
 /*
  * Return
@@ -1063,11 +1060,13 @@ static int process_input(int file_index, AVPacket *pkt)
 
 ret = 0;
 
+#if 0
 if (ret == 1) {
 /* the input file is looped: flush the decoders */
 decode_flush(ifile);
 return AVERROR(EAGAIN);
 }
+#endif
 if (ret < 0) {
 if (ret != AVERROR_EOF) {
 av_log(ifile, AV_LOG_ERROR,
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 4646c05bea..841f8d0d68 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -815,17 +815,6 @@ int hwaccel_retrieve_data(AVCodecContext *avctx, AVFrame 
*input);
 int dec_open(InputStream *ist, Scheduler *sch, unsigned sch_idx);
 void dec_free(Decoder **pdec);
 
-/**
- * Submit a packet for decoding
- *
- * When pkt==NULL and no_eof=0, there will be no more input. Flush decoders and
- * mark all downstreams as finished.
- *
- * When pkt==NULL and no_eof=1, the stream was reset (e.g. after a seek). Flush
- * decoders and await further input.
- */
-int dec_packet(InputStream *ist, const AVPacket *pkt, int no_eof);
-
 int enc_alloc(Encoder **penc, const AVCodec *codec,
   Scheduler *sch, unsigned sch_idx);
 void enc_free(Encoder **penc);
diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c
index dc8d0374a3..400fa666b9 100644
--- a/fftools/ffmpeg_dec.c
+++ b/fftools/ffmpeg_dec.c
@@ -53,24 +53,6 @@ struct Decoder {
 
 Scheduler  *sch;
 unsignedsch_idx;
-
-pthread_t   thread;
-/**
- * Queue for sending coded packets from the main thread to
- * the decoder thread.
- *
- * An empty packet is sent to flush the decoder without terminating
- * decoding.
- */
-ThreadQueue*queue_in;
-/**
- * Queue for sending decoded frames from the decoder thread
- * to the main thread.
- *
- * An empty frame is sent to signal that a single packet has been fully
- * processed.
- */
-ThreadQueue*queue_out;
 };
 
 // data that is local to the decoder thread and not visible outside of it
@@ -79,24 +61,6 @@ typedef struct DecThreadContext {
 AVPacket*pkt;
 } DecThreadContext;
 
-static int dec_thread_stop(Decoder *d)
-{
-void *ret;
-
-if (!d->queue_in)
-return 0;
-
-tq_send_finish(d->queue_in, 0);
-tq_receive_finish(d->queue_out, 0);
-
-pthread_join(d->thread, );
-
-tq_free(>queue_in);
-tq_free(>queue_out);
-
-return (intptr_t)ret;
-}
-
 void dec_free(Decoder **pdec)
 {
 Decoder *dec = *pdec;
@@ -104,8 +68,6 @@ void dec_free(Decoder **pdec)
 if (!dec)
 return;
 
-dec_thread_stop(dec);
-
 av_frame_free(>frame);
 av_packet_free(>pkt);
 
@@ -147,25 +109,6 @@ fail:
 return AVERROR(ENOMEM);
 }
 
-static int send_frame_to_filters(InputStream *ist, AVFrame *decoded_frame)
-{
-int i, ret = 0;
-
-for (i = 0; i < ist->nb_filters; i++) {
-ret = ifilter_send_frame(ist->filters[i], decoded_frame,
- i < ist->nb_filters - 1 ||
- ist->dec->type == AVMEDIA_TYPE_SUBTITLE);
-if (ret == AVERROR_EOF)
-ret = 0; /* ignore */
-if (ret < 0) {
-av_log(NULL, AV_LOG_ERROR,
-   "Failed to inject frame into filter network: %s\n", 
av_err2str(ret));
-break;
-}
-}
-return ret;
-}
-
 static AVRational audio_samplerate_update(void *logctx, Decoder *d,
   const AVFrame *frame)
 {
@@ -420,7 +363,8 @@ static int process_subtitle(InputStream *ist, AVFrame 
*frame)
 if (!subtitle)
 return 0;
 
-ret = send_frame_to_filters(ist, frame);
+// XXX
+//ret = send_frame_to_filters(ist, frame);
 if (ret < 0)
 return ret;
 
@@ -495,7 +439,7 @@ static int transcode_subtitles(InputStream *ist, const 
AVPacket *pkt,
 
 ist->frames_decoded++;
 
-// XXX the queue for transferring data back to the main thread runs

[FFmpeg-devel] [PATCH 22/27] WIP fftools/ffmpeg_demux: convert to the scheduler

2023-09-19 Thread Anton Khirnov
---
 fftools/ffmpeg.c   |   2 +-
 fftools/ffmpeg.h   |  12 
 fftools/ffmpeg_demux.c | 131 +++--
 3 files changed, 60 insertions(+), 85 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 995424ca93..00e57c4382 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -1061,7 +1061,7 @@ static int process_input(int file_index, AVPacket *pkt)
 InputStream *ist;
 int ret, i;
 
-ret = ifile_get_packet(ifile, pkt);
+ret = 0;
 
 if (ret == 1) {
 /* the input file is looped: flush the decoders */
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 278216e5ff..4646c05bea 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -860,18 +860,6 @@ int64_t of_filesize(OutputFile *of);
 int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch);
 void ifile_close(InputFile **f);
 
-/**
- * Get next input packet from the demuxer.
- *
- * @param pkt the packet is written here when this function returns 0
- * @return
- * - 0 when a packet has been read successfully
- * - 1 when stream end was reached, but the stream is looped;
- * caller should flush decoders and read from this demuxer again
- * - a negative error code on failure
- */
-int ifile_get_packet(InputFile *f, AVPacket *pkt);
-
 int ist_output_add(InputStream *ist, OutputStream *ost);
 int ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple);
 
diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c
index 074546d517..9c0e54979e 100644
--- a/fftools/ffmpeg_demux.c
+++ b/fftools/ffmpeg_demux.c
@@ -21,8 +21,6 @@
 
 #include "ffmpeg.h"
 #include "ffmpeg_sched.h"
-#include "objpool.h"
-#include "thread_queue.h"
 
 #include "libavutil/avassert.h"
 #include "libavutil/avstring.h"
@@ -34,7 +32,6 @@
 #include "libavutil/pixdesc.h"
 #include "libavutil/time.h"
 #include "libavutil/timestamp.h"
-#include "libavutil/thread.h"
 
 #include "libavcodec/packet.h"
 
@@ -65,6 +62,9 @@ typedef struct DemuxStream {
 
 double ts_scale;
 
+// scheduler returned EOF for this stream
+int finished;
+
 int streamcopy_needed;
 
 int wrap_correction_done;
@@ -115,11 +115,10 @@ typedef struct Demuxer {
 double readrate_initial_burst;
 
 Scheduler*sch;
-ThreadQueue  *thread_queue;
-int   thread_queue_size;
-pthread_t thread;
 
 int   read_started;
+int   nb_streams_used;
+int   nb_streams_finished;
 } Demuxer;
 
 static DemuxStream *ds_from_ist(InputStream *ist)
@@ -503,6 +502,8 @@ static int input_packet_process(Demuxer *d, AVPacket *pkt)
av_ts2timestr(input_files[ist->file_index]->ts_offset, 
_TIME_BASE_Q));
 }
 
+pkt->stream_index = ds->sch_idx_stream;
+
 return 0;
 }
 
@@ -565,9 +566,14 @@ static void *input_thread(void *arg)
 
 discard_unused_programs(f);
 
+// XXX
+d->read_started = 1;
+
 d->wallclock_start = av_gettime_relative();
 
 while (1) {
+DemuxStream *ds;
+
 ret = av_read_frame(f->ctx, pkt);
 
 if (ret == AVERROR(EAGAIN)) {
@@ -575,25 +581,32 @@ static void *input_thread(void *arg)
 continue;
 }
 if (ret < 0) {
-#if 0
 if (d->loop) {
-/* signal looping to the consumer thread */
-pkt->opaque = (void*)(intptr_t)PKT_OPAQUE_SEEK;
-ret = tq_send(d->thread_queue, 0, pkt);
-if (ret >= 0)
-ret = seek_to_start(d);
+/* signal looping to our consumers */
+for (int i = 0; i < f->nb_streams; i++) {
+pkt->opaque   = (void*)(intptr_t)PKT_OPAQUE_SEEK;
+pkt->stream_index = i;
+
+ret = sch_demux_send(d->sch, f->index, pkt);
+// XXX
+if (ret >= 0)
+//ret = seek_to_start(d);
+if (ret < 0)
+break;
+}
 if (ret >= 0)
 continue;
 
 /* fallthrough to the error path */
 }
-#endif
 
 if (ret == AVERROR_EOF)
 av_log(d, AV_LOG_VERBOSE, "EOF while reading input\n");
-else
+else {
 av_log(d, AV_LOG_ERROR, "Error during demuxing: %s\n",
av_err2str(ret));
+ret = exit_on_error ? ret : 0;
+}
 
 break;
 }
@@ -605,8 +618,9 @@ static void *input_thread(void *arg)
 
 /* the following test is needed in case new streams appear
dynamically in stream : we ignore them */
-if (pkt->stream_index >= f->nb_streams ||
-f->streams[pkt->stream_index]->discard) {
+ds = pkt->stream_index < f->nb_streams ?
+ ds_from_ist(f->streams[pkt->stream_index]) : NULL;
+if (!ds || 

[FFmpeg-devel] [PATCH 21/27] WIP fftools/ffmpeg: add thread-aware transcode scheduling infrastructure

2023-09-19 Thread Anton Khirnov
See the comment block at the top of fftools/ffmpeg_sched.h for more
details on what this scheduler is for.

This commit adds the scheduling code itself, along with minimal
integration with the rest of the program:
* allocating and freeing the scheduler
* passing it throughout the call stack in order to register the
  individual components (demuxers/decoders/filtergraphs/encoders/muxers)
  with the scheduler

The scheduler is not actually used as of this commit, so it should not
result in any change in behavior. That will change in future commits.
---
 fftools/Makefile  |1 +
 fftools/ffmpeg.c  |   18 +-
 fftools/ffmpeg.h  |   26 +-
 fftools/ffmpeg_dec.c  |   10 +-
 fftools/ffmpeg_demux.c|   44 +-
 fftools/ffmpeg_enc.c  |   13 +-
 fftools/ffmpeg_filter.c   |   38 +-
 fftools/ffmpeg_mux.c  |   15 +-
 fftools/ffmpeg_mux.h  |   10 +
 fftools/ffmpeg_mux_init.c |   70 +-
 fftools/ffmpeg_opt.c  |   22 +-
 fftools/ffmpeg_sched.c| 1703 +
 fftools/ffmpeg_sched.h|  414 +
 13 files changed, 2332 insertions(+), 52 deletions(-)
 create mode 100644 fftools/ffmpeg_sched.c
 create mode 100644 fftools/ffmpeg_sched.h

diff --git a/fftools/Makefile b/fftools/Makefile
index 56820e6bc8..d6a8913a7f 100644
--- a/fftools/Makefile
+++ b/fftools/Makefile
@@ -18,6 +18,7 @@ OBJS-ffmpeg +=  \
 fftools/ffmpeg_mux.o\
 fftools/ffmpeg_mux_init.o   \
 fftools/ffmpeg_opt.o\
+fftools/ffmpeg_sched.o  \
 fftools/objpool.o   \
 fftools/sync_queue.o\
 fftools/thread_queue.o  \
diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index e084318864..995424ca93 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -99,6 +99,7 @@
 
 #include "cmdutils.h"
 #include "ffmpeg.h"
+#include "ffmpeg_sched.h"
 #include "sync_queue.h"
 
 const char program_name[] = "ffmpeg";
@@ -1155,7 +1156,7 @@ static int transcode_step(OutputStream *ost, AVPacket 
*demux_pkt)
 /*
  * The following code is the main loop of the file converter
  */
-static int transcode(int *err_rate_exceeded)
+static int transcode(Scheduler *sch, int *err_rate_exceeded)
 {
 int ret = 0, i;
 InputStream *ist;
@@ -1293,6 +1294,8 @@ static int64_t getmaxrss(void)
 
 int main(int argc, char **argv)
 {
+Scheduler *sch = NULL;
+
 int ret, err_rate_exceeded;
 BenchmarkTimeStamps ti;
 
@@ -1310,8 +1313,14 @@ int main(int argc, char **argv)
 
 show_banner(argc, argv, options);
 
+sch = sch_alloc();
+if (!sch) {
+ret = AVERROR(ENOMEM);
+goto finish;
+}
+
 /* parse options and open all input/output files */
-ret = ffmpeg_parse_options(argc, argv);
+ret = ffmpeg_parse_options(argc, argv, sch);
 if (ret < 0)
 goto finish;
 
@@ -1329,7 +1338,7 @@ int main(int argc, char **argv)
 }
 
 current_time = ti = get_benchmark_time_stamps();
-ret = transcode(_rate_exceeded);
+ret = transcode(sch, _rate_exceeded);
 if (ret >= 0 && do_benchmark) {
 int64_t utime, stime, rtime;
 current_time = get_benchmark_time_stamps();
@@ -1349,5 +1358,8 @@ finish:
 ret = 0;
 
 ffmpeg_cleanup(ret);
+
+sch_free();
+
 return ret;
 }
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index a4fd825749..278216e5ff 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -27,6 +27,7 @@
 #include 
 
 #include "cmdutils.h"
+#include "ffmpeg_sched.h"
 #include "sync_queue.h"
 
 #include "libavformat/avformat.h"
@@ -731,7 +732,8 @@ int parse_and_set_vsync(const char *arg, int *vsync_var, 
int file_idx, int st_id
 int check_filter_outputs(void);
 int filtergraph_is_simple(const FilterGraph *fg);
 int init_simple_filtergraph(InputStream *ist, OutputStream *ost,
-char *graph_desc);
+char *graph_desc,
+Scheduler *sch, unsigned sch_idx_enc);
 int init_complex_filtergraph(FilterGraph *fg);
 
 int copy_av_subtitle(AVSubtitle *dst, const AVSubtitle *src);
@@ -754,7 +756,8 @@ void ifilter_sub2video_heartbeat(InputFilter *ifilter, 
int64_t pts, AVRational t
  */
 int ifilter_parameters_from_dec(InputFilter *ifilter, const AVCodecContext 
*dec);
 
-int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost);
+int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost,
+ unsigned sched_idx_enc);
 
 /**
  * Create a new filtergraph in the global filtergraph list.
@@ -762,7 +765,7 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream 
*ost);
  * @param graph_desc Graph description; an av_malloc()ed string, filtergraph
  *   takes ownership of it.
  */
-int fg_create(FilterGraph **pfg, char *graph_desc);
+int fg_create(FilterGraph **pfg, char *graph_desc, Scheduler *sch);
 
 void fg_free(FilterGraph **pfg);
 
@@ -786,7 +789,7 @@ void fg_send_command(FilterGraph *fg, double time, const 
char *target,
  */
 int 

[FFmpeg-devel] [PATCH 20/27] WIP: fftools/ffmpeg_enc: move encoding to a separate thread

2023-09-19 Thread Anton Khirnov
As for the analogous decoding change, this is only a preparatory step to
a fully threaded architecture and does not yet make encoding truly
parallel. The main thread will currently submit a frame and wait until
it has been fully processed by the encoder before moving on. That will
change in future commits after filters are moved to threads and a
thread-aware scheduler is added.

WIP: resolve all // XXX left in the code
Also, if an encoder with a sync queue receives EOF it will terminate
after processing everything it currently has, even though the sync queue
might still be triggered by other threads.
---
 fftools/ffmpeg_enc.c | 384 ++-
 1 file changed, 340 insertions(+), 44 deletions(-)

diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c
index d8d7c3416d..ea542173c5 100644
--- a/fftools/ffmpeg_enc.c
+++ b/fftools/ffmpeg_enc.c
@@ -20,6 +20,7 @@
 #include 
 
 #include "ffmpeg.h"
+#include "thread_queue.h"
 
 #include "libavutil/avassert.h"
 #include "libavutil/avstring.h"
@@ -43,6 +44,7 @@ struct Encoder {
 
 // packet for receiving encoded output
 AVPacket *pkt;
+AVFrame  *sub_frame;
 
 // combined size of all the packets received from the encoder
 uint64_t data_size;
@@ -51,8 +53,48 @@ struct Encoder {
 uint64_t packets_encoded;
 
 int opened;
+int finished;
+
+pthread_t   thread;
+/**
+ * Queue for sending frames from the main thread to
+ * the encoder thread.
+ */
+ThreadQueue*queue_in;
+/**
+ * Queue for sending encoded packets from the encoder thread
+ * to the main thread.
+ *
+ * An empty packet is sent to signal that a previously sent
+ * frame has been fully processed.
+ */
+ThreadQueue*queue_out;
 };
 
+// data that is local to the decoder thread and not visible outside of it
+typedef struct EncoderThread {
+AVFrame *frame;
+AVPacket  *pkt;
+} EncoderThread;
+
+static int enc_thread_stop(Encoder *e)
+{
+void *ret;
+
+if (!e->queue_in)
+return 0;
+
+tq_send_finish(e->queue_in, 0);
+tq_receive_finish(e->queue_out, 0);
+
+pthread_join(e->thread, );
+
+tq_free(>queue_in);
+tq_free(>queue_out);
+
+return (int)(intptr_t)ret;
+}
+
 void enc_free(Encoder **penc)
 {
 Encoder *enc = *penc;
@@ -60,7 +102,10 @@ void enc_free(Encoder **penc)
 if (!enc)
 return;
 
+enc_thread_stop(enc);
+
 av_frame_free(>sq_frame);
+av_frame_free(>sub_frame);
 
 av_packet_free(>pkt);
 
@@ -77,6 +122,12 @@ int enc_alloc(Encoder **penc, const AVCodec *codec)
 if (!enc)
 return AVERROR(ENOMEM);
 
+if (codec->type == AVMEDIA_TYPE_SUBTITLE) {
+enc->sub_frame = av_frame_alloc();
+if (!enc->sub_frame)
+goto fail;
+}
+
 enc->pkt = av_packet_alloc();
 if (!enc->pkt)
 goto fail;
@@ -165,6 +216,52 @@ static int set_encoder_id(OutputFile *of, OutputStream 
*ost)
 return 0;
 }
 
+static void *encoder_thread(void *arg);
+
+static int enc_thread_start(OutputStream *ost)
+{
+Encoder *e = ost->enc;
+ObjPool *op;
+int ret = 0;
+
+op = objpool_alloc_frames();
+if (!op)
+return AVERROR(ENOMEM);
+
+e->queue_in = tq_alloc(1, 1, op, frame_move);
+if (!e->queue_in) {
+objpool_free();
+return AVERROR(ENOMEM);
+}
+
+op = objpool_alloc_packets();
+if (!op)
+goto fail;
+
+e->queue_out = tq_alloc(1, 4, op, pkt_move);
+if (!e->queue_out) {
+objpool_free();
+goto fail;
+}
+
+ret = pthread_create(>thread, NULL, encoder_thread, ost);
+if (ret) {
+ret = AVERROR(ret);
+av_log(ost, AV_LOG_ERROR, "pthread_create() failed: %s\n",
+   av_err2str(ret));
+goto fail;
+}
+
+return 0;
+fail:
+if (ret >= 0)
+ret = AVERROR(ENOMEM);
+
+tq_free(>queue_in);
+tq_free(>queue_out);
+return ret;
+}
+
 int enc_open(OutputStream *ost, const AVFrame *frame)
 {
 InputStream *ist = ost->ist;
@@ -387,6 +484,13 @@ int enc_open(OutputStream *ost, const AVFrame *frame)
 if (ost->st->time_base.num <= 0 || ost->st->time_base.den <= 0)
 ost->st->time_base = av_add_q(ost->enc_ctx->time_base, (AVRational){0, 
1});
 
+ret = enc_thread_start(ost);
+if (ret < 0) {
+av_log(ost, AV_LOG_ERROR, "Error starting encoder thread: %s\n",
+   av_err2str(ret));
+return ret;
+}
+
 ret = of_stream_init(of, ost);
 if (ret < 0)
 return ret;
@@ -400,19 +504,18 @@ static int check_recording_time(OutputStream *ost, 
int64_t ts, AVRational tb)
 
 if (of->recording_time != INT64_MAX &&
 av_compare_ts(ts, tb, of->recording_time, AV_TIME_BASE_Q) >= 0) {
-close_output_stream(ost);
 return 0;
 }
 return 1;
 }
 
-int enc_subtitle(OutputFile *of, OutputStream *ost, const AVSubtitle *sub)
+static int do_subtitle_out(OutputFile *of, OutputStream *ost, 

[FFmpeg-devel] [PATCH 18/27] XXX fftools/ffmpeg_enc: temporarily disable side data copying

2023-09-19 Thread Anton Khirnov
It conflicts with threading work.
---
 fftools/ffmpeg_enc.c  |  2 ++
 .../fate/matroska-mastering-display-metadata  | 24 ++-
 tests/ref/lavf/mpg|  6 ++--
 tests/ref/seek/lavf-mpg   | 30 +--
 4 files changed, 23 insertions(+), 39 deletions(-)

diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c
index c300a11f28..d8d7c3416d 100644
--- a/fftools/ffmpeg_enc.c
+++ b/fftools/ffmpeg_enc.c
@@ -345,6 +345,7 @@ int enc_open(OutputStream *ost, const AVFrame *frame)
 return ret;
 }
 
+#if 0
 if (ost->enc_ctx->nb_coded_side_data) {
 int i;
 
@@ -380,6 +381,7 @@ int enc_open(OutputStream *ost, const AVFrame *frame)
 }
 }
 }
+#endif
 
 // copy timebase while removing common factors
 if (ost->st->time_base.num <= 0 || ost->st->time_base.den <= 0)
diff --git a/tests/ref/fate/matroska-mastering-display-metadata 
b/tests/ref/fate/matroska-mastering-display-metadata
index 3726469213..6d3c4f1023 100644
--- a/tests/ref/fate/matroska-mastering-display-metadata
+++ b/tests/ref/fate/matroska-mastering-display-metadata
@@ -1,5 +1,5 @@
-9d0fb8123a2e90e85153428a91d1ee9d 
*tests/data/fate/matroska-mastering-display-metadata.matroska
-1669589 tests/data/fate/matroska-mastering-display-metadata.matroska
+1ed4248debff46761cf6230c55768dd9 
*tests/data/fate/matroska-mastering-display-metadata.matroska
+1669465 tests/data/fate/matroska-mastering-display-metadata.matroska
 #extradata 0:4, 0x040901a3
 #extradata 3:  200, 0x506463a8
 #tb 0: 1/1000
@@ -24,7 +24,7 @@
 #sar 3: 1/1
 0,  0,  0,   16,57008, 0x43416399, S=2,8,  
 88
 1,  0,  0,   16, 2403, 0xaa818522
-3,  0,  0,   16,   274117, 0xc439610f, S=2,8,  
 88
+3,  0,  0,   16,   274117, 0xc439610f
 0, 17, 17,   16,57248, 0xa06cd7b5
 1, 17, 17,   16, 2403, 0xe1a991e5
 2, 17, 17,   16, 1602, 0x5d868171
@@ -74,22 +74,4 @@ codec_name=pcm_s16be
 [STREAM]
 index=3
 codec_name=ffv1
-[SIDE_DATA]
-side_data_type=Content light level metadata
-max_content=1000
-max_average=100
-[/SIDE_DATA]
-[SIDE_DATA]
-side_data_type=Mastering display metadata
-red_x=17/25
-red_y=8/25
-green_x=53/200
-green_y=69/100
-blue_x=3/20
-blue_y=3/50
-white_point_x=3127/1
-white_point_y=329/1000
-min_luminance=0/1
-max_luminance=1000/1
-[/SIDE_DATA]
 [/STREAM]
diff --git a/tests/ref/lavf/mpg b/tests/ref/lavf/mpg
index 332b7114b5..8779871ebf 100644
--- a/tests/ref/lavf/mpg
+++ b/tests/ref/lavf/mpg
@@ -1,9 +1,9 @@
-01bbdea588da51ab4a9d1d26f3443c96 *tests/data/lavf/lavf.mpg
+f9b99341af206109dc6d48fc7c57fb5c *tests/data/lavf/lavf.mpg
 372736 tests/data/lavf/lavf.mpg
 tests/data/lavf/lavf.mpg CRC=0x000e23ae
-87b447b78a7d1141b9d41bb3aa50434d *tests/data/lavf/lavf.mpg
+d2b1947240fd0d8da0561c785788cc32 *tests/data/lavf/lavf.mpg
 389120 tests/data/lavf/lavf.mpg
 tests/data/lavf/lavf.mpg CRC=0x60ba4ab9
-284f41c914df75c12de01e223d65f87f *tests/data/lavf/lavf.mpg
+a4cc793cd26616ac980514c4399e36cb *tests/data/lavf/lavf.mpg
 372736 tests/data/lavf/lavf.mpg
 tests/data/lavf/lavf.mpg CRC=0x000e23ae
diff --git a/tests/ref/seek/lavf-mpg b/tests/ref/seek/lavf-mpg
index e804b84739..e8b8899fb6 100644
--- a/tests/ref/seek/lavf-mpg
+++ b/tests/ref/seek/lavf-mpg
@@ -2,51 +2,51 @@ ret: 0 st: 1 flags:1 dts: 0.529089 pts: 0.529089 pos: 
  2048 size:   208
 ret: 0 st:-1 flags:0  ts:-1.00
 ret: 0 st: 1 flags:1 dts: 0.529089 pts: 0.529089 pos:   2048 size:   
208
 ret: 0 st:-1 flags:1  ts: 1.894167
-ret: 0 st: 1 flags:1 dts: 1.051544 pts: 1.051544 pos: 342028 size:   
314
+ret: 0 st: 0 flags:1 dts: 1.46 pts: 1.50 pos: 346112 size: 
24937
 ret: 0 st: 0 flags:0  ts: 0.788333
-ret: 0 st: 0 flags:0 dts: 0.82 pts: 0.86 pos: 118784 size: 
14717
+ret: 0 st: 0 flags:0 dts: 0.82 pts: 0.86 pos: 126976 size: 
14717
 ret: 0 st: 0 flags:1  ts:-0.317500
 ret: 0 st: 1 flags:1 dts: 0.529089 pts: 0.529089 pos:   2048 size:   
208
 ret: 0 st: 1 flags:0  ts: 2.576667
-ret: 0 st: 1 flags:1 dts: 1.312767 pts: 1.312767 pos: 368652 size:   
379
+ret: 0 st: 1 flags:1 dts: 1.312767 pts: 1.312767 pos:  51200 size:   
367
 ret: 0 st: 1 flags:1  ts: 1.470833
-ret: 0 st: 1 flags:1 dts: 1.312767 pts: 1.312767 pos: 368652 size:   
379
+ret: 0 st: 1 flags:1 dts: 1.312767 pts: 1.312767 pos:  51200 size:   
367
 ret: 0 st:-1 flags:0  ts: 0.365002
 ret: 0 st: 1 flags:1 dts: 0.529089 pts: 0.529089 pos:   2048 size:   
208
 ret: 0 st:-1 flags:1  ts:-0.740831
 ret: 0 st: 1 flags:1 dts: 0.529089 pts: 0.529089 pos:   2048 size:   
208
 ret: 0 st: 0 flags:0  ts: 2.15
-ret: 0 st: 1 flags:1 dts: 1.051544 pts: 1.051544 pos: 342028 

[FFmpeg-devel] [PATCH 19/27] XXX ffmpeg temporarily disable -stream_loop

2023-09-19 Thread Anton Khirnov
It conflicts with threading work.
---
 fftools/ffmpeg.h   |  6 +++---
 fftools/ffmpeg_dec.c   |  4 
 fftools/ffmpeg_demux.c |  8 +++-
 tests/fate/ffmpeg.mak  | 12 ++--
 4 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 88b8ed12c0..a4fd825749 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -45,7 +45,7 @@
 #include "libavutil/pixfmt.h"
 #include "libavutil/rational.h"
 #include "libavutil/thread.h"
-#include "libavutil/threadmessage.h"
+//#include "libavutil/threadmessage.h"
 
 #include "libswresample/swresample.h"
 
@@ -438,8 +438,8 @@ typedef struct InputFile {
 
 /* when looping the input file, this queue is used by decoders to report
  * the last frame duration back to the demuxer thread */
-AVThreadMessageQueue *audio_duration_queue;
-int   audio_duration_queue_size;
+//AVThreadMessageQueue *audio_duration_queue;
+//int   audio_duration_queue_size;
 } InputFile;
 
 enum forced_keyframes_const {
diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c
index fb7b404020..36163195ca 100644
--- a/fftools/ffmpeg_dec.c
+++ b/fftools/ffmpeg_dec.c
@@ -702,6 +702,7 @@ static void *decoder_thread(void *arg)
 if (!flush_buffers)
 break;
 
+#if 0
 /* report last frame duration to the demuxer thread */
 if (ist->dec->type == AVMEDIA_TYPE_AUDIO) {
 LastFrameDuration dur;
@@ -713,6 +714,7 @@ static void *decoder_thread(void *arg)
 
 av_thread_message_queue_send(ifile->audio_duration_queue, 
, 0);
 }
+#endif
 
 avcodec_flush_buffers(ist->dec_ctx);
 } else if (ret < 0) {
@@ -738,10 +740,12 @@ finish:
 tq_receive_finish(d->queue_in,  0);
 tq_send_finish   (d->queue_out, 0);
 
+#if 0
 // make sure the demuxer does not get stuck waiting for audio durations
 // that will never arrive
 if (ifile->audio_duration_queue && ist->dec->type == AVMEDIA_TYPE_AUDIO)
 av_thread_message_queue_set_err_recv(ifile->audio_duration_queue, 
AVERROR_EOF);
+#endif
 
 dec_thread_uninit();
 
diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c
index 0955956117..ea74b45663 100644
--- a/fftools/ffmpeg_demux.c
+++ b/fftools/ffmpeg_demux.c
@@ -150,6 +150,7 @@ static void report_new_stream(Demuxer *d, const AVPacket 
*pkt)
 d->nb_streams_warn = pkt->stream_index + 1;
 }
 
+#if 0
 static void ifile_duration_update(Demuxer *d, DemuxStream *ds,
   int64_t last_duration)
 {
@@ -217,6 +218,7 @@ static int seek_to_start(Demuxer *d)
 
 return ret;
 }
+#endif
 
 static void ts_discontinuity_detect(Demuxer *d, InputStream *ist,
 AVPacket *pkt)
@@ -568,6 +570,7 @@ static void *input_thread(void *arg)
 continue;
 }
 if (ret < 0) {
+#if 0
 if (d->loop) {
 /* signal looping to the consumer thread */
 pkt->opaque = (void*)(intptr_t)PKT_OPAQUE_SEEK;
@@ -579,6 +582,7 @@ static void *input_thread(void *arg)
 
 /* fallthrough to the error path */
 }
+#endif
 
 if (ret == AVERROR_EOF)
 av_log(d, AV_LOG_VERBOSE, "EOF while reading input\n");
@@ -655,7 +659,7 @@ static void thread_stop(Demuxer *d)
 
 tq_free(>thread_queue);
 
-av_thread_message_queue_free(>audio_duration_queue);
+//av_thread_message_queue_free(>audio_duration_queue);
 }
 
 static int thread_start(Demuxer *d)
@@ -677,6 +681,7 @@ static int thread_start(Demuxer *d)
 return AVERROR(ENOMEM);
 }
 
+#if 0
 if (d->loop) {
 int nb_audio_dec = 0;
 
@@ -694,6 +699,7 @@ static int thread_start(Demuxer *d)
 f->audio_duration_queue_size = nb_audio_dec;
 }
 }
+#endif
 
 if ((ret = pthread_create(>thread, NULL, input_thread, d))) {
 av_log(d, AV_LOG_ERROR, "pthread_create failed: %s. Try to increase 
`ulimit -v` or decrease `ulimit -s`.\n", strerror(ret));
diff --git a/tests/fate/ffmpeg.mak b/tests/fate/ffmpeg.mak
index ebc1e1f189..a5dac5476a 100644
--- a/tests/fate/ffmpeg.mak
+++ b/tests/fate/ffmpeg.mak
@@ -154,10 +154,10 @@ fate-ffmpeg-fix_sub_duration: CMD = fmtstdout srt 
-fix_sub_duration \
 
 # FIXME: the integer AAC decoder does not produce the same output on all 
platforms
 # so until that is fixed we use the volume filter to silence the data
-FATE_SAMPLES_FFMPEG-$(call FRAMECRC, MATROSKA, H264 AAC_FIXED, 
PCM_S32LE_ENCODER VOLUME_FILTER) += fate-ffmpeg-streamloop-transcode-av
-fate-ffmpeg-streamloop-transcode-av: CMD = \
-framecrc -auto_conversion_filters -stream_loop 3 -c:a aac_fixed -i 
$(TARGET_SAMPLES)/mkv/1242-small.mkv \
--af volume=0:precision=fixed -c:a pcm_s32le
+#FATE_SAMPLES_FFMPEG-$(call FRAMECRC, MATROSKA, H264 AAC_FIXED, 
PCM_S32LE_ENCODER VOLUME_FILTER) += fate-ffmpeg-streamloop-transcode-av

[FFmpeg-devel] [PATCH 16/27] fftools/ffmpeg_demux: switch from AVThreadMessageQueue to ThreadQueue

2023-09-19 Thread Anton Khirnov
* the code is made shorter and simpler
* avoids constantly allocating and freeing AVPackets, thanks to
  ThreadQueue integration with ObjPool
* is consistent with decoding/filtering/muxing
* reduces the diff in the future switch to thread-aware scheduling

This makes ifile_get_packet() always block. Any potential issues caused
by this will be resolved by the switch to thread-aware scheduling in
future commits.
---
 fftools/ffmpeg.c|  32 +--
 fftools/ffmpeg.h|  14 -
 fftools/ffmpeg_demux.c  | 116 +++-
 fftools/ffmpeg_filter.c |   2 +-
 4 files changed, 71 insertions(+), 93 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 7c33b56cd3..7d6972f689 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -1029,9 +1029,6 @@ static int check_keyboard_interaction(int64_t cur_time)
 
 static void reset_eagain(void)
 {
-int i;
-for (i = 0; i < nb_input_files; i++)
-input_files[i]->eagain = 0;
 for (OutputStream *ost = ost_iter(NULL); ost; ost = ost_iter(ost))
 ost->unavailable = 0;
 }
@@ -1055,19 +1052,14 @@ static void decode_flush(InputFile *ifile)
  *   this function should be called again
  * - AVERROR_EOF -- this function should not be called again
  */
-static int process_input(int file_index)
+static int process_input(int file_index, AVPacket *pkt)
 {
 InputFile *ifile = input_files[file_index];
 InputStream *ist;
-AVPacket *pkt;
 int ret, i;
 
-ret = ifile_get_packet(ifile, );
+ret = ifile_get_packet(ifile, pkt);
 
-if (ret == AVERROR(EAGAIN)) {
-ifile->eagain = 1;
-return ret;
-}
 if (ret == 1) {
 /* the input file is looped: flush the decoders */
 decode_flush(ifile);
@@ -1114,7 +1106,7 @@ static int process_input(int file_index)
 
 ret = process_input_packet(ist, pkt, 0);
 
-av_packet_free();
+av_packet_unref(pkt);
 
 return ret < 0 ? ret : 0;
 }
@@ -1124,7 +1116,7 @@ static int process_input(int file_index)
  *
  * @return  0 for success, <0 for error
  */
-static int transcode_step(OutputStream *ost)
+static int transcode_step(OutputStream *ost, AVPacket *demux_pkt)
 {
 InputStream  *ist = NULL;
 int ret;
@@ -1139,10 +1131,8 @@ static int transcode_step(OutputStream *ost)
 av_assert0(ist);
 }
 
-ret = process_input(ist->file_index);
+ret = process_input(ist->file_index, demux_pkt);
 if (ret == AVERROR(EAGAIN)) {
-if (input_files[ist->file_index]->eagain)
-ost->unavailable = 1;
 return 0;
 }
 
@@ -1168,12 +1158,19 @@ static int transcode(int *err_rate_exceeded)
 int ret = 0, i;
 InputStream *ist;
 int64_t timer_start;
+AVPacket *demux_pkt = NULL;
 
 print_stream_maps();
 
 *err_rate_exceeded = 0;
 atomic_store(_init_done, 1);
 
+demux_pkt = av_packet_alloc();
+if (!demux_pkt) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+
 if (stdin_interaction) {
 av_log(NULL, AV_LOG_INFO, "Press [q] to stop, [?] for help\n");
 }
@@ -1201,7 +1198,7 @@ static int transcode(int *err_rate_exceeded)
 break;
 }
 
-ret = transcode_step(ost);
+ret = transcode_step(ost, demux_pkt);
 if (ret < 0 && ret != AVERROR_EOF) {
 av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", 
av_err2str(ret));
 break;
@@ -1242,6 +1239,9 @@ static int transcode(int *err_rate_exceeded)
 /* dump report by using the first video and audio streams */
 print_report(1, timer_start, av_gettime_relative());
 
+fail:
+av_packet_free(_pkt);
+
 return ret;
 }
 
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 5a8f52ce00..88b8ed12c0 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -101,6 +101,17 @@ typedef struct {
 } AudioChannelMap;
 #endif
 
+/**
+ * AVPacket.opaque values we use.
+ */
+enum PacketOpaque {
+/**
+ * Sent by demuxers after seeking, so that decoders should be flushed.
+ * The packet wit this value is otherwise always empty.
+ */
+PKT_OPAQUE_SEEK = 1,
+};
+
 typedef struct DemuxPktData {
 // estimated dts in AV_TIME_BASE_Q,
 // to be used when real dts is missing
@@ -406,7 +417,6 @@ typedef struct InputFile {
 
 AVFormatContext *ctx;
 int eof_reached;  /* true if eof reached */
-int eagain;   /* true if last read attempt returned EAGAIN */
 int64_t input_ts_offset;
 int input_sync_ref;
 /**
@@ -856,7 +866,7 @@ void ifile_close(InputFile **f);
  * caller should flush decoders and read from this demuxer again
  * - a negative error code on failure
  */
-int ifile_get_packet(InputFile *f, AVPacket **pkt);
+int ifile_get_packet(InputFile *f, AVPacket *pkt);
 
 int ist_output_add(InputStream *ist, OutputStream *ost);
 int ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple);
diff --git a/fftools/ffmpeg_demux.c b/fftools/ffmpeg_demux.c
index 

[FFmpeg-devel] [PATCH 17/27] XXX: disable fix_sub_duration_heartbeat

2023-09-19 Thread Anton Khirnov
It conflicts with threading work.
---
 fftools/ffmpeg.c  |  2 ++
 tests/fate/ffmpeg.mak | 24 
 2 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 7d6972f689..e084318864 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -770,6 +770,7 @@ int subtitle_wrap_frame(AVFrame *frame, AVSubtitle 
*subtitle, int copy)
 
 int trigger_fix_sub_duration_heartbeat(OutputStream *ost, const AVPacket *pkt)
 {
+#if 0
 OutputFile *of = output_files[ost->file_index];
 int64_t signal_pts = av_rescale_q(pkt->pts, pkt->time_base,
   AV_TIME_BASE_Q);
@@ -795,6 +796,7 @@ int trigger_fix_sub_duration_heartbeat(OutputStream *ost, 
const AVPacket *pkt)
 if ((ret = fix_sub_duration_heartbeat(ist, signal_pts)) < 0)
 return ret;
 }
+#endif
 
 return 0;
 }
diff --git a/tests/fate/ffmpeg.mak b/tests/fate/ffmpeg.mak
index 835770a924..ebc1e1f189 100644
--- a/tests/fate/ffmpeg.mak
+++ b/tests/fate/ffmpeg.mak
@@ -139,18 +139,18 @@ fate-ffmpeg-fix_sub_duration: CMD = fmtstdout srt 
-fix_sub_duration \
 
 # Basic test for fix_sub_duration_heartbeat, which causes a buffered subtitle
 # to be pushed out when a video keyframe is received from an encoder.
-FATE_SAMPLES_FFMPEG-$(call FILTERDEMDECENCMUX, MOVIE, MPEGVIDEO, \
-   MPEG2VIDEO, SUBRIP, SRT, LAVFI_INDEV  \
-   MPEGVIDEO_PARSER CCAPTION_DECODER \
-   MPEG2VIDEO_ENCODER NULL_MUXER PIPE_PROTOCOL) \
-   += fate-ffmpeg-fix_sub_duration_heartbeat
-fate-ffmpeg-fix_sub_duration_heartbeat: CMD = fmtstdout srt -fix_sub_duration \
-  -real_time 1 -f lavfi \
-  -i "movie=$(TARGET_SAMPLES)/sub/Closedcaption_rollup.m2v[out0+subcc]" \
-  -map 0:v  -map 0:s -fix_sub_duration_heartbeat:v:0 \
-  -c:v mpeg2video -b:v 2M -g 30 -sc_threshold 10 \
-  -c:s srt \
-  -f null -
+#FATE_SAMPLES_FFMPEG-$(call FILTERDEMDECENCMUX, MOVIE, MPEGVIDEO, \
+#   MPEG2VIDEO, SUBRIP, SRT, LAVFI_INDEV  \
+#   MPEGVIDEO_PARSER CCAPTION_DECODER \
+#   MPEG2VIDEO_ENCODER NULL_MUXER PIPE_PROTOCOL) \
+#   += fate-ffmpeg-fix_sub_duration_heartbeat
+#fate-ffmpeg-fix_sub_duration_heartbeat: CMD = fmtstdout srt -fix_sub_duration 
\
+#  -real_time 1 -f lavfi \
+#  -i "movie=$(TARGET_SAMPLES)/sub/Closedcaption_rollup.m2v[out0+subcc]" \
+#  -map 0:v  -map 0:s -fix_sub_duration_heartbeat:v:0 \
+#  -c:v mpeg2video -b:v 2M -g 30 -sc_threshold 10 \
+#  -c:s srt \
+#  -f null -
 
 # FIXME: the integer AAC decoder does not produce the same output on all 
platforms
 # so until that is fixed we use the volume filter to silence the data
-- 
2.40.1

___
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".


[FFmpeg-devel] [PATCH 14/27] fftools/ffmpeg_filter: move filtering to a separate thread

2023-09-19 Thread Anton Khirnov
As previously for decoding, this is merely "scaffolding" for moving to a
fully threaded architecture and does not yet make filtering truly
parallel - the main thread will currently wait for the filtering thread
to finish its work before continuing. That will change in future commits
after encoders are also moved to threads and a thread-aware scheduler is
added.
---
 fftools/ffmpeg.h|   1 -
 fftools/ffmpeg_dec.c|  39 +-
 fftools/ffmpeg_filter.c | 835 ++--
 3 files changed, 733 insertions(+), 142 deletions(-)

diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 0983d026cd..5a8f52ce00 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -735,7 +735,6 @@ FrameData *frame_data(AVFrame *frame);
 
 int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame, int 
keep_reference);
 int ifilter_send_eof(InputFilter *ifilter, int64_t pts, AVRational tb);
-int ifilter_sub2video(InputFilter *ifilter, const AVFrame *frame);
 void ifilter_sub2video_heartbeat(InputFilter *ifilter, int64_t pts, AVRational 
tb);
 
 /**
diff --git a/fftools/ffmpeg_dec.c b/fftools/ffmpeg_dec.c
index 1de8234a97..fb7b404020 100644
--- a/fftools/ffmpeg_dec.c
+++ b/fftools/ffmpeg_dec.c
@@ -146,11 +146,12 @@ fail:
 
 static int send_frame_to_filters(InputStream *ist, AVFrame *decoded_frame)
 {
-int i, ret;
+int i, ret = 0;
 
-av_assert1(ist->nb_filters > 0); /* ensure ret is initialized */
 for (i = 0; i < ist->nb_filters; i++) {
-ret = ifilter_send_frame(ist->filters[i], decoded_frame, i < 
ist->nb_filters - 1);
+ret = ifilter_send_frame(ist->filters[i], decoded_frame,
+ i < ist->nb_filters - 1 ||
+ ist->dec->type == AVMEDIA_TYPE_SUBTITLE);
 if (ret == AVERROR_EOF)
 ret = 0; /* ignore */
 if (ret < 0) {
@@ -379,15 +380,6 @@ static int video_frame_process(InputStream *ist, AVFrame 
*frame)
 return 0;
 }
 
-static void sub2video_flush(InputStream *ist)
-{
-for (int i = 0; i < ist->nb_filters; i++) {
-int ret = ifilter_sub2video(ist->filters[i], NULL);
-if (ret != AVERROR_EOF && ret < 0)
-av_log(NULL, AV_LOG_WARNING, "Flush the frame error.\n");
-}
-}
-
 static int process_subtitle(InputStream *ist, AVFrame *frame)
 {
 Decoder *d = ist->decoder;
@@ -425,14 +417,9 @@ static int process_subtitle(InputStream *ist, AVFrame 
*frame)
 if (!subtitle)
 return 0;
 
-for (int i = 0; i < ist->nb_filters; i++) {
-ret = ifilter_sub2video(ist->filters[i], frame);
-if (ret < 0) {
-av_log(ist, AV_LOG_ERROR, "Error sending a subtitle for filtering: 
%s\n",
-   av_err2str(ret));
-return ret;
-}
-}
+ret = send_frame_to_filters(ist, frame);
+if (ret < 0)
+return ret;
 
 subtitle = (AVSubtitle*)frame->buf[0]->data;
 if (!subtitle->num_rects)
@@ -823,14 +810,10 @@ finish:
 return ret;
 
 // signal EOF to our downstreams
-if (ist->dec->type == AVMEDIA_TYPE_SUBTITLE)
-sub2video_flush(ist);
-else {
-ret = send_filter_eof(ist);
-if (ret < 0) {
-av_log(NULL, AV_LOG_FATAL, "Error marking filters as finished\n");
-return ret;
-}
+ret = send_filter_eof(ist);
+if (ret < 0) {
+av_log(NULL, AV_LOG_FATAL, "Error marking filters as finished\n");
+return ret;
 }
 
 return AVERROR_EOF;
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index b9a4a4e400..cfd13dd81a 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -21,6 +21,7 @@
 #include 
 
 #include "ffmpeg.h"
+#include "thread_queue.h"
 
 #include "libavfilter/avfilter.h"
 #include "libavfilter/buffersink.h"
@@ -41,6 +42,14 @@
 // FIXME private header, used for mid_pred()
 #include "libavcodec/mathops.h"
 
+enum FrameOpaque {
+FRAME_OPAQUE_REAP_FILTERS = 1,
+FRAME_OPAQUE_CHOOSE_INPUT,
+FRAME_OPAQUE_SUB_HEARTBEAT,
+FRAME_OPAQUE_EOF,
+FRAME_OPAQUE_SEND_COMMAND,
+};
+
 typedef struct FilterGraphPriv {
 FilterGraph fg;
 
@@ -53,12 +62,50 @@ typedef struct FilterGraphPriv {
 int is_meta;
 int disable_conversions;
 
+int nb_inputs_bound;
+int nb_outputs_bound;
+
 const char *graph_desc;
 
 // frame for temporarily holding output from the filtergraph
 AVFrame *frame;
 // frame for sending output to the encoder
 AVFrame *frame_enc;
+
+pthread_tthread;
+/**
+ * Queue for sending frames from the main thread to the filtergraph. Has
+ * nb_inputs+1 streams - the first nb_inputs stream correspond to
+ * filtergraph inputs. Frames on those streams may have their opaque set to
+ * - FRAME_OPAQUE_EOF: frame contains no data, but pts+timebase of the
+ *   EOF event for the correspondint stream. Will be immediately followed 
by
+ *   this stream being send-closed.
+ * - 

[FFmpeg-devel] [PATCH 15/27] fftools/ffmpeg_mux: add muxing thread private data

2023-09-19 Thread Anton Khirnov
To be used for data that never needs to be visible outside of the muxer
thread. Start by moving the muxed AVPacket in there.
---
 fftools/ffmpeg_mux.c | 44 +++-
 1 file changed, 35 insertions(+), 9 deletions(-)

diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c
index 7a924dba6c..033894ae86 100644
--- a/fftools/ffmpeg_mux.c
+++ b/fftools/ffmpeg_mux.c
@@ -38,6 +38,10 @@
 #include "libavformat/avformat.h"
 #include "libavformat/avio.h"
 
+typedef struct MuxThreadContext {
+AVPacket *pkt;
+} MuxThreadContext;
+
 int want_sdp = 1;
 
 static Muxer *mux_from_of(OutputFile *of)
@@ -209,18 +213,40 @@ static void thread_set_name(OutputFile *of)
 ff_thread_setname(name);
 }
 
+static void mux_thread_uninit(MuxThreadContext *mt)
+{
+av_packet_free(>pkt);
+
+memset(mt, 0, sizeof(*mt));
+}
+
+static int mux_thread_init(MuxThreadContext *mt)
+{
+memset(mt, 0, sizeof(*mt));
+
+mt->pkt = av_packet_alloc();
+if (!mt->pkt)
+goto fail;
+
+return 0;
+
+fail:
+mux_thread_uninit(mt);
+return AVERROR(ENOMEM);
+}
+
 static void *muxer_thread(void *arg)
 {
 Muxer *mux = arg;
 OutputFile *of = >of;
-AVPacket  *pkt = NULL;
+
+MuxThreadContext mt;
+
 intret = 0;
 
-pkt = av_packet_alloc();
-if (!pkt) {
-ret = AVERROR(ENOMEM);
+ret = mux_thread_init();
+if (ret < 0)
 goto finish;
-}
 
 thread_set_name(of);
 
@@ -228,7 +254,7 @@ static void *muxer_thread(void *arg)
 OutputStream *ost;
 int stream_idx, stream_eof = 0;
 
-ret = tq_receive(mux->tq, _idx, pkt);
+ret = tq_receive(mux->tq, _idx, mt.pkt);
 if (stream_idx < 0) {
 av_log(mux, AV_LOG_VERBOSE, "All streams finished\n");
 ret = 0;
@@ -236,8 +262,8 @@ static void *muxer_thread(void *arg)
 }
 
 ost = of->streams[stream_idx];
-ret = sync_queue_process(mux, ost, ret < 0 ? NULL : pkt, _eof);
-av_packet_unref(pkt);
+ret = sync_queue_process(mux, ost, ret < 0 ? NULL : mt.pkt, 
_eof);
+av_packet_unref(mt.pkt);
 if (ret == AVERROR_EOF) {
 if (stream_eof) {
 tq_receive_finish(mux->tq, stream_idx);
@@ -253,7 +279,7 @@ static void *muxer_thread(void *arg)
 }
 
 finish:
-av_packet_free();
+mux_thread_uninit();
 
 for (unsigned int i = 0; i < mux->fc->nb_streams; i++)
 tq_receive_finish(mux->tq, i);
-- 
2.40.1

___
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".


[FFmpeg-devel] [PATCH 12/27] fftools/ffmpeg_filter: fail on filtering errors

2023-09-19 Thread Anton Khirnov
These should be considered serious errors - don't just print a log
message and continue as if nothing happened.
---
 fftools/ffmpeg_filter.c | 20 ++--
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 92f6a6236d..b9a4a4e400 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -2152,17 +2152,17 @@ static int fg_output_step(OutputFilterPriv *ofp, int 
flush)
 
 ret = av_buffersink_get_frame_flags(filter, frame,
 AV_BUFFERSINK_FLAG_NO_REQUEST);
-if (ret < 0) {
-if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
-av_log(fgp, AV_LOG_WARNING,
-   "Error in av_buffersink_get_frame_flags(): %s\n", 
av_err2str(ret));
-} else if (flush && ret == AVERROR_EOF && ofp->got_frame &&
-   av_buffersink_get_type(filter) == AVMEDIA_TYPE_VIDEO) {
-ret = fg_output_frame(ofp, NULL);
-return (ret < 0) ? ret : 1;
-}
-
+if (flush && ret == AVERROR_EOF && ofp->got_frame &&
+ost->type == AVMEDIA_TYPE_VIDEO) {
+ret = fg_output_frame(ofp, NULL);
+return (ret < 0) ? ret : 1;
+} else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
 return 1;
+} else if (ret < 0) {
+av_log(fgp, AV_LOG_WARNING,
+   "Error in retrieving a frame from the filtergraph: %s\n",
+   av_err2str(ret));
+return ret;
 }
 if (ost->finished) {
 av_frame_unref(frame);
-- 
2.40.1

___
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".


[FFmpeg-devel] [PATCH 13/27] fftools/ffmpeg_enc: constify the frame passed to enc_open()

2023-09-19 Thread Anton Khirnov
---
 fftools/ffmpeg.h | 2 +-
 fftools/ffmpeg_enc.c | 7 +++
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 15790d3e0c..0983d026cd 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -817,7 +817,7 @@ int dec_packet(InputStream *ist, const AVPacket *pkt, int 
no_eof);
 int enc_alloc(Encoder **penc, const AVCodec *codec);
 void enc_free(Encoder **penc);
 
-int enc_open(OutputStream *ost, AVFrame *frame);
+int enc_open(OutputStream *ost, const AVFrame *frame);
 int enc_subtitle(OutputFile *of, OutputStream *ost, const AVSubtitle *sub);
 int enc_frame(OutputStream *ost, AVFrame *frame);
 int enc_flush(void);
diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c
index 321554ab5c..c300a11f28 100644
--- a/fftools/ffmpeg_enc.c
+++ b/fftools/ffmpeg_enc.c
@@ -165,7 +165,7 @@ static int set_encoder_id(OutputFile *of, OutputStream *ost)
 return 0;
 }
 
-int enc_open(OutputStream *ost, AVFrame *frame)
+int enc_open(OutputStream *ost, const AVFrame *frame)
 {
 InputStream *ist = ost->ist;
 Encoder  *e = ost->enc;
@@ -183,9 +183,8 @@ int enc_open(OutputStream *ost, AVFrame *frame)
 av_assert0(frame || (enc->type != AVMEDIA_TYPE_VIDEO && enc->type != 
AVMEDIA_TYPE_AUDIO));
 
 if (frame) {
-fd = frame_data(frame);
-if (!fd)
-return AVERROR(ENOMEM);
+av_assert0(frame->opaque_ref);
+fd = (FrameData*)frame->opaque_ref->data;
 }
 
 ret = set_encoder_id(output_files[ost->file_index], ost);
-- 
2.40.1

___
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".


[FFmpeg-devel] [PATCH 11/27] fftools/ffmpeg_enc: move fps conversion code to ffmpeg_filter

2023-09-19 Thread Anton Khirnov
Its function is analogous to that of the fps filter, so filtering is a
more appropriate place for this.

The main practical reason for this move is that it places the encoding
sync queue right at the boundary between filters and encoders. This will
be important when switching to threaded scheduling, as the sync queue
involves multiple streams and will thus need to do nontrivial
inter-thread synchronization.

In addition to framerate conversion, the closely-related
* encoder timebase selection
* applying the start_time offset
are also moved to filtering.
---
 fftools/ffmpeg.c|   6 +-
 fftools/ffmpeg.h|   7 +-
 fftools/ffmpeg_enc.c| 370 +++---
 fftools/ffmpeg_filter.c | 432 ++--
 4 files changed, 442 insertions(+), 373 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index a854589bef..7c33b56cd3 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -536,7 +536,7 @@ static void print_report(int is_last_report, int64_t 
timer_start, int64_t cur_ti
 av_bprintf(_script, "stream_%d_%d_q=%.1f\n",
ost->file_index, ost->index, q);
 }
-if (!vid && ost->type == AVMEDIA_TYPE_VIDEO) {
+if (!vid && ost->type == AVMEDIA_TYPE_VIDEO && ost->filter) {
 float fps;
 uint64_t frame_number = atomic_load(>packets_written);
 
@@ -550,8 +550,8 @@ static void print_report(int is_last_report, int64_t 
timer_start, int64_t cur_ti
 if (is_last_report)
 av_bprintf(, "L");
 
-nb_frames_dup  = ost->nb_frames_dup;
-nb_frames_drop = ost->nb_frames_drop;
+nb_frames_dup  = ost->filter->nb_frames_dup;
+nb_frames_drop = ost->filter->nb_frames_drop;
 
 vid = 1;
 }
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index eaa663e718..15790d3e0c 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -302,6 +302,9 @@ typedef struct OutputFilter {
 
 /* pts of the last frame received from this filter, in AV_TIME_BASE_Q */
 int64_t last_pts;
+
+uint64_t nb_frames_dup;
+uint64_t nb_frames_drop;
 } OutputFilter;
 
 typedef struct FilterGraph {
@@ -536,10 +539,6 @@ typedef struct OutputStream {
 Encoder *enc;
 AVCodecContext *enc_ctx;
 
-uint64_t nb_frames_dup;
-uint64_t nb_frames_drop;
-int64_t last_dropped;
-
 /* video only */
 AVRational frame_rate;
 AVRational max_frame_rate;
diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c
index 9aee18bfe1..321554ab5c 100644
--- a/fftools/ffmpeg_enc.c
+++ b/fftools/ffmpeg_enc.c
@@ -36,29 +36,9 @@
 
 #include "libavcodec/avcodec.h"
 
-// FIXME private header, used for mid_pred()
-#include "libavcodec/mathops.h"
-
 #include "libavformat/avformat.h"
 
-typedef struct FPSConvContext {
-AVFrame *last_frame;
-/* number of frames emitted by the video-encoding sync code */
-int64_t frame_number;
-/* history of nb_frames_prev, i.e. the number of times the
- * previous frame was duplicated by vsync code in recent
- * do_video_out() calls */
-int64_t frames_prev_hist[3];
-
-uint64_t dup_warning;
-} FPSConvContext;
-
 struct Encoder {
-/* predicted pts of the next frame to be encoded */
-int64_t next_pts;
-
-FPSConvContext fps;
-
 AVFrame *sq_frame;
 
 // packet for receiving encoded output
@@ -80,7 +60,6 @@ void enc_free(Encoder **penc)
 if (!enc)
 return;
 
-av_frame_free(>fps.last_frame);
 av_frame_free(>sq_frame);
 
 av_packet_free(>pkt);
@@ -98,14 +77,6 @@ int enc_alloc(Encoder **penc, const AVCodec *codec)
 if (!enc)
 return AVERROR(ENOMEM);
 
-if (codec->type == AVMEDIA_TYPE_VIDEO) {
-enc->fps.last_frame = av_frame_alloc();
-if (!enc->fps.last_frame)
-goto fail;
-
-enc->fps.dup_warning = 1000;
-}
-
 enc->pkt = av_packet_alloc();
 if (!enc->pkt)
 goto fail;
@@ -194,98 +165,6 @@ static int set_encoder_id(OutputFile *of, OutputStream 
*ost)
 return 0;
 }
 
-static int enc_choose_timebase(OutputStream *ost, AVFrame *frame)
-{
-const OutputFile *of = output_files[ost->file_index];
-AVCodecContext  *enc = ost->enc_ctx;
-AVRationaltb = (AVRational){ 0, 0 };
-AVRational fr;
-FrameData *fd;
-
-if (ost->type == AVMEDIA_TYPE_SUBTITLE) {
-if (ost->enc_timebase.num)
-av_log(ost, AV_LOG_WARNING,
-   "-enc_time_base not supported for subtitles, ignoring\n");
-enc->time_base = AV_TIME_BASE_Q;
-return 0;
-}
-
-fd = frame_data(frame);
-
-// apply -enc_time_base
-if (ost->enc_timebase.num == ENC_TIME_BASE_DEMUX &&
-(fd->dec.tb.num <= 0 || fd->dec.tb.den <= 0)) {
-av_log(ost, AV_LOG_ERROR,
-   "Demuxing timebase not available - cannot use it for 
encoding\n");
-return AVERROR(EINVAL);
-}
-
-switch (ost->enc_timebase.num) 

[FFmpeg-devel] [PATCH 10/27] fftools/ffmpeg_enc: move framerate conversion state into a separate struct

2023-09-19 Thread Anton Khirnov
Makes it more clear what state is specific to framerate conversion,
which will be useful in the following commit.
---
 fftools/ffmpeg_enc.c | 65 
 1 file changed, 35 insertions(+), 30 deletions(-)

diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c
index 2250d22bd3..9aee18bfe1 100644
--- a/fftools/ffmpeg_enc.c
+++ b/fftools/ffmpeg_enc.c
@@ -41,18 +41,24 @@
 
 #include "libavformat/avformat.h"
 
-struct Encoder {
-/* predicted pts of the next frame to be encoded */
-int64_t next_pts;
-
+typedef struct FPSConvContext {
 AVFrame *last_frame;
 /* number of frames emitted by the video-encoding sync code */
-int64_t vsync_frame_number;
+int64_t frame_number;
 /* history of nb_frames_prev, i.e. the number of times the
  * previous frame was duplicated by vsync code in recent
  * do_video_out() calls */
 int64_t frames_prev_hist[3];
 
+uint64_t dup_warning;
+} FPSConvContext;
+
+struct Encoder {
+/* predicted pts of the next frame to be encoded */
+int64_t next_pts;
+
+FPSConvContext fps;
+
 AVFrame *sq_frame;
 
 // packet for receiving encoded output
@@ -64,8 +70,6 @@ struct Encoder {
 // number of packets received from the encoder
 uint64_t packets_encoded;
 
-uint64_t dup_warning;
-
 int opened;
 };
 
@@ -76,7 +80,7 @@ void enc_free(Encoder **penc)
 if (!enc)
 return;
 
-av_frame_free(>last_frame);
+av_frame_free(>fps.last_frame);
 av_frame_free(>sq_frame);
 
 av_packet_free(>pkt);
@@ -95,17 +99,17 @@ int enc_alloc(Encoder **penc, const AVCodec *codec)
 return AVERROR(ENOMEM);
 
 if (codec->type == AVMEDIA_TYPE_VIDEO) {
-enc->last_frame = av_frame_alloc();
-if (!enc->last_frame)
+enc->fps.last_frame = av_frame_alloc();
+if (!enc->fps.last_frame)
 goto fail;
+
+enc->fps.dup_warning = 1000;
 }
 
 enc->pkt = av_packet_alloc();
 if (!enc->pkt)
 goto fail;
 
-enc->dup_warning = 1000;
-
 *penc = enc;
 
 return 0;
@@ -966,13 +970,14 @@ static void video_sync_process(OutputFile *of, 
OutputStream *ost, AVFrame *frame
int64_t *nb_frames, int64_t *nb_frames_prev)
 {
 Encoder *e = ost->enc;
+FPSConvContext *fps = >fps;
 AVCodecContext *enc = ost->enc_ctx;
 double delta0, delta, sync_ipts, duration;
 
 if (!frame) {
-*nb_frames_prev = *nb_frames = mid_pred(e->frames_prev_hist[0],
-e->frames_prev_hist[1],
-e->frames_prev_hist[2]);
+*nb_frames_prev = *nb_frames = mid_pred(fps->frames_prev_hist[0],
+fps->frames_prev_hist[1],
+fps->frames_prev_hist[2]);
 goto finish;
 }
 
@@ -1006,7 +1011,7 @@ static void video_sync_process(OutputFile *of, 
OutputStream *ost, AVFrame *frame
 
 switch (ost->vsync_method) {
 case VSYNC_VSCFR:
-if (e->vsync_frame_number == 0 && delta0 >= 0.5) {
+if (fps->frame_number == 0 && delta0 >= 0.5) {
 av_log(ost, AV_LOG_DEBUG, "Not duplicating %d initial frames\n", 
(int)lrintf(delta0));
 delta = duration;
 delta0 = 0;
@@ -1014,7 +1019,7 @@ static void video_sync_process(OutputFile *of, 
OutputStream *ost, AVFrame *frame
 }
 case VSYNC_CFR:
 // FIXME set to 0.5 after we fix some dts/pts bugs like in avidec.c
-if (frame_drop_threshold && delta < frame_drop_threshold && 
e->vsync_frame_number) {
+if (frame_drop_threshold && delta < frame_drop_threshold && 
fps->frame_number) {
 *nb_frames = 0;
 } else if (delta < -1.1)
 *nb_frames = 0;
@@ -1042,16 +1047,16 @@ static void video_sync_process(OutputFile *of, 
OutputStream *ost, AVFrame *frame
 }
 
 finish:
-memmove(e->frames_prev_hist + 1,
-e->frames_prev_hist,
-sizeof(e->frames_prev_hist[0]) * 
(FF_ARRAY_ELEMS(e->frames_prev_hist) - 1));
-e->frames_prev_hist[0] = *nb_frames_prev;
+memmove(fps->frames_prev_hist + 1,
+fps->frames_prev_hist,
+sizeof(fps->frames_prev_hist[0]) * 
(FF_ARRAY_ELEMS(fps->frames_prev_hist) - 1));
+fps->frames_prev_hist[0] = *nb_frames_prev;
 
 if (*nb_frames_prev == 0 && ost->last_dropped) {
 ost->nb_frames_drop++;
 av_log(ost, AV_LOG_VERBOSE,
"*** dropping frame %"PRId64" at ts %"PRId64"\n",
-   e->vsync_frame_number, e->last_frame->pts);
+   fps->frame_number, fps->last_frame->pts);
 }
 if (*nb_frames > (*nb_frames_prev && ost->last_dropped) + (*nb_frames > 
*nb_frames_prev)) {
 if (*nb_frames > dts_error_threshold * 30) {
@@ -1062,9 +1067,9 @@ finish:
 }
 ost->nb_frames_dup += *nb_frames - (*nb_frames_prev && 
ost->last_dropped) - 

[FFmpeg-devel] [PATCH 08/27] fftools/ffmpeg_enc: merge -force_key_frames source/source_no_drop

2023-09-19 Thread Anton Khirnov
Always use the functionality of the latter, which makes more sense as it
avoids losing keyframes due to vsync code dropping frames.

Deprecate the 'source_no_drop' value, as it is now redundant.
---
 doc/ffmpeg.texi |  5 -
 fftools/ffmpeg.h|  3 +++
 fftools/ffmpeg_enc.c|  5 +
 fftools/ffmpeg_mux_init.c   |  6 +-
 tests/ref/fate/force_key_frames-source-drop | 22 ++---
 5 files changed, 20 insertions(+), 21 deletions(-)

diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
index d2864ff37e..ea473e14e8 100644
--- a/doc/ffmpeg.texi
+++ b/doc/ffmpeg.texi
@@ -1060,7 +1060,6 @@ Deprecated see -bsf
 @item -force_key_frames[:@var{stream_specifier}] @var{time}[,@var{time}...] 
(@emph{output,per-stream})
 @item -force_key_frames[:@var{stream_specifier}] expr:@var{expr} 
(@emph{output,per-stream})
 @item -force_key_frames[:@var{stream_specifier}] source 
(@emph{output,per-stream})
-@item -force_key_frames[:@var{stream_specifier}] source_no_drop 
(@emph{output,per-stream})
 
 @var{force_key_frames} can take arguments of the following form:
 
@@ -1121,10 +1120,6 @@ starting from second 13:
 @item source
 If the argument is @code{source}, ffmpeg will force a key frame if
 the current frame being encoded is marked as a key frame in its source.
-
-@item source_no_drop
-If the argument is @code{source_no_drop}, ffmpeg will force a key frame if
-the current frame being encoded is marked as a key frame in its source.
 In cases where this particular source frame has to be dropped,
 enforce the next available frame to become a key frame instead.
 
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 2e8f1db9b6..eaa663e718 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -58,6 +58,7 @@
 #define FFMPEG_OPT_ADRIFT_THRESHOLD 1
 #define FFMPEG_OPT_ENC_TIME_BASE_NUM 1
 #define FFMPEG_OPT_TOP 1
+#define FFMPEG_OPT_FORCE_KF_SOURCE_NO_DROP 1
 
 enum VideoSyncMethod {
 VSYNC_AUTO = -1,
@@ -484,7 +485,9 @@ typedef enum {
 
 enum {
 KF_FORCE_SOURCE = 1,
+#if FFMPEG_OPT_FORCE_KF_SOURCE_NO_DROP
 KF_FORCE_SOURCE_NO_DROP = 2,
+#endif
 };
 
 typedef struct KeyframeForceCtx {
diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c
index 1db67d1497..0ad3a7b6b1 100644
--- a/fftools/ffmpeg_enc.c
+++ b/fftools/ffmpeg_enc.c
@@ -1105,10 +1105,7 @@ static enum AVPictureType forced_kf_apply(void *logctx, 
KeyframeForceCtx *kf,
 kf->expr_const_values[FKF_N_FORCED] += 1;
 goto force_keyframe;
 }
-} else if (kf->type == KF_FORCE_SOURCE &&
-   (in_picture->flags & AV_FRAME_FLAG_KEY) && !dup_idx) {
-goto force_keyframe;
-} else if (kf->type == KF_FORCE_SOURCE_NO_DROP && !dup_idx) {
+} else if (kf->type == KF_FORCE_SOURCE && !dup_idx) {
 int dropped_keyframe = kf->dropped_keyframe;
 kf->dropped_keyframe = 0;
 if ((in_picture->flags & AV_FRAME_FLAG_KEY) || dropped_keyframe)
diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c
index 9d6f442068..f35680e355 100644
--- a/fftools/ffmpeg_mux_init.c
+++ b/fftools/ffmpeg_mux_init.c
@@ -2509,8 +2509,12 @@ static int process_forced_keyframes(Muxer *mux, const 
OptionsContext *o)
 // parse it only for static kf timings
 } else if (!strcmp(forced_keyframes, "source")) {
 ost->kf.type = KF_FORCE_SOURCE;
+#if FFMPEG_OPT_FORCE_KF_SOURCE_NO_DROP
 } else if (!strcmp(forced_keyframes, "source_no_drop")) {
-ost->kf.type = KF_FORCE_SOURCE_NO_DROP;
+av_log(ost, AV_LOG_WARNING, "The 'source_no_drop' value for "
+   "-force_key_frames is deprecated, use just 'source'\n");
+ost->kf.type = KF_FORCE_SOURCE;
+#endif
 } else {
 int ret = parse_forced_key_frames(ost, >kf, mux, 
forced_keyframes);
 if (ret < 0)
diff --git a/tests/ref/fate/force_key_frames-source-drop 
b/tests/ref/fate/force_key_frames-source-drop
index 99aa2ae826..220c0f0f88 100644
--- a/tests/ref/fate/force_key_frames-source-drop
+++ b/tests/ref/fate/force_key_frames-source-drop
@@ -9,14 +9,14 @@
 0,  2,  3,1,   24, 0x589c06e0, F=0x0, S=1,8
 0,  3,  4,1,   24, 0x4a700621, F=0x0, S=1,8
 0,  4,  5,1,   24, 0x4f300661, F=0x0, S=1,8
-0,  5,  6,1,   24, 0x53f006a1, F=0x0, S=1,8
-0,  6,  7,1,   24, 0x58b006e1, F=0x0, S=1,8
-0,  7,  8,1,   24, 0x4a840622, F=0x0, S=1,8
-0,  8,  9,1,   24, 0x4f440662, F=0x0, S=1,8
-0,  9, 10,1,   24, 0x540406a2, F=0x0, S=1,8
-0, 10, 11,1,   24, 0x58c406e2, F=0x0, S=1,8
-0, 11, 12,1,   24, 0x4a980623, F=0x0, S=1,8
-0,   

[FFmpeg-devel] [PATCH 09/27] fftools/ffmpeg: stop accessing OutputStream.last_dropped in print_report()

2023-09-19 Thread Anton Khirnov
That field is used by the framerate code to track whether any output has
been generated for the last input frame(*). Its use in the last
invocation of print_report() is meant to meant to account (in the number
of dropped frames printed in the log) for the very last filtered frame
being dropped. However, that is a highly inappropriate place to do so,
as it makes assumptions about vsync logic in completely unrelated code.
Move the increment to encoder flush instead.

(*) the name is misleading, as the input frame has not yet been dropped
and may still be output in the future
---
 fftools/ffmpeg.c | 3 ---
 fftools/ffmpeg_enc.c | 3 +++
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 14f55cbec7..a854589bef 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -566,9 +566,6 @@ static void print_report(int is_last_report, int64_t 
timer_start, int64_t cur_ti
 pts -= copy_ts_first_pts;
 }
 }
-
-if (is_last_report)
-nb_frames_drop += ost->last_dropped;
 }
 
 us= FFABS64U(pts) % AV_TIME_BASE;
diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c
index 0ad3a7b6b1..2250d22bd3 100644
--- a/fftools/ffmpeg_enc.c
+++ b/fftools/ffmpeg_enc.c
@@ -761,6 +761,9 @@ static int encode_frame(OutputFile *of, OutputStream *ost, 
AVFrame *frame)
 
 if (frame->sample_aspect_ratio.num && !ost->frame_aspect_ratio.num)
 enc->sample_aspect_ratio = frame->sample_aspect_ratio;
+} else if (ost->last_dropped) {
+ost->nb_frames_drop++;
+ost->last_dropped = 0;
 }
 
 update_benchmark(NULL);
-- 
2.40.1

___
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".


[FFmpeg-devel] [PATCH 06/27] tests/fate/ffmpeg: add tests for -force_key_frames source

2023-09-19 Thread Anton Khirnov
---
 tests/fate/ffmpeg.mak   |  20 +
 tests/ref/fate/force_key_frames-source  | 397 +
 tests/ref/fate/force_key_frames-source-drop |  22 +
 tests/ref/fate/force_key_frames-source-dup  | 617 
 4 files changed, 1056 insertions(+)
 create mode 100644 tests/ref/fate/force_key_frames-source
 create mode 100644 tests/ref/fate/force_key_frames-source-drop
 create mode 100644 tests/ref/fate/force_key_frames-source-dup

diff --git a/tests/fate/ffmpeg.mak b/tests/fate/ffmpeg.mak
index 04500d53a0..835770a924 100644
--- a/tests/fate/ffmpeg.mak
+++ b/tests/fate/ffmpeg.mak
@@ -48,6 +48,26 @@ fate-force_key_frames: CMD = enc_dec \
   avi "-c mpeg4 -g 240 -qscale 10 -force_key_frames 0.5,0:00:01.5" \
   framecrc "" "-skip_frame nokey"
 
+# test -force_key_frames source with and without framerate conversion
+# * we don't care about the actual video content, so replace it with
+#   a 2x2 black square to speed up encoding
+# * force mpeg2video to only emit keyframes when explicitly requested
+fate-force_key_frames-source: CMD = framecrc -i 
$(TARGET_SAMPLES)/h264/intra_refresh.h264 \
+  -vf crop=2:2,drawbox=color=black:t=fill\
+  -c:v mpeg2video -g 400 -sc_threshold 9 \
+  -force_key_frames source
+fate-force_key_frames-source-drop: CMD = framecrc -i 
$(TARGET_SAMPLES)/h264/intra_refresh.h264 \
+  -vf crop=2:2,drawbox=color=black:t=fill\
+  -c:v mpeg2video -g 400 -sc_threshold 9 \
+  -force_key_frames source -r 1
+fate-force_key_frames-source-dup: CMD = framecrc -i 
$(TARGET_SAMPLES)/h264/intra_refresh.h264 \
+  -vf crop=2:2,drawbox=color=black:t=fill\
+  -c:v mpeg2video -g 400 -sc_threshold 9 \
+  -force_key_frames source -r 39 -force_fps -strict experimental
+
+FATE_SAMPLES_FFMPEG-$(call ENCDEC, MPEG2VIDEO H264, FRAMECRC H264, CROP_FILTER 
DRAWBOX_FILTER) += \
+fate-force_key_frames-source fate-force_key_frames-source-drop 
fate-force_key_frames-source-dup
+
 # Tests that the video is properly autorotated using the contained
 # display matrix and that the generated file does not contain
 # a display matrix any more.
diff --git a/tests/ref/fate/force_key_frames-source 
b/tests/ref/fate/force_key_frames-source
new file mode 100644
index 00..87a35e2d2c
--- /dev/null
+++ b/tests/ref/fate/force_key_frames-source
@@ -0,0 +1,397 @@
+#tb 0: 1/25
+#media_type 0: video
+#codec_id 0: mpeg2video
+#dimensions 0: 2x2
+#sar 0: 0/1
+0, -1,  0,1,   57, 0x7db00eb7, S=1,8
+0,  0,  1,1,   24, 0x4f1c0660, F=0x0, S=1,8
+0,  1,  2,1,   24, 0x53dc06a0, F=0x0, S=1,8
+0,  2,  3,1,   24, 0x589c06e0, F=0x0, S=1,8
+0,  3,  4,1,   24, 0x4a700621, F=0x0, S=1,8
+0,  4,  5,1,   24, 0x4f300661, F=0x0, S=1,8
+0,  5,  6,1,   24, 0x53f006a1, F=0x0, S=1,8
+0,  6,  7,1,   24, 0x58b006e1, F=0x0, S=1,8
+0,  7,  8,1,   24, 0x4a840622, F=0x0, S=1,8
+0,  8,  9,1,   24, 0x4f440662, F=0x0, S=1,8
+0,  9, 10,1,   24, 0x540406a2, F=0x0, S=1,8
+0, 10, 11,1,   24, 0x58c406e2, F=0x0, S=1,8
+0, 11, 12,1,   24, 0x4a980623, F=0x0, S=1,8
+0, 12, 13,1,   24, 0x4f580663, F=0x0, S=1,8
+0, 13, 14,1,   24, 0x541806a3, F=0x0, S=1,8
+0, 14, 15,1,   24, 0x58d806e3, F=0x0, S=1,8
+0, 15, 16,1,   24, 0x4aac0624, F=0x0, S=1,8
+0, 16, 17,1,   24, 0x4f6c0664, F=0x0, S=1,8
+0, 17, 18,1,   24, 0x542c06a4, F=0x0, S=1,8
+0, 18, 19,1,   24, 0x58ec06e4, F=0x0, S=1,8
+0, 19, 20,1,   24, 0x4ac00625, F=0x0, S=1,8
+0, 20, 21,1,   24, 0x4f800665, F=0x0, S=1,8
+0, 21, 22,1,   24, 0x544006a5, F=0x0, S=1,8
+0, 22, 23,1,   24, 0x590006e5, F=0x0, S=1,8
+0, 23, 24,1,   24, 0x4ad40626, F=0x0, S=1,8
+0, 24, 25,1,   24, 0x4f940666, F=0x0, S=1,8
+0, 25, 26,1,   24, 0x545406a6, F=0x0, S=1,8
+0, 26, 27,1,   24, 0x591406e6, F=0x0, S=1,8
+0, 27, 28,1,   24, 0x4ae80627, F=0x0, S=1,8
+0, 28, 29,1,   24, 0x4fa80667, F=0x0, S=1,8
+0, 29, 30,1,   24, 0x546806a7, F=0x0, S=1,8
+0, 30, 31,1,   24, 0x592806e7, 

[FFmpeg-devel] [PATCH 07/27] fftools/ffmpeg_enc: unbreak -force_key_frames source_no_drop

2023-09-19 Thread Anton Khirnov
Unlike the 'source' mode, which preserves source keyframe-marking as-is,
the 'source_no_drop' mode attempts to keep track of keyframes dropped by
framerate conversion and mark the next output frame as key in such
cases. However,
* c75be061487 broke this functionality entirely, and made it equivalent
  to 'source'
* even before it would only work when the frame immediately following
  the dropped keyframe is preserved and not dropped as well

Also, drop a redundant check for 'frame' in setting dropped_keyframe, as
it is redundant with the check on the above line.
---
 fftools/ffmpeg_enc.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c
index df79eaff59..1db67d1497 100644
--- a/fftools/ffmpeg_enc.c
+++ b/fftools/ffmpeg_enc.c
@@ -1066,7 +1066,7 @@ finish:
 }
 
 ost->last_dropped = *nb_frames == *nb_frames_prev && frame;
-ost->kf.dropped_keyframe = ost->last_dropped && frame && (frame->flags & 
AV_FRAME_FLAG_KEY);
+ost->kf.dropped_keyframe |= ost->last_dropped && (frame->flags & 
AV_FRAME_FLAG_KEY);
 }
 
 static enum AVPictureType forced_kf_apply(void *logctx, KeyframeForceCtx *kf,
@@ -1109,8 +1109,9 @@ static enum AVPictureType forced_kf_apply(void *logctx, 
KeyframeForceCtx *kf,
(in_picture->flags & AV_FRAME_FLAG_KEY) && !dup_idx) {
 goto force_keyframe;
 } else if (kf->type == KF_FORCE_SOURCE_NO_DROP && !dup_idx) {
+int dropped_keyframe = kf->dropped_keyframe;
 kf->dropped_keyframe = 0;
-if ((in_picture->flags & AV_FRAME_FLAG_KEY) || kf->dropped_keyframe)
+if ((in_picture->flags & AV_FRAME_FLAG_KEY) || dropped_keyframe)
 goto force_keyframe;
 }
 
-- 
2.40.1

___
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".


[FFmpeg-devel] [PATCH 05/27] ffools/ffmpeg_filter: stop trying to handle an unreachable state

2023-09-19 Thread Anton Khirnov
ifilter_send_eof() will fail if the input has no real or fallback
parameters, so there is no need to handle the case of some inputs being
in EOF state yet having no parameters.
---
 fftools/ffmpeg.c|  2 +-
 fftools/ffmpeg.h|  2 --
 fftools/ffmpeg_filter.c | 10 +-
 3 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index fd2ce1c2d0..14f55cbec7 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -944,7 +944,7 @@ static int choose_output(OutputStream **post)
INT64_MIN : ost->last_mux_dts;
 }
 
-if (!ost->initialized && !ost->inputs_done && !ost->finished) {
+if (!ost->initialized && !ost->finished) {
 ost_min = ost;
 break;
 }
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index b059ecbb9f..2e8f1db9b6 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -583,8 +583,6 @@ typedef struct OutputStream {
 // parameters are set in the AVStream.
 int initialized;
 
-int inputs_done;
-
 const char *attachment_filename;
 
 int keep_pix_fmt;
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index b6348d7f87..804b9de3dc 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -2076,11 +2076,11 @@ int fg_transcode_step(FilterGraph *graph, InputStream 
**best_ist)
 }
 }
 
-// graph not configured, but all inputs are either initialized or EOF
-for (int i = 0; i < graph->nb_outputs; i++)
-graph->outputs[i]->ost->inputs_done = 1;
-
-return 0;
+// This state - graph is not configured, but all inputs are either
+// initialized or EOF - should be unreachable because sending EOF to a
+// filter without even a fallback format should fail
+av_assert0(0);
+return AVERROR_BUG;
 }
 
 *best_ist = NULL;
-- 
2.40.1

___
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".


[FFmpeg-devel] [PATCH 04/27] fftools/ffmpeg_enc: simplify adjust_frame_pts_to_encoder_tb() signature

2023-09-19 Thread Anton Khirnov
It does not need an OutputFile and an OutputStream, only the target
timebase and the timestamp offset.
---
 fftools/ffmpeg_enc.c | 25 ++---
 1 file changed, 10 insertions(+), 15 deletions(-)

diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c
index 420fe96c97..df79eaff59 100644
--- a/fftools/ffmpeg_enc.c
+++ b/fftools/ffmpeg_enc.c
@@ -917,16 +917,12 @@ static int do_audio_out(OutputFile *of, OutputStream *ost,
 return (ret < 0 && ret != AVERROR_EOF) ? ret : 0;
 }
 
-static double adjust_frame_pts_to_encoder_tb(OutputFile *of, OutputStream *ost,
- AVFrame *frame)
+static double adjust_frame_pts_to_encoder_tb(AVFrame *frame, AVRational tb_dst,
+ int64_t start_time)
 {
 double float_pts = AV_NOPTS_VALUE; // this is identical to frame.pts but 
with higher precision
-const int64_t start_time = (of->start_time == AV_NOPTS_VALUE) ?
-   0 : of->start_time;
 
-AVCodecContext *const enc = ost->enc_ctx;
-
-AVRationaltb = enc->time_base;
+AVRationaltb = tb_dst;
 AVRational filter_tb = frame->time_base;
 const int extra_bits = av_clip(29 - av_log2(tb.den), 0, 16);
 
@@ -943,19 +939,17 @@ static double adjust_frame_pts_to_encoder_tb(OutputFile 
*of, OutputStream *ost,
 if (float_pts != llrint(float_pts))
 float_pts += FFSIGN(float_pts) * 1.0 / (1<<17);
 
-frame->pts = av_rescale_q(frame->pts, filter_tb, enc->time_base) -
- av_rescale_q(start_time, AV_TIME_BASE_Q, enc->time_base);
-frame->time_base = enc->time_base;
+frame->pts = av_rescale_q(frame->pts, filter_tb, tb_dst) -
+ av_rescale_q(start_time, AV_TIME_BASE_Q, tb_dst);
+frame->time_base = tb_dst;
 
 early_exit:
 
 if (debug_ts) {
 av_log(NULL, AV_LOG_INFO, "filter -> pts:%s pts_time:%s exact:%f 
time_base:%d/%d\n",
frame ? av_ts2str(frame->pts) : "NULL",
-   (enc && frame) ? av_ts2timestr(frame->pts, >time_base) : 
"NULL",
-   float_pts,
-   enc ? enc->time_base.num : -1,
-   enc ? enc->time_base.den : -1);
+   av_ts2timestr(frame->pts, _dst),
+   float_pts, tb_dst.num, tb_dst.den);
 }
 
 return float_pts;
@@ -981,7 +975,8 @@ static void video_sync_process(OutputFile *of, OutputStream 
*ost, AVFrame *frame
 
 duration = lrintf(frame->duration * av_q2d(frame->time_base) / 
av_q2d(enc->time_base));
 
-sync_ipts = adjust_frame_pts_to_encoder_tb(of, ost, frame);
+sync_ipts = adjust_frame_pts_to_encoder_tb(frame, enc->time_base,
+   of->start_time == 
AV_NOPTS_VALUE ? 0 : of->start_time);
 /* delta0 is the "drift" between the input frame and
  * where it would fall in the output. */
 delta0 = sync_ipts - e->next_pts;
-- 
2.40.1

___
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".


[FFmpeg-devel] [PATCH 02/27] fftools/ffmpeg_enc: move handling video frame duration to video_sync_process()

2023-09-19 Thread Anton Khirnov
That is a more appropriate place for this.
---
 fftools/ffmpeg_enc.c | 14 ++
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c
index 9b8b3e0226..9aa00f682c 100644
--- a/fftools/ffmpeg_enc.c
+++ b/fftools/ffmpeg_enc.c
@@ -965,12 +965,12 @@ early_exit:
  * should this (and possibly previous) frame be repeated in order to conform to
  * desired target framerate (if any).
  */
-static void video_sync_process(OutputFile *of, OutputStream *ost,
-   AVFrame *frame, double duration,
+static void video_sync_process(OutputFile *of, OutputStream *ost, AVFrame 
*frame,
int64_t *nb_frames, int64_t *nb_frames_prev)
 {
 Encoder *e = ost->enc;
-double delta0, delta, sync_ipts;
+AVCodecContext *enc = ost->enc_ctx;
+double delta0, delta, sync_ipts, duration;
 
 if (!frame) {
 *nb_frames_prev = *nb_frames = mid_pred(e->frames_prev_hist[0],
@@ -979,6 +979,8 @@ static void video_sync_process(OutputFile *of, OutputStream 
*ost,
 goto finish;
 }
 
+duration = lrintf(frame->duration * av_q2d(frame->time_base) / 
av_q2d(enc->time_base));
+
 sync_ipts = adjust_frame_pts_to_encoder_tb(of, ost, frame);
 /* delta0 is the "drift" between the input frame and
  * where it would fall in the output. */
@@ -1107,12 +1109,8 @@ static int do_video_out(OutputFile *of, OutputStream 
*ost, AVFrame *frame)
 Encoder *e = ost->enc;
 AVCodecContext *enc = ost->enc_ctx;
 int64_t nb_frames, nb_frames_prev, i;
-double duration = 0;
 
-if (frame)
-duration = lrintf(frame->duration * av_q2d(frame->time_base) / 
av_q2d(enc->time_base));
-
-video_sync_process(of, ost, frame, duration,
+video_sync_process(of, ost, frame,
_frames, _frames_prev);
 
 if (nb_frames_prev == 0 && ost->last_dropped) {
-- 
2.40.1

___
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".


[FFmpeg-devel] [RFC/PATCH] ffmpeg CLI multithreading

2023-09-19 Thread Anton Khirnov
Hi,
as some of you might know, I have been working on multithreading for the
ffmpeg CLI (as opposed to the libraries) for quite a while now. That
work is now finally entering the vicinity of being usable, so I've
decided to air it on the ML for comments on the big picture.

Do note that many things still do not work at all, notably
* subtitles
* bitstream filters
* streamloop
* filtergraphs with no inputs
Many others are probably broken to a larger or smaller extent.

I can, however, get some interesting results - e.g. significant
wallclock speedup in cases where singlethreaded codecs/filters can now
be run in parallel. I am also seeing 10-20% overall clock cycle increase
in my tests - for now that is a known bug that will hopefully be
addressed later.

One of the main themes of this work is separating various bits of
functionality in the code - that typically grew organically over years
(often in rather random places) - into clearly defined objects with
clearly defined responsibilities. At the core of the new world order is
the new scheduler object, living in ffmpeg_sched.[ch]. It handles all
interactions between the various ffmpeg components, inter-thread
synchronization, etc., so the individual components themselves do not
need to know anything about threading/synchronization/the rest of the
transcoding pipeline.

The patches are roughly grouped as follows:
* 01-13 Preparatory cleanup.
  The big thing here is moving fps conversion from video encoding to
  filtering (see commit message for 20/27 for details)
* 14-20 "Fake" threading for encoders/filters.
  This moves the last two unthreaded components - encoders and filters -
  into threads. As previously for decoders, this is merely preparatory,
  since the main thread waits while the encoder/filter thread does its
  work. The filter patch is unfortunately especially large, because
  filtering has multiple entrypoints and they all need to be wrapped and
  unwrapped for communication with the filtering thread.
  Some features that conflict with threading are also disabled in
  these patches. That will hopefully change later (though currently
  I don't see how subtitle heartbeat can work in its current form).
* 21 The scheduler itself, merely added without being used
* 22-27 Actually using the scheduler.
  This is split into multiple patches for clarity, but will be squashed
  in the final form.

You can fetch the code from the 'ffmpeg_threading' branch in
git://git.khirnov.net/libav. I will also present a short talk about this
work at VDD. Comments, questions, suggestions, etc. are very much
welcome, both here and there.

Cheers,
-- 
Anton Khirnov

___
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".


[FFmpeg-devel] [PATCH 01/27] fftools/ffmpeg: move derivation of frame duration from filter framerate

2023-09-19 Thread Anton Khirnov
>From ffmpeg_enc to ffmpeg_filter, which is a more appropriate
place for it.

fate-lavf-gxf* no longer spuriously duplicate the first video frame, due
to different rounding.
---
 fftools/ffmpeg_enc.c| 9 +
 fftools/ffmpeg_filter.c | 6 +-
 tests/ref/lavf/gxf  | 2 +-
 tests/ref/lavf/gxf_ntsc | 2 +-
 tests/ref/lavf/gxf_pal  | 2 +-
 5 files changed, 9 insertions(+), 12 deletions(-)

diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c
index b40a6211a9..9b8b3e0226 100644
--- a/fftools/ffmpeg_enc.c
+++ b/fftools/ffmpeg_enc.c
@@ -1109,16 +1109,9 @@ static int do_video_out(OutputFile *of, OutputStream 
*ost, AVFrame *frame)
 int64_t nb_frames, nb_frames_prev, i;
 double duration = 0;
 
-if (frame) {
-FrameData *fd = frame_data(frame);
-
+if (frame)
 duration = lrintf(frame->duration * av_q2d(frame->time_base) / 
av_q2d(enc->time_base));
 
-if (duration <= 0 &&
-fd->frame_rate_filter.num > 0 && fd->frame_rate_filter.den > 0)
-duration = 1 / (av_q2d(fd->frame_rate_filter) * 
av_q2d(enc->time_base));
-}
-
 video_sync_process(of, ost, frame, duration,
_frames, _frames_prev);
 
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 9bf870b615..b6348d7f87 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -1817,8 +1817,12 @@ static int fg_output_step(OutputFilterPriv *ofp, int 
flush)
 
 if (ost->type == AVMEDIA_TYPE_VIDEO) {
 AVRational fr = av_buffersink_get_frame_rate(filter);
-if (fr.num > 0 && fr.den > 0)
+if (fr.num > 0 && fr.den > 0) {
 fd->frame_rate_filter = fr;
+
+if (!frame->duration)
+frame->duration = av_rescale_q(1, av_inv_q(fr), 
frame->time_base);
+}
 }
 
 ret = enc_frame(ost, frame);
diff --git a/tests/ref/lavf/gxf b/tests/ref/lavf/gxf
index e8351fab86..d5fd40c8ab 100644
--- a/tests/ref/lavf/gxf
+++ b/tests/ref/lavf/gxf
@@ -1,3 +1,3 @@
 0638c4d073ac224608baaba16732b68f *tests/data/lavf/lavf.gxf
 795876 tests/data/lavf/lavf.gxf
-tests/data/lavf/lavf.gxf CRC=0x5ade0285
+tests/data/lavf/lavf.gxf CRC=0xe032707a
diff --git a/tests/ref/lavf/gxf_ntsc b/tests/ref/lavf/gxf_ntsc
index 60efd80462..d375420ee6 100644
--- a/tests/ref/lavf/gxf_ntsc
+++ b/tests/ref/lavf/gxf_ntsc
@@ -1,3 +1,3 @@
 9a27673c85f1671ba9ff7cd33e5735de *tests/data/lavf/lavf.gxf_ntsc
 794660 tests/data/lavf/lavf.gxf_ntsc
-tests/data/lavf/lavf.gxf_ntsc CRC=0xdcd39443
+tests/data/lavf/lavf.gxf_ntsc CRC=0xaf956c57
diff --git a/tests/ref/lavf/gxf_pal b/tests/ref/lavf/gxf_pal
index aefcd0ccab..83b0482431 100644
--- a/tests/ref/lavf/gxf_pal
+++ b/tests/ref/lavf/gxf_pal
@@ -1,3 +1,3 @@
 4d1bd16c6d52468c05711d8301e4e302 *tests/data/lavf/lavf.gxf_pal
 795880 tests/data/lavf/lavf.gxf_pal
-tests/data/lavf/lavf.gxf_pal CRC=0x1dbfef76
+tests/data/lavf/lavf.gxf_pal CRC=0x34fe5d7a
-- 
2.40.1

___
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".


[FFmpeg-devel] [PATCH 03/27] fftools/ffmpeg_enc: move remaining vsync-related code to video_sync_process()

2023-09-19 Thread Anton Khirnov
---
 fftools/ffmpeg_enc.c | 46 +++-
 1 file changed, 24 insertions(+), 22 deletions(-)

diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c
index 9aa00f682c..420fe96c97 100644
--- a/fftools/ffmpeg_enc.c
+++ b/fftools/ffmpeg_enc.c
@@ -1048,6 +1048,30 @@ finish:
 e->frames_prev_hist,
 sizeof(e->frames_prev_hist[0]) * 
(FF_ARRAY_ELEMS(e->frames_prev_hist) - 1));
 e->frames_prev_hist[0] = *nb_frames_prev;
+
+if (*nb_frames_prev == 0 && ost->last_dropped) {
+ost->nb_frames_drop++;
+av_log(ost, AV_LOG_VERBOSE,
+   "*** dropping frame %"PRId64" at ts %"PRId64"\n",
+   e->vsync_frame_number, e->last_frame->pts);
+}
+if (*nb_frames > (*nb_frames_prev && ost->last_dropped) + (*nb_frames > 
*nb_frames_prev)) {
+if (*nb_frames > dts_error_threshold * 30) {
+av_log(ost, AV_LOG_ERROR, "%"PRId64" frame duplication too large, 
skipping\n", *nb_frames - 1);
+ost->nb_frames_drop++;
+*nb_frames = 0;
+return;
+}
+ost->nb_frames_dup += *nb_frames - (*nb_frames_prev && 
ost->last_dropped) - (*nb_frames > *nb_frames_prev);
+av_log(ost, AV_LOG_VERBOSE, "*** %"PRId64" dup!\n", *nb_frames - 1);
+if (ost->nb_frames_dup > e->dup_warning) {
+av_log(ost, AV_LOG_WARNING, "More than %"PRIu64" frames 
duplicated\n", e->dup_warning);
+e->dup_warning *= 10;
+}
+}
+
+ost->last_dropped = *nb_frames == *nb_frames_prev && frame;
+ost->kf.dropped_keyframe = ost->last_dropped && frame && (frame->flags & 
AV_FRAME_FLAG_KEY);
 }
 
 static enum AVPictureType forced_kf_apply(void *logctx, KeyframeForceCtx *kf,
@@ -1113,28 +1137,6 @@ static int do_video_out(OutputFile *of, OutputStream 
*ost, AVFrame *frame)
 video_sync_process(of, ost, frame,
_frames, _frames_prev);
 
-if (nb_frames_prev == 0 && ost->last_dropped) {
-ost->nb_frames_drop++;
-av_log(ost, AV_LOG_VERBOSE,
-   "*** dropping frame %"PRId64" at ts %"PRId64"\n",
-   e->vsync_frame_number, e->last_frame->pts);
-}
-if (nb_frames > (nb_frames_prev && ost->last_dropped) + (nb_frames > 
nb_frames_prev)) {
-if (nb_frames > dts_error_threshold * 30) {
-av_log(ost, AV_LOG_ERROR, "%"PRId64" frame duplication too large, 
skipping\n", nb_frames - 1);
-ost->nb_frames_drop++;
-return 0;
-}
-ost->nb_frames_dup += nb_frames - (nb_frames_prev && 
ost->last_dropped) - (nb_frames > nb_frames_prev);
-av_log(ost, AV_LOG_VERBOSE, "*** %"PRId64" dup!\n", nb_frames - 1);
-if (ost->nb_frames_dup > e->dup_warning) {
-av_log(ost, AV_LOG_WARNING, "More than %"PRIu64" frames 
duplicated\n", e->dup_warning);
-e->dup_warning *= 10;
-}
-}
-ost->last_dropped = nb_frames == nb_frames_prev && frame;
-ost->kf.dropped_keyframe = ost->last_dropped && frame && (frame->flags & 
AV_FRAME_FLAG_KEY);
-
 /* duplicates frame if needed */
 for (i = 0; i < nb_frames; i++) {
 AVFrame *in_picture;
-- 
2.40.1

___
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".


Re: [FFmpeg-devel] FFmpeg release 6.1

2023-09-19 Thread Michael Niedermayer
On Tue, Sep 19, 2023 at 07:18:03PM +0200, Niklas Haas wrote:
> On Tue, 11 Apr 2023 00:14:28 +0200 Michael Niedermayer 
>  wrote:
> > Hi all
> > 
> > There was the request to make a 6.1 before end of April
> > Is that still so ?
> > 
> > Assuming it is, its time to make that branch and release soon
> 
> Hi,
> 
> It is now september. What happened to this release? FFmpeg 6.1 is
> currently the only thing blocking the adoption of vulkan video.

there are several security issues that need to be fixed
ossfuzz found more, it also put some random unlreated issues again
into the same ticket. (which are basically invissible sub-tickets)
the evc code also needs a security review, Maybe Dawid is working on this
iam not sure. And iam sure theres more
We also have a security issue in fate, i belive nicolas is looking into
that, that doesnt hold up the release but all these things compete for time
and some people you may have noticed tried to just randomly block patches
going back and forth on these and discussing with tech/community committtees
also took time.
And last but not least if people want me to design a standalone SDR library
while thats not holding up 6.1 it takes time from the pot from 6.1 work.
I did say this, i was attacked but yes time is unforgiving it doesnt care

Also I did fall behind with security fixes in the summer a bit, the weather was
nice, some members of the community where not nice. So i tried to spend some
time with the nice weather

If you want 6.1 to happen quick. be nice to me or help with anything that i
have to work on 6.1 or other so theres more time in the pot
what about merging libplacebo into FFmpeg for example ?
As far as iam concerned you can have absolute final power about anything
in that libplacebo inside FFmpeg.
Or help with the whole SDR thing. If i dont have to think about it and
can concentrate on the release and security then yes it will happen faster

I also have some paid work under NDA which i signed a contract for, i need
to work on that too. Yes code will be submitted to FFmpeg when/if its done
And theres life, i have other shit to do too. For example my taxes and i also
want to spend some time working on AI/neural nets. I guess that will not be
FFmpeg related as id like my work on AI not to be in a similar position to
where avradio is now.

So yeah, i think theres no problem with 6.1 its just not happening as quick
as I and others wanted

thx

[...]
-- 
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

If you think the mosad wants you dead since a long time then you are either
wrong or dead since a long time.


signature.asc
Description: PGP signature
___
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".


Re: [FFmpeg-devel] [PATCH 5/5] avcodec/decode: EAGAIN is not fully supported in decode_simple_internal()

2023-09-19 Thread Michael Niedermayer
On Mon, Sep 18, 2023 at 08:30:58PM -0300, James Almer wrote:
> On 9/18/2023 7:35 PM, Michael Niedermayer wrote:
> > Signed-off-by: Michael Niedermayer 
> > ---
> >   libavcodec/decode.c | 1 +
> >   1 file changed, 1 insertion(+)
> > 
> > diff --git a/libavcodec/decode.c b/libavcodec/decode.c
> > index 169ee79acd9..376e4a4d373 100644
> > --- a/libavcodec/decode.c
> > +++ b/libavcodec/decode.c
> > @@ -457,6 +457,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
> >   if (ret == AVERROR(EAGAIN))
> >   av_frame_unref(frame);
> > +av_assert0(consumed != AVERROR(EAGAIN)); // code later will add 
> > AVERROR(EAGAIN) to a pointer
> 
> FF_CODEC_CB_TYPE_DECODE decoders must not return EAGAIN or EOF, only actual
> error codes. IMO that should be stated too.

ok will apply with an expanded comment


> 
> >   if (consumed < 0)
> >   ret = consumed;
> >   if (consumed >= 0 && avctx->codec->type == AVMEDIA_TYPE_VIDEO)
> 
> LGTM.

thx

[...]

-- 
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Complexity theory is the science of finding the exact solution to an
approximation. Benchmarking OTOH is finding an approximation of the exact


signature.asc
Description: PGP signature
___
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".


[FFmpeg-devel] [PATCH 3/3] doc/ffmpeg: expand -bsf documentation

2023-09-19 Thread Anton Khirnov
Explain how to pass options to filters.
---
 doc/ffmpeg.texi | 15 ---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
index d2864ff37e..cf47eb68d1 100644
--- a/doc/ffmpeg.texi
+++ b/doc/ffmpeg.texi
@@ -1893,9 +1893,18 @@ ffmpeg -i inurl -streamid 0:33 -streamid 1:36 out.ts
 @end example
 
 @item -bsf[:@var{stream_specifier}] @var{bitstream_filters} 
(@emph{output,per-stream})
-Set bitstream filters for matching streams. @var{bitstream_filters} is
-a comma-separated list of bitstream filters. Use the @code{-bsfs} option
-to get the list of bitstream filters.
+Apply bitstream filters to matching streams.
+
+@var{bitstream_filters} is a comma-separated list of bitstream filter
+specifications that will be applied to coded packets in the order they are
+written in. Each bitstream filter specification is of the form
+@example
+@var{filter}[=@var{optname0}=@var{optval0}:@var{optname1}=@var{optval1}:...]
+@end example
+Any of the ',=:' characters that are to be a part of an option value need to be
+escaped with a backslash.
+
+Use the @code{-bsfs} option to get the list of bitstream filters.
 @example
 ffmpeg -i h264.mp4 -c:v copy -bsf:v h264_mp4toannexb -an out.h264
 @end example
-- 
2.40.1

___
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".


[FFmpeg-devel] [PATCH 2/3] tests/fate: replace deprecated -vsync with -fps_mode

2023-09-19 Thread Anton Khirnov
---
 tests/fate/ffmpeg.mak | 4 ++--
 tests/fate/filter-video.mak   | 2 +-
 tests/fate/gif.mak| 2 +-
 tests/fate/hevc.mak   | 2 +-
 tests/fate/lossless-video.mak | 6 +++---
 tests/fate/mov.mak| 4 ++--
 tests/fate/mpeg4.mak  | 2 +-
 tests/fate/vcodec.mak | 2 +-
 tests/fate/vpx.mak| 2 +-
 9 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/tests/fate/ffmpeg.mak b/tests/fate/ffmpeg.mak
index b5c26788c0..a17539ba7a 100644
--- a/tests/fate/ffmpeg.mak
+++ b/tests/fate/ffmpeg.mak
@@ -67,7 +67,7 @@ fate-sub2video: CMD = framecrc -auto_conversion_filters \
 FATE_SAMPLES_FFMPEG-$(call FRAMECRC, VOBSUB, DVDSUB, SCALE_FILTER) += 
fate-sub2video_basic
 fate-sub2video_basic: CMD = framecrc -auto_conversion_filters \
   -i $(TARGET_SAMPLES)/sub/vobsub.idx \
-  -vsync passthrough -copyts \
+  -fps_mode passthrough -copyts \
   -filter_complex "sws_flags=+accurate_rnd+bitexact\;[0:s:0]scale" \
   -c:v rawvideo -threads 1
 
@@ -76,7 +76,7 @@ fate-sub2video_basic: CMD = framecrc -auto_conversion_filters 
\
 FATE_SAMPLES_FFMPEG-$(call FRAMECRC, SUP, PGSSUB, SCALE_FILTER 
RAWVIDEO_ENCODER) += fate-sub2video_time_limited
 fate-sub2video_time_limited: CMD = framecrc -auto_conversion_filters \
   -i $(TARGET_SAMPLES)/sub/pgs_sub.sup \
-  -vsync passthrough -copyts \
+  -fps_mode passthrough -copyts \
   -t 15 \
   -filter_complex "sws_flags=+accurate_rnd+bitexact\;[0:s:0]scale" \
   -c:v rawvideo -threads 1
diff --git a/tests/fate/filter-video.mak b/tests/fate/filter-video.mak
index 789ec6414c..0b919f55a8 100644
--- a/tests/fate/filter-video.mak
+++ b/tests/fate/filter-video.mak
@@ -391,7 +391,7 @@ fate-filter-fps-start-drop: CMD = framecrc -lavfi 
testsrc2=r=7:d=3.5,fps=3:start
 fate-filter-fps-start-fill: CMD = framecrc -lavfi 
testsrc2=r=7:d=1.5,setpts=PTS+14,fps=3:start_time=1.5
 
 FATE_FILTER_SAMPLES-$(call FILTERDEMDEC, FPS SCALE, MOV, QTRLE) += 
fate-filter-fps-cfr fate-filter-fps
-fate-filter-fps-cfr: CMD = framecrc -auto_conversion_filters -i 
$(TARGET_SAMPLES)/qtrle/apple-animation-variable-fps-bug.mov -r 30 -vsync cfr 
-pix_fmt yuv420p
+fate-filter-fps-cfr: CMD = framecrc -auto_conversion_filters -i 
$(TARGET_SAMPLES)/qtrle/apple-animation-variable-fps-bug.mov -r 30 -fps_mode 
cfr -pix_fmt yuv420p
 fate-filter-fps: CMD = framecrc -auto_conversion_filters -i 
$(TARGET_SAMPLES)/qtrle/apple-animation-variable-fps-bug.mov -vf fps=30 
-pix_fmt yuv420p
 
 FATE_FILTER_ALPHAEXTRACT_ALPHAMERGE := $(addprefix 
fate-filter-alphaextract_alphamerge_, rgb yuv)
diff --git a/tests/fate/gif.mak b/tests/fate/gif.mak
index 1eef2a1026..fc5a73218d 100644
--- a/tests/fate/gif.mak
+++ b/tests/fate/gif.mak
@@ -11,7 +11,7 @@ FATE_GIF += fate-gif-gray
 fate-gif-gray: CMD = framecrc -i 
$(TARGET_SAMPLES)/gif/Newtons_cradle_animation_book_2.gif -pix_fmt bgra -vf 
scale
 
 FATE_GIF += fate-gif-deal
-fate-gif-deal: CMD = framecrc -i $(TARGET_SAMPLES)/gif/deal.gif -vsync cfr 
-pix_fmt bgra -auto_conversion_filters
+fate-gif-deal: CMD = framecrc -i $(TARGET_SAMPLES)/gif/deal.gif -fps_mode cfr 
-pix_fmt bgra -auto_conversion_filters
 
 FATE_GIF-$(call FRAMECRC, GIF, GIF, SCALE_FILTER) += $(FATE_GIF)
 
diff --git a/tests/fate/hevc.mak b/tests/fate/hevc.mak
index 20c2e5ba9c..b3c6792140 100644
--- a/tests/fate/hevc.mak
+++ b/tests/fate/hevc.mak
@@ -210,7 +210,7 @@ FATE_HEVC-$(call FRAMECRC, HEVC, HEVC, HEVC_PARSER 
SCALE_FILTER) += \
 $(HEVC_TESTS_422_10BIN) \
 $(HEVC_TESTS_444_12BIT) \
 
-fate-hevc-paramchange-yuv420p-yuv420p10: CMD = framecrc -vsync passthrough -i 
$(TARGET_SAMPLES)/hevc/paramchange_yuv420p_yuv420p10.hevc -sws_flags 
area+accurate_rnd+bitexact
+fate-hevc-paramchange-yuv420p-yuv420p10: CMD = framecrc -i 
$(TARGET_SAMPLES)/hevc/paramchange_yuv420p_yuv420p10.hevc -fps_mode passthrough 
-sws_flags area+accurate_rnd+bitexact
 FATE_HEVC-$(call FRAMECRC, HEVC, HEVC, HEVC_PARSER SCALE_FILTER LARGE_TESTS) 
+= fate-hevc-paramchange-yuv420p-yuv420p10
 
 tests/data/hevc-mp4.mov: TAG = GEN
diff --git a/tests/fate/lossless-video.mak b/tests/fate/lossless-video.mak
index 05a8ba29e1..74292d13c7 100644
--- a/tests/fate/lossless-video.mak
+++ b/tests/fate/lossless-video.mak
@@ -15,9 +15,9 @@ fate-lagarith-red: CMD = framecrc -i 
$(TARGET_SAMPLES)/lagarith/lagarith-red.avi
 
 FATE_LAGARITH += fate-lagarith-ticket4119 fate-lagarith-ticket4119-cfr 
fate-lagarith-ticket4119-vfr fate-lagarith-ticket4119-pass
 fate-lagarith-ticket4119: CMD = framecrc -i 
$(TARGET_SAMPLES)/lagarith/lagarith-1.3.27-black-frames-and-off-by-ones.avi
-fate-lagarith-ticket4119-cfr : CMD = framecrc -i 
$(TARGET_SAMPLES)/lagarith/lagarith-1.3.27-black-frames-and-off-by-ones.avi 
-vsync cfr
-fate-lagarith-ticket4119-vfr : CMD = framecrc -i 
$(TARGET_SAMPLES)/lagarith/lagarith-1.3.27-black-frames-and-off-by-ones.avi 
-vsync vfr
-fate-lagarith-ticket4119-pass: CMD = framecrc -i 

[FFmpeg-devel] [PATCH 1/3] tests/fate/ffmpeg: replace deprecated -vbsf with -bsf:v

2023-09-19 Thread Anton Khirnov
---
 tests/fate/ffmpeg.mak | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tests/fate/ffmpeg.mak b/tests/fate/ffmpeg.mak
index 04500d53a0..b5c26788c0 100644
--- a/tests/fate/ffmpeg.mak
+++ b/tests/fate/ffmpeg.mak
@@ -217,11 +217,11 @@ fate-h264_mp4toannexb_ticket5927_2: CMD = transcode "mp4" 
$(TARGET_SAMPLES)/h264
 
 FATE_SAMPLES_FFMPEG-$(call TRANSCODE, MPEG4 MPEG2VIDEO, AVI, MPEGPS_DEMUXER 
MPEGVIDEO_DEMUXER MPEGVIDEO_PARSER EXTRACT_EXTRADATA_BSF REMOVE_EXTRADATA_BSF) 
+= fate-ffmpeg-bsf-remove-k fate-ffmpeg-bsf-remove-r fate-ffmpeg-bsf-remove-e
 fate-ffmpeg-bsf-remove-k: CMD = transcode "mpeg" 
$(TARGET_SAMPLES)/mpeg2/matrixbench_mpeg2.lq1.mpg\
-  avi "-vbsf remove_extra=k" "-codec copy"
+  avi "-bsf:v remove_extra=k" "-codec copy"
 fate-ffmpeg-bsf-remove-r: CMD = transcode "mpeg" 
$(TARGET_SAMPLES)/mpeg2/matrixbench_mpeg2.lq1.mpg\
-  avi "-vbsf remove_extra=keyframe" "-codec copy"
+  avi "-bsf:v remove_extra=keyframe" "-codec copy"
 fate-ffmpeg-bsf-remove-e: CMD = transcode "mpeg" 
$(TARGET_SAMPLES)/mpeg2/matrixbench_mpeg2.lq1.mpg\
-  avi "-vbsf remove_extra=e" "-codec copy"
+  avi "-bsf:v remove_extra=e" "-codec copy"
 
 FATE_SAMPLES_FFMPEG-$(call DEMMUX, APNG, FRAMECRC, SETTS_BSF PIPE_PROTOCOL) += 
fate-ffmpeg-setts-bsf
 fate-ffmpeg-setts-bsf: CMD = framecrc -i $(TARGET_SAMPLES)/apng/clock.png -c:v 
copy -bsf:v 
"setts=duration=if(eq(NEXT_PTS\,NOPTS)\,PREV_OUTDURATION\,(NEXT_PTS-PTS)/2):ts=PTS/2"
 -fflags +bitexact
-- 
2.40.1

___
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".


Re: [FFmpeg-devel] [PATCH 3/5] avcodec/dcadec: Do not explode EAGAIN

2023-09-19 Thread Michael Niedermayer
On Mon, Sep 18, 2023 at 08:24:25PM -0300, James Almer wrote:
> On 9/18/2023 7:35 PM, Michael Niedermayer wrote:
> > Fixes: out of array access
> > Fixes: 
> > 62164/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_DCA_fuzzer-6041088751960064
> > 
> > Found-by: continuous fuzzing process 
> > https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
> > Signed-off-by: Michael Niedermayer 
> > ---
> >   libavcodec/dcadec.c | 2 +-
> >   1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/libavcodec/dcadec.c b/libavcodec/dcadec.c
> > index 3e3e3053bbe..070a9ae094d 100644
> > --- a/libavcodec/dcadec.c
> > +++ b/libavcodec/dcadec.c
> > @@ -221,7 +221,7 @@ static int dcadec_decode_frame(AVCodecContext *avctx, 
> > AVFrame *frame,
> >   && (prev_packet & DCA_PACKET_XLL)
> >   && (s->packet & DCA_PACKET_CORE))
> >   s->packet |= DCA_PACKET_XLL | DCA_PACKET_RECOVERY;
> > -else if (ret == AVERROR(ENOMEM) || (avctx->err_recognition 
> > & AV_EF_EXPLODE))
> > +else if (ret == AVERROR(ENOMEM) || (avctx->err_recognition 
> > & AV_EF_EXPLODE) && ret != AVERROR(EAGAIN))
> >   return ret;
> >   } else {
> >   s->packet |= DCA_PACKET_XLL;
> 
> Maybe instead do
> 
> > diff --git a/libavcodec/dcadec.c b/libavcodec/dcadec.c
> > index 3e3e3053bb..3926115f21 100644
> > --- a/libavcodec/dcadec.c
> > +++ b/libavcodec/dcadec.c
> > @@ -217,11 +217,10 @@ static int dcadec_decode_frame(AVCodecContext *avctx, 
> > AVFrame *frame,
> >  if (asset && (asset->extension_mask & DCA_EXSS_XLL)) {
> >  if ((ret = ff_dca_xll_parse(>xll, input, asset)) < 0) {
> >  // Conceal XLL synchronization error
> > -if (ret == AVERROR(EAGAIN)
> > -&& (prev_packet & DCA_PACKET_XLL)
> > -&& (s->packet & DCA_PACKET_CORE))
> > -s->packet |= DCA_PACKET_XLL | DCA_PACKET_RECOVERY;
> > -else if (ret == AVERROR(ENOMEM) || (avctx->err_recognition 
> > & AV_EF_EXPLODE))
> > +if (ret == AVERROR(EAGAIN) {
> > +if ((prev_packet & DCA_PACKET_XLL) && (s->packet & 
> > DCA_PACKET_CORE))
> > +s->packet |= DCA_PACKET_XLL | DCA_PACKET_RECOVERY;
> > +} else if (ret == AVERROR(ENOMEM) || 
> > (avctx->err_recognition & AV_EF_EXPLODE))
> >  return ret;
> >  } else {
> >  s->packet |= DCA_PACKET_XLL;
> 
> So EAGAIN is handled in one place.

ok will apply with you as author as its your change now

thx

[...]

-- 
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Everything should be made as simple as possible, but not simpler.
-- Albert Einstein


signature.asc
Description: PGP signature
___
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".


Re: [FFmpeg-devel] [PATCH] avcodec/cbs_h266_syntax_template: Check num_output_layers_in_ols

2023-09-19 Thread Michael Niedermayer
On Tue, Sep 19, 2023 at 11:28:20PM +0800, Nuo Mi wrote:
> On Tue, Sep 19, 2023 at 11:26 PM Nuo Mi  wrote:
> 
> > from the specification:
> > For each OLS, there shall be at least one layer that is an output layer.
> > In other words, for any value of i in the range of 0
> > to TotalNumOlss − 1, inclusive, the value of NumOutputLayersInOls[ i ]
> > shall be greater than or equal to 1
> >
> > Fixes: index 257 out of bounds for type 'uint8_t [257]'
> > Fixes:
> > 61160/clusterfuzz-testcase-minimized-ffmpeg_BSF_VVC_METADATA_fuzzer-6709397181825024
> >
> replaces
> https://patchwork.ffmpeg.org/project/ffmpeg/patch/20230905020358.32527-2-mich...@niedermayer.cc/

will apply your patch

thanks

[...]
-- 
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Take away the freedom of one citizen and you will be jailed, take away
the freedom of all citizens and you will be congratulated by your peers
in Parliament.


signature.asc
Description: PGP signature
___
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".


Re: [FFmpeg-devel] TRAC Spam

2023-09-19 Thread Michael Niedermayer
On Tue, Sep 19, 2023 at 07:44:03AM +0200, Michael Koch wrote:
> Ticket / Comment
> 2104 / 14
> 2776 / 6
> 3720 / 9

The ticket comment 14 on ticket #2104 has been deleted.
The ticket comment 6 on ticket #2776 has been deleted.
The ticket comment 9 on ticket #3720 has been deleted.


[...]
-- 
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

It is dangerous to be right in matters on which the established authorities
are wrong. -- Voltaire


signature.asc
Description: PGP signature
___
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".


  1   2   >