* [FFmpeg-devel] [PATCH v3] Add avpriv_slicethread_create2() and avpriv_slicethread_execute2(), make execute() and execute2() return FFMIN() of thread return codes
@ 2022-09-26 13:46 Tomas Härdin
2022-09-26 13:50 ` Andreas Rheinhardt
2022-09-26 13:58 ` Andreas Rheinhardt
0 siblings, 2 replies; 9+ messages in thread
From: Tomas Härdin @ 2022-09-26 13:46 UTC (permalink / raw)
To: ffmpeg-devel
[-- Attachment #1: Type: text/plain, Size: 226 bytes --]
Fixed the ABI break in the previous version of this patch, updated all
internal uses of related APIs.
Tested with both ./configure and ./configure --disable-pthreads
Also using a new email for mailing list purposes.
/Tomas
[-- Attachment #2: 0001-Add-avpriv_slicethread_create2-and-avpriv_slicethrea.patch --]
[-- Type: text/x-patch, Size: 22938 bytes --]
From 265f1095fb85b1eba18ed1b89fe71531ee09fe9b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= <git@haerdin.se>
Date: Thu, 16 Jun 2022 12:16:44 +0200
Subject: [PATCH] Add avpriv_slicethread_create2() and
avpriv_slicethread_execute2(), make execute() and execute2() return FFMIN()
of thread return codes
Updates all internal uses of related APIs.
At the moment only fic.c actually checks return code of execute() hence the change to its FATE reference.
---
doc/APIchanges | 4 ++
libavcodec/avcodec.c | 10 +++--
libavcodec/pthread_slice.c | 14 +++----
libavfilter/pthread.c | 8 ++--
libavutil/slicethread.c | 70 ++++++++++++++++++++++++++++++++---
libavutil/slicethread.h | 27 ++++++++++++++
libavutil/version.h | 2 +-
libswscale/swscale.c | 20 ++--------
libswscale/swscale_internal.h | 6 +--
libswscale/utils.c | 8 ++--
tests/fate/screen.mak | 1 +
tests/ref/fate/fic-avi | 30 +++++++--------
12 files changed, 137 insertions(+), 63 deletions(-)
diff --git a/doc/APIchanges b/doc/APIchanges
index b0a41c9e37..240e549a2f 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -14,6 +14,10 @@ libavutil: 2021-04-27
API changes, most recent first:
+2022-09-26 - xxxxxxxxxx - lavu 57.38.100 - slicethread.h
+ Deprecate avpriv_slicethread_create() and avpriv_slicethread_execute().
+ Add avpriv_slicethread_create2() and avpriv_slicethread_execute2().
+
2022-09-26 - xxxxxxxxxx - lavc 59.48.100 - avcodec.h
Deprecate avcodec_enum_to_chroma_pos() and avcodec_chroma_pos_to_enum().
Use av_chroma_location_enum_to_pos() or av_chroma_location_pos_to_enum()
diff --git a/libavcodec/avcodec.c b/libavcodec/avcodec.c
index a85d3c2309..ee75b3abe7 100644
--- a/libavcodec/avcodec.c
+++ b/libavcodec/avcodec.c
@@ -44,28 +44,30 @@
int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2), void *arg, int *ret, int count, int size)
{
- int i;
+ int i, rr = 0;
for (i = 0; i < count; i++) {
int r = func(c, (char *)arg + i * size);
+ rr = FFMIN(rr, r);
if (ret)
ret[i] = r;
}
emms_c();
- return 0;
+ return rr;
}
int avcodec_default_execute2(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2, int jobnr, int threadnr), void *arg, int *ret, int count)
{
- int i;
+ int i, rr = 0;
for (i = 0; i < count; i++) {
int r = func(c, arg, i, 0);
+ rr = FFMIN(rr, r);
if (ret)
ret[i] = r;
}
emms_c();
- return 0;
+ return rr;
}
static AVMutex codec_mutex = AV_MUTEX_INITIALIZER;
diff --git a/libavcodec/pthread_slice.c b/libavcodec/pthread_slice.c
index a4d31c6f4d..795d0c9c5a 100644
--- a/libavcodec/pthread_slice.c
+++ b/libavcodec/pthread_slice.c
@@ -61,13 +61,13 @@ typedef struct SliceThreadContext {
Progress *progress;
} SliceThreadContext;
-static void main_function(void *priv) {
+static int main_function(void *priv) {
AVCodecContext *avctx = priv;
SliceThreadContext *c = avctx->internal->thread_ctx;
- c->mainfunc(avctx);
+ return c->mainfunc(avctx);
}
-static void worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
+static int worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
{
AVCodecContext *avctx = priv;
SliceThreadContext *c = avctx->internal->thread_ctx;
@@ -77,6 +77,7 @@ static void worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb
: c->func2(avctx, c->args, jobnr, threadnr);
if (c->rets)
c->rets[jobnr] = ret;
+ return ret;
}
void ff_slice_thread_free(AVCodecContext *avctx)
@@ -112,8 +113,7 @@ static int thread_execute(AVCodecContext *avctx, action_func* func, void *arg, i
c->func = func;
c->rets = ret;
- avpriv_slicethread_execute(c->thread, job_count, !!c->mainfunc );
- return 0;
+ return avpriv_slicethread_execute2(c->thread, job_count, !!c->mainfunc);
}
static int thread_execute2(AVCodecContext *avctx, action_func2* func2, void *arg, int *ret, int job_count)
@@ -135,7 +135,7 @@ int ff_slice_thread_init(AVCodecContext *avctx)
{
SliceThreadContext *c;
int thread_count = avctx->thread_count;
- void (*mainfunc)(void *);
+ int (*mainfunc)(void *);
// We cannot do this in the encoder init as the threads are created before
if (av_codec_is_encoder(avctx->codec) &&
@@ -161,7 +161,7 @@ int ff_slice_thread_init(AVCodecContext *avctx)
avctx->internal->thread_ctx = c = av_mallocz(sizeof(*c));
mainfunc = ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_SLICE_THREAD_HAS_MF ? &main_function : NULL;
- if (!c || (thread_count = avpriv_slicethread_create(&c->thread, avctx, worker_func, mainfunc, thread_count)) <= 1) {
+ if (!c || (thread_count = avpriv_slicethread_create2(&c->thread, avctx, worker_func, mainfunc, thread_count)) <= 1) {
if (c)
avpriv_slicethread_free(&c->thread);
av_freep(&avctx->internal->thread_ctx);
diff --git a/libavfilter/pthread.c b/libavfilter/pthread.c
index 1a063d3cc0..855c842df9 100644
--- a/libavfilter/pthread.c
+++ b/libavfilter/pthread.c
@@ -43,12 +43,13 @@ typedef struct ThreadContext {
int *rets;
} ThreadContext;
-static void worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
+static int worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
{
ThreadContext *c = priv;
int ret = c->func(c->ctx, c->arg, jobnr, nb_jobs);
if (c->rets)
c->rets[jobnr] = ret;
+ return ret;
}
static void slice_thread_uninit(ThreadContext *c)
@@ -68,13 +69,12 @@ static int thread_execute(AVFilterContext *ctx, avfilter_action_func *func,
c->func = func;
c->rets = ret;
- avpriv_slicethread_execute(c->thread, nb_jobs, 0);
- return 0;
+ return avpriv_slicethread_execute2(c->thread, nb_jobs, 0);
}
static int thread_init_internal(ThreadContext *c, int nb_threads)
{
- nb_threads = avpriv_slicethread_create(&c->thread, c, worker_func, NULL, nb_threads);
+ nb_threads = avpriv_slicethread_create2(&c->thread, c, worker_func, NULL, nb_threads);
if (nb_threads <= 1)
avpriv_slicethread_free(&c->thread);
return FFMAX(nb_threads, 1);
diff --git a/libavutil/slicethread.c b/libavutil/slicethread.c
index 115b099736..38c4ebdc4c 100644
--- a/libavutil/slicethread.c
+++ b/libavutil/slicethread.c
@@ -34,6 +34,7 @@ typedef struct WorkerContext {
pthread_cond_t cond;
pthread_t thread;
int done;
+ int ret;
} WorkerContext;
struct AVSliceThread {
@@ -50,11 +51,15 @@ struct AVSliceThread {
int finished;
void *priv;
+ // either worker_func and main_func are non-NULL or worker_func2 and main_func2 are
+ // all four are never non-NULL at the same time
void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads);
void (*main_func)(void *priv);
+ int (*worker_func2)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads);
+ int (*main_func2)(void *priv);
};
-static int run_jobs(AVSliceThread *ctx)
+static int run_jobs(AVSliceThread *ctx, int *ret_out)
{
unsigned nb_jobs = ctx->nb_jobs;
unsigned nb_active_threads = ctx->nb_active_threads;
@@ -62,7 +67,12 @@ static int run_jobs(AVSliceThread *ctx)
unsigned current_job = first_job;
do {
- ctx->worker_func(ctx->priv, current_job, first_job, nb_jobs, nb_active_threads);
+ if (ctx->worker_func2) {
+ int ret = ctx->worker_func2(ctx->priv, current_job, first_job, nb_jobs, nb_active_threads);
+ *ret_out = FFMIN(*ret_out, ret);
+ } else {
+ ctx->worker_func(ctx->priv, current_job, first_job, nb_jobs, nb_active_threads);
+ }
} while ((current_job = atomic_fetch_add_explicit(&ctx->current_job, 1, memory_order_acq_rel)) < nb_jobs);
return current_job == nb_jobs + nb_active_threads - 1;
@@ -86,7 +96,7 @@ static void *attribute_align_arg thread_worker(void *v)
return NULL;
}
- if (run_jobs(ctx)) {
+ if (run_jobs(ctx, &w->ret)) {
pthread_mutex_lock(&ctx->done_mutex);
ctx->done = 1;
pthread_cond_signal(&ctx->done_cond);
@@ -95,9 +105,11 @@ static void *attribute_align_arg thread_worker(void *v)
}
}
-int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
+static int slicethread_create(AVSliceThread **pctx, void *priv,
void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
void (*main_func)(void *priv),
+ int (*worker_func2)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
+ int (*main_func2)(void *priv),
int nb_threads)
{
AVSliceThread *ctx;
@@ -128,6 +140,8 @@ int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
ctx->priv = priv;
ctx->worker_func = worker_func;
ctx->main_func = main_func;
+ ctx->worker_func2= worker_func2;
+ ctx->main_func2 = main_func2;
ctx->nb_threads = nb_threads;
ctx->nb_active_threads = 0;
ctx->nb_jobs = 0;
@@ -165,9 +179,30 @@ int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
return nb_threads;
}
+int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
+ void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
+ void (*main_func)(void *priv),
+ int nb_threads)
+{
+ return slicethread_create(pctx, priv, worker_func, main_func, NULL, NULL, nb_threads);
+}
+
+int avpriv_slicethread_create2(AVSliceThread **pctx, void *priv,
+ int (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
+ int (*main_func)(void *priv),
+ int nb_threads)
+{
+ return slicethread_create(pctx, priv, NULL, NULL, worker_func, main_func, nb_threads);
+}
+
void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main)
{
- int nb_workers, i, is_last = 0;
+ (void)avpriv_slicethread_execute2(ctx, nb_jobs, execute_main);
+}
+
+int avpriv_slicethread_execute2(AVSliceThread *ctx, int nb_jobs, int execute_main)
+{
+ int nb_workers, i, is_last = 0, ret = 0;
av_assert0(nb_jobs > 0);
ctx->nb_jobs = nb_jobs;
@@ -182,14 +217,17 @@ void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_mai
WorkerContext *w = &ctx->workers[i];
pthread_mutex_lock(&w->mutex);
w->done = 0;
+ w->ret = 0;
pthread_cond_signal(&w->cond);
pthread_mutex_unlock(&w->mutex);
}
if (ctx->main_func && execute_main)
ctx->main_func(ctx->priv);
+ else if (ctx->main_func2 && execute_main)
+ ret = ctx->main_func2(ctx->priv);
else
- is_last = run_jobs(ctx);
+ is_last = run_jobs(ctx, &ret);
if (!is_last) {
pthread_mutex_lock(&ctx->done_mutex);
@@ -198,6 +236,11 @@ void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_mai
ctx->done = 0;
pthread_mutex_unlock(&ctx->done_mutex);
}
+
+ for (i = 0; i < nb_workers; i++)
+ ret = FFMIN(ret, ctx->workers[i].ret);
+
+ return ret;
}
void avpriv_slicethread_free(AVSliceThread **pctx)
@@ -246,11 +289,26 @@ int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
return AVERROR(ENOSYS);
}
+int avpriv_slicethread_create2(AVSliceThread **pctx, void *priv,
+ int (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
+ int (*main_func)(void *priv),
+ int nb_threads)
+{
+ *pctx = NULL;
+ return AVERROR(ENOSYS);
+}
+
void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main)
{
av_assert0(0);
}
+int avpriv_slicethread_execute2(AVSliceThread *ctx, int nb_jobs, int execute_main)
+{
+ av_assert0(0);
+ return AVERROR(ENOSYS);
+}
+
void avpriv_slicethread_free(AVSliceThread **pctx)
{
av_assert0(!pctx || !*pctx);
diff --git a/libavutil/slicethread.h b/libavutil/slicethread.h
index f6f6f302c4..4deb287674 100644
--- a/libavutil/slicethread.h
+++ b/libavutil/slicethread.h
@@ -29,20 +29,47 @@ typedef struct AVSliceThread AVSliceThread;
* @param main_func special callback function, called from main thread, may be NULL
* @param nb_threads number of threads, 0 for automatic, must be >= 0
* @return return number of threads or negative AVERROR on failure
+ * @deprecated Use avpriv_slicethread_create2() instead.
*/
+attribute_deprecated
int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
void (*main_func)(void *priv),
int nb_threads);
+/**
+ * Like avpriv_slicethread_create() except worker_func and main_func return int.
+ * @param pctx slice threading context returned here
+ * @param priv private pointer to be passed to callback function
+ * @param worker_func callback function to be executed
+ * @param main_func special callback function, called from main thread, may be NULL
+ * @param nb_threads number of threads, 0 for automatic, must be >= 0
+ * @return return number of threads or negative AVERROR on failure
+ */
+int avpriv_slicethread_create2(AVSliceThread **pctx, void *priv,
+ int (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
+ int (*main_func)(void *priv),
+ int nb_threads);
+
/**
* Execute slice threading.
* @param ctx slice threading context
* @param nb_jobs number of jobs, must be > 0
* @param execute_main also execute main_func
+ * @deprecated Use avpriv_slicethread_execute2() instead.
*/
+attribute_deprecated
void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main);
+/**
+ * Like avpriv_slicethread_execute() except returns FFMIN(0, main_func(), worker_func()).
+ * @param ctx slice threading context
+ * @param nb_jobs number of jobs, must be > 0
+ * @param execute_main also execute main_func
+ * @return AVERROR on error.
+ */
+int avpriv_slicethread_execute2(AVSliceThread *ctx, int nb_jobs, int execute_main);
+
/**
* Destroy slice threading context.
* @param pctx pointer to context
diff --git a/libavutil/version.h b/libavutil/version.h
index 9c44cef6aa..5aca550f45 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -79,7 +79,7 @@
*/
#define LIBAVUTIL_VERSION_MAJOR 57
-#define LIBAVUTIL_VERSION_MINOR 37
+#define LIBAVUTIL_VERSION_MINOR 38
#define LIBAVUTIL_VERSION_MICRO 100
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
diff --git a/libswscale/swscale.c b/libswscale/swscale.c
index 367d045a02..500b74c099 100644
--- a/libswscale/swscale.c
+++ b/libswscale/swscale.c
@@ -1150,23 +1150,11 @@ int sws_receive_slice(struct SwsContext *c, unsigned int slice_start,
if (c->slicethread) {
int nb_jobs = c->slice_ctx[0]->dither == SWS_DITHER_ED ? 1 : c->nb_slice_ctx;
- int ret = 0;
c->dst_slice_start = slice_start;
c->dst_slice_height = slice_height;
- avpriv_slicethread_execute(c->slicethread, nb_jobs, 0);
-
- for (int i = 0; i < c->nb_slice_ctx; i++) {
- if (c->slice_err[i] < 0) {
- ret = c->slice_err[i];
- break;
- }
- }
-
- memset(c->slice_err, 0, c->nb_slice_ctx * sizeof(*c->slice_err));
-
- return ret;
+ return avpriv_slicethread_execute2(c->slicethread, nb_jobs, 0);
}
for (int i = 0; i < FF_ARRAY_ELEMS(dst); i++) {
@@ -1213,8 +1201,8 @@ int attribute_align_arg sws_scale(struct SwsContext *c,
dst, dstStride, 0, c->dstH);
}
-void ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
- int nb_jobs, int nb_threads)
+int ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
+ int nb_jobs, int nb_threads)
{
SwsContext *parent = priv;
SwsContext *c = parent->slice_ctx[threadnr];
@@ -1242,5 +1230,5 @@ void ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
parent->dst_slice_start + slice_start, slice_end - slice_start);
}
- parent->slice_err[threadnr] = err;
+ return err;
}
diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h
index abeebbb002..50e73c86fa 100644
--- a/libswscale/swscale_internal.h
+++ b/libswscale/swscale_internal.h
@@ -306,7 +306,7 @@ typedef struct SwsContext {
AVSliceThread *slicethread;
struct SwsContext **slice_ctx;
- int *slice_err;
+ attribute_deprecated int *slice_err; ///< @deprecated Not used any more. Removing it would require a bunch of asm to be rewritten.
int nb_slice_ctx;
// values passed to current sws_receive_slice() call
@@ -1152,8 +1152,8 @@ void ff_init_vscale_pfn(SwsContext *c, yuv2planar1_fn yuv2plane1, yuv2planarX_fn
yuv2interleavedX_fn yuv2nv12cX, yuv2packed1_fn yuv2packed1, yuv2packed2_fn yuv2packed2,
yuv2packedX_fn yuv2packedX, yuv2anyX_fn yuv2anyX, int use_mmx);
-void ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
- int nb_jobs, int nb_threads);
+int ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
+ int nb_jobs, int nb_threads);
//number of extra lines to process
#define MAX_LINES_AHEAD 4
diff --git a/libswscale/utils.c b/libswscale/utils.c
index 45baa22b23..8bfd3a64ac 100644
--- a/libswscale/utils.c
+++ b/libswscale/utils.c
@@ -1273,8 +1273,8 @@ static int context_init_threaded(SwsContext *c,
{
int ret;
- ret = avpriv_slicethread_create(&c->slicethread, (void*)c,
- ff_sws_slice_worker, NULL, c->nb_threads);
+ ret = avpriv_slicethread_create2(&c->slicethread, (void*)c,
+ ff_sws_slice_worker, NULL, c->nb_threads);
if (ret == AVERROR(ENOSYS)) {
c->nb_threads = 1;
return 0;
@@ -1284,8 +1284,7 @@ static int context_init_threaded(SwsContext *c,
c->nb_threads = ret;
c->slice_ctx = av_calloc(c->nb_threads, sizeof(*c->slice_ctx));
- c->slice_err = av_calloc(c->nb_threads, sizeof(*c->slice_err));
- if (!c->slice_ctx || !c->slice_err)
+ if (!c->slice_ctx)
return AVERROR(ENOMEM);
for (int i = 0; i < c->nb_threads; i++) {
@@ -2421,7 +2420,6 @@ void sws_freeContext(SwsContext *c)
for (i = 0; i < c->nb_slice_ctx; i++)
sws_freeContext(c->slice_ctx[i]);
av_freep(&c->slice_ctx);
- av_freep(&c->slice_err);
avpriv_slicethread_free(&c->slicethread);
diff --git a/tests/fate/screen.mak b/tests/fate/screen.mak
index bd6d228544..b572f67b55 100644
--- a/tests/fate/screen.mak
+++ b/tests/fate/screen.mak
@@ -5,6 +5,7 @@ fate-cscd: CMD = framecrc -i $(TARGET_SAMPLES)/CSCD/sample_video.avi -an -pix_fm
FATE_SCREEN-$(call FRAMECRC, AVI, DXTORY) += fate-dxtory
fate-dxtory: CMD = framecrc -i $(TARGET_SAMPLES)/dxtory/dxtory_mic.avi -an
+# fic sample is broken. some packets are truncated and one packet has length zero
FATE_SCREEN-$(call FRAMECRC, AVI, FIC) += fate-fic-avi
fate-fic-avi: CMD = framecrc -i $(TARGET_SAMPLES)/fic/fic-partial-2MB.avi -an
diff --git a/tests/ref/fate/fic-avi b/tests/ref/fate/fic-avi
index df55789d54..4546f230b1 100644
--- a/tests/ref/fate/fic-avi
+++ b/tests/ref/fate/fic-avi
@@ -76,19 +76,18 @@
0, 70, 70, 1, 1566720, 0x40f7d39a
0, 71, 71, 1, 1566720, 0x40f7d39a
0, 72, 72, 1, 1566720, 0x40f7d39a
-0, 73, 73, 1, 1566720, 0xa7d6e25f
-0, 74, 74, 1, 1566720, 0xa7d6e25f
-0, 75, 75, 1, 1566720, 0xa7d6e25f
-0, 76, 76, 1, 1566720, 0xa7d6e25f
-0, 77, 77, 1, 1566720, 0xa7d6e25f
-0, 78, 78, 1, 1566720, 0xa7d6e25f
-0, 79, 79, 1, 1566720, 0xa7d6e25f
-0, 80, 80, 1, 1566720, 0xa7d6e25f
-0, 81, 81, 1, 1566720, 0xa7d6e25f
-0, 82, 82, 1, 1566720, 0xa7d6e25f
-0, 83, 83, 1, 1566720, 0xa7d6e25f
-0, 84, 84, 1, 1566720, 0xa7d6e25f
-0, 85, 85, 1, 1566720, 0xa7d6e25f
+0, 74, 74, 1, 1566720, 0x40f7d39a
+0, 75, 75, 1, 1566720, 0x40f7d39a
+0, 76, 76, 1, 1566720, 0x40f7d39a
+0, 77, 77, 1, 1566720, 0x40f7d39a
+0, 78, 78, 1, 1566720, 0x40f7d39a
+0, 79, 79, 1, 1566720, 0x40f7d39a
+0, 80, 80, 1, 1566720, 0x40f7d39a
+0, 81, 81, 1, 1566720, 0x40f7d39a
+0, 82, 82, 1, 1566720, 0x40f7d39a
+0, 83, 83, 1, 1566720, 0x40f7d39a
+0, 84, 84, 1, 1566720, 0x40f7d39a
+0, 85, 85, 1, 1566720, 0x40f7d39a
0, 86, 86, 1, 1566720, 0xa7d6e25f
0, 87, 87, 1, 1566720, 0xa7d6e25f
0, 88, 88, 1, 1566720, 0xa7d6e25f
@@ -104,7 +103,6 @@
0, 98, 98, 1, 1566720, 0xa7d6e25f
0, 99, 99, 1, 1566720, 0xa7d6e25f
0, 100, 100, 1, 1566720, 0xeaf8d207
-0, 101, 101, 1, 1566720, 0x6724983e
0, 102, 102, 1, 1566720, 0x0e95d209
0, 103, 103, 1, 1566720, 0x0e95d209
0, 104, 104, 1, 1566720, 0x0e95d209
@@ -121,6 +119,4 @@
0, 115, 115, 1, 1566720, 0xfe83b964
0, 116, 116, 1, 1566720, 0xfe83b964
0, 117, 117, 1, 1566720, 0xfe83b964
-0, 118, 118, 1, 1566720, 0x25dc30a6
-0, 119, 119, 1, 1566720, 0x25dc30a6
-0, 120, 120, 1, 1566720, 0x25dc30a6
+0, 119, 119, 1, 1566720, 0xfe83b964
--
2.30.2
[-- Attachment #3: Type: text/plain, Size: 251 bytes --]
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [FFmpeg-devel] [PATCH v3] Add avpriv_slicethread_create2() and avpriv_slicethread_execute2(), make execute() and execute2() return FFMIN() of thread return codes
2022-09-26 13:46 [FFmpeg-devel] [PATCH v3] Add avpriv_slicethread_create2() and avpriv_slicethread_execute2(), make execute() and execute2() return FFMIN() of thread return codes Tomas Härdin
@ 2022-09-26 13:50 ` Andreas Rheinhardt
2022-09-26 13:54 ` James Almer
2022-09-26 13:58 ` Andreas Rheinhardt
1 sibling, 1 reply; 9+ messages in thread
From: Andreas Rheinhardt @ 2022-09-26 13:50 UTC (permalink / raw)
To: ffmpeg-devel
Tomas Härdin:
> diff --git a/doc/APIchanges b/doc/APIchanges
> index b0a41c9e37..240e549a2f 100644
> --- a/doc/APIchanges
> +++ b/doc/APIchanges
> @@ -14,6 +14,10 @@ libavutil: 2021-04-27
>
> API changes, most recent first:
>
> +2022-09-26 - xxxxxxxxxx - lavu 57.38.100 - slicethread.h
> + Deprecate avpriv_slicethread_create() and avpriv_slicethread_execute().
> + Add avpriv_slicethread_create2() and avpriv_slicethread_execute2().
> +
This is not public API and therefore no entry in APIchanges is necessary
or warranted.
> 2022-09-26 - xxxxxxxxxx - lavc 59.48.100 - avcodec.h
> Deprecate avcodec_enum_to_chroma_pos() and avcodec_chroma_pos_to_enum().
> Use av_chroma_location_enum_to_pos() or av_chroma_location_pos_to_enum()
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [FFmpeg-devel] [PATCH v3] Add avpriv_slicethread_create2() and avpriv_slicethread_execute2(), make execute() and execute2() return FFMIN() of thread return codes
2022-09-26 13:50 ` Andreas Rheinhardt
@ 2022-09-26 13:54 ` James Almer
2022-09-26 14:14 ` Tomas Härdin
0 siblings, 1 reply; 9+ messages in thread
From: James Almer @ 2022-09-26 13:54 UTC (permalink / raw)
To: ffmpeg-devel
On 9/26/2022 10:50 AM, Andreas Rheinhardt wrote:
> Tomas Härdin:
>> diff --git a/doc/APIchanges b/doc/APIchanges
>> index b0a41c9e37..240e549a2f 100644
>> --- a/doc/APIchanges
>> +++ b/doc/APIchanges
>> @@ -14,6 +14,10 @@ libavutil: 2021-04-27
>>
>> API changes, most recent first:
>>
>> +2022-09-26 - xxxxxxxxxx - lavu 57.38.100 - slicethread.h
>> + Deprecate avpriv_slicethread_create() and avpriv_slicethread_execute().
>> + Add avpriv_slicethread_create2() and avpriv_slicethread_execute2().
>> +
>
> This is not public API and therefore no entry in APIchanges is necessary
> or warranted.
And for the same reason there's no need to use the deprecated attribute
on them.
Also, maybe wrap all the old stuff in LIBAVUTIL_VERSION_MAJOR < 58
checks so they are disabled gone as soon as we bump major, or at least
make some noise so we don't forget about it.
>
>> 2022-09-26 - xxxxxxxxxx - lavc 59.48.100 - avcodec.h
>> Deprecate avcodec_enum_to_chroma_pos() and avcodec_chroma_pos_to_enum().
>> Use av_chroma_location_enum_to_pos() or av_chroma_location_pos_to_enum()
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [FFmpeg-devel] [PATCH v3] Add avpriv_slicethread_create2() and avpriv_slicethread_execute2(), make execute() and execute2() return FFMIN() of thread return codes
2022-09-26 13:46 [FFmpeg-devel] [PATCH v3] Add avpriv_slicethread_create2() and avpriv_slicethread_execute2(), make execute() and execute2() return FFMIN() of thread return codes Tomas Härdin
2022-09-26 13:50 ` Andreas Rheinhardt
@ 2022-09-26 13:58 ` Andreas Rheinhardt
2022-09-26 14:01 ` Andreas Rheinhardt
2022-09-26 14:02 ` Tomas Härdin
1 sibling, 2 replies; 9+ messages in thread
From: Andreas Rheinhardt @ 2022-09-26 13:58 UTC (permalink / raw)
To: ffmpeg-devel
Tomas Härdin:
> diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h
> index abeebbb002..50e73c86fa 100644
> --- a/libswscale/swscale_internal.h
> +++ b/libswscale/swscale_internal.h
> @@ -306,7 +306,7 @@ typedef struct SwsContext {
>
> AVSliceThread *slicethread;
> struct SwsContext **slice_ctx;
> - int *slice_err;
> + attribute_deprecated int *slice_err; ///< @deprecated Not used any more. Removing it would require a bunch of asm to be rewritten.
> int nb_slice_ctx;
>
> // values passed to current sws_receive_slice() call
What asm would need to be rewritten? (I presume that no asm code
accesses slice_err, because doing so would be insane and because you
already stop allocating slice_err in this patch. Is it because of
hardcoded offsets of other fields? Which fields? Why is there no
corresponding AV_CHECK_OFFSET for them?)
Anyway, we don't deprecate internal fields; if we have to keep them
around for ABI compatibility, we wrap them in #if LIBFOO_VERSION_MAJOR <
BAR.
- Andreas
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [FFmpeg-devel] [PATCH v3] Add avpriv_slicethread_create2() and avpriv_slicethread_execute2(), make execute() and execute2() return FFMIN() of thread return codes
2022-09-26 13:58 ` Andreas Rheinhardt
@ 2022-09-26 14:01 ` Andreas Rheinhardt
2022-09-26 14:02 ` Tomas Härdin
1 sibling, 0 replies; 9+ messages in thread
From: Andreas Rheinhardt @ 2022-09-26 14:01 UTC (permalink / raw)
To: ffmpeg-devel
Andreas Rheinhardt:
> Tomas Härdin:
>> diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h
>> index abeebbb002..50e73c86fa 100644
>> --- a/libswscale/swscale_internal.h
>> +++ b/libswscale/swscale_internal.h
>> @@ -306,7 +306,7 @@ typedef struct SwsContext {
>>
>> AVSliceThread *slicethread;
>> struct SwsContext **slice_ctx;
>> - int *slice_err;
>> + attribute_deprecated int *slice_err; ///< @deprecated Not used any more. Removing it would require a bunch of asm to be rewritten.
>> int nb_slice_ctx;
>>
>> // values passed to current sws_receive_slice() call
>
> What asm would need to be rewritten? (I presume that no asm code
> accesses slice_err, because doing so would be insane and because you
> already stop allocating slice_err in this patch. Is it because of
> hardcoded offsets of other fields? Which fields? Why is there no
> corresponding AV_CHECK_OFFSET for them?)
>
> Anyway, we don't deprecate internal fields; if we have to keep them
> around for ABI compatibility, we wrap them in #if LIBFOO_VERSION_MAJOR <
> BAR.
>
Ok, just moving this led me to the issue: An assert in line 751 of
libswscale/x86/swscale.c.
This is actually very frightening. A dev who does not use x86 could
break x86 any time.
- Andreas
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [FFmpeg-devel] [PATCH v3] Add avpriv_slicethread_create2() and avpriv_slicethread_execute2(), make execute() and execute2() return FFMIN() of thread return codes
2022-09-26 13:58 ` Andreas Rheinhardt
2022-09-26 14:01 ` Andreas Rheinhardt
@ 2022-09-26 14:02 ` Tomas Härdin
2022-09-26 14:28 ` Andreas Rheinhardt
1 sibling, 1 reply; 9+ messages in thread
From: Tomas Härdin @ 2022-09-26 14:02 UTC (permalink / raw)
To: FFmpeg development discussions and patches
mån 2022-09-26 klockan 15:58 +0200 skrev Andreas Rheinhardt:
> Tomas Härdin:
> > diff --git a/libswscale/swscale_internal.h
> > b/libswscale/swscale_internal.h
> > index abeebbb002..50e73c86fa 100644
> > --- a/libswscale/swscale_internal.h
> > +++ b/libswscale/swscale_internal.h
> > @@ -306,7 +306,7 @@ typedef struct SwsContext {
> >
> > AVSliceThread *slicethread;
> > struct SwsContext **slice_ctx;
> > - int *slice_err;
> > + attribute_deprecated int *slice_err; ///< @deprecated Not used
> > any more. Removing it would require a bunch of asm to be rewritten.
> > int nb_slice_ctx;
> >
> > // values passed to current sws_receive_slice() call
>
> What asm would need to be rewritten?
swscale.c:
/* yuv2gbrp uses the SwsContext for yuv coefficients
if struct offsets change the asm needs to be updated too */
av_assert0(offsetof(SwsContext, yuv2rgb_y_offset) == 40292);
> Anyway, we don't deprecate internal fields; if we have to keep them
> around for ABI compatibility, we wrap them in #if
> LIBFOO_VERSION_MAJOR <
> BAR.
It's not actually an API/ABI issue but an asm issue
/Tomas
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [FFmpeg-devel] [PATCH v3] Add avpriv_slicethread_create2() and avpriv_slicethread_execute2(), make execute() and execute2() return FFMIN() of thread return codes
2022-09-26 13:54 ` James Almer
@ 2022-09-26 14:14 ` Tomas Härdin
0 siblings, 0 replies; 9+ messages in thread
From: Tomas Härdin @ 2022-09-26 14:14 UTC (permalink / raw)
To: FFmpeg development discussions and patches
[-- Attachment #1: Type: text/plain, Size: 1055 bytes --]
mån 2022-09-26 klockan 10:54 -0300 skrev James Almer:
> On 9/26/2022 10:50 AM, Andreas Rheinhardt wrote:
> > Tomas Härdin:
> > > diff --git a/doc/APIchanges b/doc/APIchanges
> > > index b0a41c9e37..240e549a2f 100644
> > > --- a/doc/APIchanges
> > > +++ b/doc/APIchanges
> > > @@ -14,6 +14,10 @@ libavutil: 2021-04-27
> > >
> > > API changes, most recent first:
> > >
> > > +2022-09-26 - xxxxxxxxxx - lavu 57.38.100 - slicethread.h
> > > + Deprecate avpriv_slicethread_create() and
> > > avpriv_slicethread_execute().
> > > + Add avpriv_slicethread_create2() and
> > > avpriv_slicethread_execute2().
> > > +
> >
> > This is not public API and therefore no entry in APIchanges is
> > necessary
> > or warranted.
>
> And for the same reason there's no need to use the deprecated
> attribute
> on them.
>
> Also, maybe wrap all the old stuff in LIBAVUTIL_VERSION_MAJOR < 58
> checks so they are disabled gone as soon as we bump major, or at
> least
> make some noise so we don't forget about it.
Updated patch attached
/Tomas
[-- Attachment #2: 0001-Add-avpriv_slicethread_create2-and-avpriv_slicethrea.patch --]
[-- Type: text/x-patch, Size: 22283 bytes --]
From 3199f1d9feb37f4d304678a57169ee563ecbab41 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= <git@haerdin.se>
Date: Thu, 16 Jun 2022 12:16:44 +0200
Subject: [PATCH] Add avpriv_slicethread_create2() and
avpriv_slicethread_execute2(), make execute() and execute2() return FFMIN()
of thread return codes
Updates all internal uses of related APIs.
At the moment only fic.c actually checks return code of execute() hence the change to its FATE reference.
---
libavcodec/avcodec.c | 10 +++--
libavcodec/pthread_slice.c | 14 +++----
libavfilter/pthread.c | 8 ++--
libavutil/slicethread.c | 74 ++++++++++++++++++++++++++++++++---
libavutil/slicethread.h | 27 +++++++++++++
libavutil/version.h | 2 +-
libswscale/swscale.c | 20 ++--------
libswscale/swscale_internal.h | 6 +--
libswscale/utils.c | 8 ++--
tests/fate/screen.mak | 1 +
tests/ref/fate/fic-avi | 30 ++++++--------
11 files changed, 137 insertions(+), 63 deletions(-)
diff --git a/libavcodec/avcodec.c b/libavcodec/avcodec.c
index a85d3c2309..ee75b3abe7 100644
--- a/libavcodec/avcodec.c
+++ b/libavcodec/avcodec.c
@@ -44,28 +44,30 @@
int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2), void *arg, int *ret, int count, int size)
{
- int i;
+ int i, rr = 0;
for (i = 0; i < count; i++) {
int r = func(c, (char *)arg + i * size);
+ rr = FFMIN(rr, r);
if (ret)
ret[i] = r;
}
emms_c();
- return 0;
+ return rr;
}
int avcodec_default_execute2(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2, int jobnr, int threadnr), void *arg, int *ret, int count)
{
- int i;
+ int i, rr = 0;
for (i = 0; i < count; i++) {
int r = func(c, arg, i, 0);
+ rr = FFMIN(rr, r);
if (ret)
ret[i] = r;
}
emms_c();
- return 0;
+ return rr;
}
static AVMutex codec_mutex = AV_MUTEX_INITIALIZER;
diff --git a/libavcodec/pthread_slice.c b/libavcodec/pthread_slice.c
index a4d31c6f4d..795d0c9c5a 100644
--- a/libavcodec/pthread_slice.c
+++ b/libavcodec/pthread_slice.c
@@ -61,13 +61,13 @@ typedef struct SliceThreadContext {
Progress *progress;
} SliceThreadContext;
-static void main_function(void *priv) {
+static int main_function(void *priv) {
AVCodecContext *avctx = priv;
SliceThreadContext *c = avctx->internal->thread_ctx;
- c->mainfunc(avctx);
+ return c->mainfunc(avctx);
}
-static void worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
+static int worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
{
AVCodecContext *avctx = priv;
SliceThreadContext *c = avctx->internal->thread_ctx;
@@ -77,6 +77,7 @@ static void worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb
: c->func2(avctx, c->args, jobnr, threadnr);
if (c->rets)
c->rets[jobnr] = ret;
+ return ret;
}
void ff_slice_thread_free(AVCodecContext *avctx)
@@ -112,8 +113,7 @@ static int thread_execute(AVCodecContext *avctx, action_func* func, void *arg, i
c->func = func;
c->rets = ret;
- avpriv_slicethread_execute(c->thread, job_count, !!c->mainfunc );
- return 0;
+ return avpriv_slicethread_execute2(c->thread, job_count, !!c->mainfunc);
}
static int thread_execute2(AVCodecContext *avctx, action_func2* func2, void *arg, int *ret, int job_count)
@@ -135,7 +135,7 @@ int ff_slice_thread_init(AVCodecContext *avctx)
{
SliceThreadContext *c;
int thread_count = avctx->thread_count;
- void (*mainfunc)(void *);
+ int (*mainfunc)(void *);
// We cannot do this in the encoder init as the threads are created before
if (av_codec_is_encoder(avctx->codec) &&
@@ -161,7 +161,7 @@ int ff_slice_thread_init(AVCodecContext *avctx)
avctx->internal->thread_ctx = c = av_mallocz(sizeof(*c));
mainfunc = ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_SLICE_THREAD_HAS_MF ? &main_function : NULL;
- if (!c || (thread_count = avpriv_slicethread_create(&c->thread, avctx, worker_func, mainfunc, thread_count)) <= 1) {
+ if (!c || (thread_count = avpriv_slicethread_create2(&c->thread, avctx, worker_func, mainfunc, thread_count)) <= 1) {
if (c)
avpriv_slicethread_free(&c->thread);
av_freep(&avctx->internal->thread_ctx);
diff --git a/libavfilter/pthread.c b/libavfilter/pthread.c
index 1a063d3cc0..855c842df9 100644
--- a/libavfilter/pthread.c
+++ b/libavfilter/pthread.c
@@ -43,12 +43,13 @@ typedef struct ThreadContext {
int *rets;
} ThreadContext;
-static void worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
+static int worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
{
ThreadContext *c = priv;
int ret = c->func(c->ctx, c->arg, jobnr, nb_jobs);
if (c->rets)
c->rets[jobnr] = ret;
+ return ret;
}
static void slice_thread_uninit(ThreadContext *c)
@@ -68,13 +69,12 @@ static int thread_execute(AVFilterContext *ctx, avfilter_action_func *func,
c->func = func;
c->rets = ret;
- avpriv_slicethread_execute(c->thread, nb_jobs, 0);
- return 0;
+ return avpriv_slicethread_execute2(c->thread, nb_jobs, 0);
}
static int thread_init_internal(ThreadContext *c, int nb_threads)
{
- nb_threads = avpriv_slicethread_create(&c->thread, c, worker_func, NULL, nb_threads);
+ nb_threads = avpriv_slicethread_create2(&c->thread, c, worker_func, NULL, nb_threads);
if (nb_threads <= 1)
avpriv_slicethread_free(&c->thread);
return FFMAX(nb_threads, 1);
diff --git a/libavutil/slicethread.c b/libavutil/slicethread.c
index 115b099736..9ce58ffa64 100644
--- a/libavutil/slicethread.c
+++ b/libavutil/slicethread.c
@@ -34,6 +34,7 @@ typedef struct WorkerContext {
pthread_cond_t cond;
pthread_t thread;
int done;
+ int ret;
} WorkerContext;
struct AVSliceThread {
@@ -50,11 +51,15 @@ struct AVSliceThread {
int finished;
void *priv;
+ // either worker_func and main_func are non-NULL or worker_func2 and main_func2 are
+ // all four are never non-NULL at the same time
void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads);
void (*main_func)(void *priv);
+ int (*worker_func2)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads);
+ int (*main_func2)(void *priv);
};
-static int run_jobs(AVSliceThread *ctx)
+static int run_jobs(AVSliceThread *ctx, int *ret_out)
{
unsigned nb_jobs = ctx->nb_jobs;
unsigned nb_active_threads = ctx->nb_active_threads;
@@ -62,7 +67,12 @@ static int run_jobs(AVSliceThread *ctx)
unsigned current_job = first_job;
do {
- ctx->worker_func(ctx->priv, current_job, first_job, nb_jobs, nb_active_threads);
+ if (ctx->worker_func2) {
+ int ret = ctx->worker_func2(ctx->priv, current_job, first_job, nb_jobs, nb_active_threads);
+ *ret_out = FFMIN(*ret_out, ret);
+ } else {
+ ctx->worker_func(ctx->priv, current_job, first_job, nb_jobs, nb_active_threads);
+ }
} while ((current_job = atomic_fetch_add_explicit(&ctx->current_job, 1, memory_order_acq_rel)) < nb_jobs);
return current_job == nb_jobs + nb_active_threads - 1;
@@ -86,7 +96,7 @@ static void *attribute_align_arg thread_worker(void *v)
return NULL;
}
- if (run_jobs(ctx)) {
+ if (run_jobs(ctx, &w->ret)) {
pthread_mutex_lock(&ctx->done_mutex);
ctx->done = 1;
pthread_cond_signal(&ctx->done_cond);
@@ -95,9 +105,11 @@ static void *attribute_align_arg thread_worker(void *v)
}
}
-int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
+static int slicethread_create(AVSliceThread **pctx, void *priv,
void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
void (*main_func)(void *priv),
+ int (*worker_func2)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
+ int (*main_func2)(void *priv),
int nb_threads)
{
AVSliceThread *ctx;
@@ -128,6 +140,8 @@ int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
ctx->priv = priv;
ctx->worker_func = worker_func;
ctx->main_func = main_func;
+ ctx->worker_func2= worker_func2;
+ ctx->main_func2 = main_func2;
ctx->nb_threads = nb_threads;
ctx->nb_active_threads = 0;
ctx->nb_jobs = 0;
@@ -165,9 +179,34 @@ int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
return nb_threads;
}
+#if LIBAVUTIL_VERSION_MAJOR < 58
+int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
+ void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
+ void (*main_func)(void *priv),
+ int nb_threads)
+{
+ return slicethread_create(pctx, priv, worker_func, main_func, NULL, NULL, nb_threads);
+}
+#endif // LIBAVUTIL_VERSION_MAJOR
+
+int avpriv_slicethread_create2(AVSliceThread **pctx, void *priv,
+ int (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
+ int (*main_func)(void *priv),
+ int nb_threads)
+{
+ return slicethread_create(pctx, priv, NULL, NULL, worker_func, main_func, nb_threads);
+}
+
+#if LIBAVUTIL_VERSION_MAJOR < 58
void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main)
{
- int nb_workers, i, is_last = 0;
+ (void)avpriv_slicethread_execute2(ctx, nb_jobs, execute_main);
+}
+#endif // LIBAVUTIL_VERSION_MAJOR
+
+int avpriv_slicethread_execute2(AVSliceThread *ctx, int nb_jobs, int execute_main)
+{
+ int nb_workers, i, is_last = 0, ret = 0;
av_assert0(nb_jobs > 0);
ctx->nb_jobs = nb_jobs;
@@ -182,14 +221,17 @@ void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_mai
WorkerContext *w = &ctx->workers[i];
pthread_mutex_lock(&w->mutex);
w->done = 0;
+ w->ret = 0;
pthread_cond_signal(&w->cond);
pthread_mutex_unlock(&w->mutex);
}
if (ctx->main_func && execute_main)
ctx->main_func(ctx->priv);
+ else if (ctx->main_func2 && execute_main)
+ ret = ctx->main_func2(ctx->priv);
else
- is_last = run_jobs(ctx);
+ is_last = run_jobs(ctx, &ret);
if (!is_last) {
pthread_mutex_lock(&ctx->done_mutex);
@@ -198,6 +240,11 @@ void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_mai
ctx->done = 0;
pthread_mutex_unlock(&ctx->done_mutex);
}
+
+ for (i = 0; i < nb_workers; i++)
+ ret = FFMIN(ret, ctx->workers[i].ret);
+
+ return ret;
}
void avpriv_slicethread_free(AVSliceThread **pctx)
@@ -246,11 +293,26 @@ int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
return AVERROR(ENOSYS);
}
+int avpriv_slicethread_create2(AVSliceThread **pctx, void *priv,
+ int (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
+ int (*main_func)(void *priv),
+ int nb_threads)
+{
+ *pctx = NULL;
+ return AVERROR(ENOSYS);
+}
+
void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main)
{
av_assert0(0);
}
+int avpriv_slicethread_execute2(AVSliceThread *ctx, int nb_jobs, int execute_main)
+{
+ av_assert0(0);
+ return AVERROR(ENOSYS);
+}
+
void avpriv_slicethread_free(AVSliceThread **pctx)
{
av_assert0(!pctx || !*pctx);
diff --git a/libavutil/slicethread.h b/libavutil/slicethread.h
index f6f6f302c4..912ea13ce0 100644
--- a/libavutil/slicethread.h
+++ b/libavutil/slicethread.h
@@ -21,6 +21,7 @@
typedef struct AVSliceThread AVSliceThread;
+#if LIBAVUTIL_VERSION_MAJOR < 58
/**
* Create slice threading context.
* @param pctx slice threading context returned here
@@ -34,7 +35,23 @@ int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
void (*main_func)(void *priv),
int nb_threads);
+#endif // LIBAVUTIL_VERSION_MAJOR
+/**
+ * Like avpriv_slicethread_create() except worker_func and main_func return int.
+ * @param pctx slice threading context returned here
+ * @param priv private pointer to be passed to callback function
+ * @param worker_func callback function to be executed
+ * @param main_func special callback function, called from main thread, may be NULL
+ * @param nb_threads number of threads, 0 for automatic, must be >= 0
+ * @return return number of threads or negative AVERROR on failure
+ */
+int avpriv_slicethread_create2(AVSliceThread **pctx, void *priv,
+ int (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
+ int (*main_func)(void *priv),
+ int nb_threads);
+
+#if LIBAVUTIL_VERSION_MAJOR < 58
/**
* Execute slice threading.
* @param ctx slice threading context
@@ -42,6 +59,16 @@ int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
* @param execute_main also execute main_func
*/
void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main);
+#endif // LIBAVUTIL_VERSION_MAJOR
+
+/**
+ * Like avpriv_slicethread_execute() except returns FFMIN(0, main_func(), worker_func()).
+ * @param ctx slice threading context
+ * @param nb_jobs number of jobs, must be > 0
+ * @param execute_main also execute main_func
+ * @return AVERROR on error.
+ */
+int avpriv_slicethread_execute2(AVSliceThread *ctx, int nb_jobs, int execute_main);
/**
* Destroy slice threading context.
diff --git a/libavutil/version.h b/libavutil/version.h
index 9c44cef6aa..5aca550f45 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -79,7 +79,7 @@
*/
#define LIBAVUTIL_VERSION_MAJOR 57
-#define LIBAVUTIL_VERSION_MINOR 37
+#define LIBAVUTIL_VERSION_MINOR 38
#define LIBAVUTIL_VERSION_MICRO 100
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
diff --git a/libswscale/swscale.c b/libswscale/swscale.c
index 367d045a02..500b74c099 100644
--- a/libswscale/swscale.c
+++ b/libswscale/swscale.c
@@ -1150,23 +1150,11 @@ int sws_receive_slice(struct SwsContext *c, unsigned int slice_start,
if (c->slicethread) {
int nb_jobs = c->slice_ctx[0]->dither == SWS_DITHER_ED ? 1 : c->nb_slice_ctx;
- int ret = 0;
c->dst_slice_start = slice_start;
c->dst_slice_height = slice_height;
- avpriv_slicethread_execute(c->slicethread, nb_jobs, 0);
-
- for (int i = 0; i < c->nb_slice_ctx; i++) {
- if (c->slice_err[i] < 0) {
- ret = c->slice_err[i];
- break;
- }
- }
-
- memset(c->slice_err, 0, c->nb_slice_ctx * sizeof(*c->slice_err));
-
- return ret;
+ return avpriv_slicethread_execute2(c->slicethread, nb_jobs, 0);
}
for (int i = 0; i < FF_ARRAY_ELEMS(dst); i++) {
@@ -1213,8 +1201,8 @@ int attribute_align_arg sws_scale(struct SwsContext *c,
dst, dstStride, 0, c->dstH);
}
-void ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
- int nb_jobs, int nb_threads)
+int ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
+ int nb_jobs, int nb_threads)
{
SwsContext *parent = priv;
SwsContext *c = parent->slice_ctx[threadnr];
@@ -1242,5 +1230,5 @@ void ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
parent->dst_slice_start + slice_start, slice_end - slice_start);
}
- parent->slice_err[threadnr] = err;
+ return err;
}
diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h
index abeebbb002..50e73c86fa 100644
--- a/libswscale/swscale_internal.h
+++ b/libswscale/swscale_internal.h
@@ -306,7 +306,7 @@ typedef struct SwsContext {
AVSliceThread *slicethread;
struct SwsContext **slice_ctx;
- int *slice_err;
+ attribute_deprecated int *slice_err; ///< @deprecated Not used any more. Removing it would require a bunch of asm to be rewritten.
int nb_slice_ctx;
// values passed to current sws_receive_slice() call
@@ -1152,8 +1152,8 @@ void ff_init_vscale_pfn(SwsContext *c, yuv2planar1_fn yuv2plane1, yuv2planarX_fn
yuv2interleavedX_fn yuv2nv12cX, yuv2packed1_fn yuv2packed1, yuv2packed2_fn yuv2packed2,
yuv2packedX_fn yuv2packedX, yuv2anyX_fn yuv2anyX, int use_mmx);
-void ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
- int nb_jobs, int nb_threads);
+int ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
+ int nb_jobs, int nb_threads);
//number of extra lines to process
#define MAX_LINES_AHEAD 4
diff --git a/libswscale/utils.c b/libswscale/utils.c
index 45baa22b23..8bfd3a64ac 100644
--- a/libswscale/utils.c
+++ b/libswscale/utils.c
@@ -1273,8 +1273,8 @@ static int context_init_threaded(SwsContext *c,
{
int ret;
- ret = avpriv_slicethread_create(&c->slicethread, (void*)c,
- ff_sws_slice_worker, NULL, c->nb_threads);
+ ret = avpriv_slicethread_create2(&c->slicethread, (void*)c,
+ ff_sws_slice_worker, NULL, c->nb_threads);
if (ret == AVERROR(ENOSYS)) {
c->nb_threads = 1;
return 0;
@@ -1284,8 +1284,7 @@ static int context_init_threaded(SwsContext *c,
c->nb_threads = ret;
c->slice_ctx = av_calloc(c->nb_threads, sizeof(*c->slice_ctx));
- c->slice_err = av_calloc(c->nb_threads, sizeof(*c->slice_err));
- if (!c->slice_ctx || !c->slice_err)
+ if (!c->slice_ctx)
return AVERROR(ENOMEM);
for (int i = 0; i < c->nb_threads; i++) {
@@ -2421,7 +2420,6 @@ void sws_freeContext(SwsContext *c)
for (i = 0; i < c->nb_slice_ctx; i++)
sws_freeContext(c->slice_ctx[i]);
av_freep(&c->slice_ctx);
- av_freep(&c->slice_err);
avpriv_slicethread_free(&c->slicethread);
diff --git a/tests/fate/screen.mak b/tests/fate/screen.mak
index bd6d228544..b572f67b55 100644
--- a/tests/fate/screen.mak
+++ b/tests/fate/screen.mak
@@ -5,6 +5,7 @@ fate-cscd: CMD = framecrc -i $(TARGET_SAMPLES)/CSCD/sample_video.avi -an -pix_fm
FATE_SCREEN-$(call FRAMECRC, AVI, DXTORY) += fate-dxtory
fate-dxtory: CMD = framecrc -i $(TARGET_SAMPLES)/dxtory/dxtory_mic.avi -an
+# fic sample is broken. some packets are truncated and one packet has length zero
FATE_SCREEN-$(call FRAMECRC, AVI, FIC) += fate-fic-avi
fate-fic-avi: CMD = framecrc -i $(TARGET_SAMPLES)/fic/fic-partial-2MB.avi -an
diff --git a/tests/ref/fate/fic-avi b/tests/ref/fate/fic-avi
index df55789d54..4546f230b1 100644
--- a/tests/ref/fate/fic-avi
+++ b/tests/ref/fate/fic-avi
@@ -76,19 +76,18 @@
0, 70, 70, 1, 1566720, 0x40f7d39a
0, 71, 71, 1, 1566720, 0x40f7d39a
0, 72, 72, 1, 1566720, 0x40f7d39a
-0, 73, 73, 1, 1566720, 0xa7d6e25f
-0, 74, 74, 1, 1566720, 0xa7d6e25f
-0, 75, 75, 1, 1566720, 0xa7d6e25f
-0, 76, 76, 1, 1566720, 0xa7d6e25f
-0, 77, 77, 1, 1566720, 0xa7d6e25f
-0, 78, 78, 1, 1566720, 0xa7d6e25f
-0, 79, 79, 1, 1566720, 0xa7d6e25f
-0, 80, 80, 1, 1566720, 0xa7d6e25f
-0, 81, 81, 1, 1566720, 0xa7d6e25f
-0, 82, 82, 1, 1566720, 0xa7d6e25f
-0, 83, 83, 1, 1566720, 0xa7d6e25f
-0, 84, 84, 1, 1566720, 0xa7d6e25f
-0, 85, 85, 1, 1566720, 0xa7d6e25f
+0, 74, 74, 1, 1566720, 0x40f7d39a
+0, 75, 75, 1, 1566720, 0x40f7d39a
+0, 76, 76, 1, 1566720, 0x40f7d39a
+0, 77, 77, 1, 1566720, 0x40f7d39a
+0, 78, 78, 1, 1566720, 0x40f7d39a
+0, 79, 79, 1, 1566720, 0x40f7d39a
+0, 80, 80, 1, 1566720, 0x40f7d39a
+0, 81, 81, 1, 1566720, 0x40f7d39a
+0, 82, 82, 1, 1566720, 0x40f7d39a
+0, 83, 83, 1, 1566720, 0x40f7d39a
+0, 84, 84, 1, 1566720, 0x40f7d39a
+0, 85, 85, 1, 1566720, 0x40f7d39a
0, 86, 86, 1, 1566720, 0xa7d6e25f
0, 87, 87, 1, 1566720, 0xa7d6e25f
0, 88, 88, 1, 1566720, 0xa7d6e25f
@@ -104,7 +103,6 @@
0, 98, 98, 1, 1566720, 0xa7d6e25f
0, 99, 99, 1, 1566720, 0xa7d6e25f
0, 100, 100, 1, 1566720, 0xeaf8d207
-0, 101, 101, 1, 1566720, 0x6724983e
0, 102, 102, 1, 1566720, 0x0e95d209
0, 103, 103, 1, 1566720, 0x0e95d209
0, 104, 104, 1, 1566720, 0x0e95d209
@@ -121,6 +119,4 @@
0, 115, 115, 1, 1566720, 0xfe83b964
0, 116, 116, 1, 1566720, 0xfe83b964
0, 117, 117, 1, 1566720, 0xfe83b964
-0, 118, 118, 1, 1566720, 0x25dc30a6
-0, 119, 119, 1, 1566720, 0x25dc30a6
-0, 120, 120, 1, 1566720, 0x25dc30a6
+0, 119, 119, 1, 1566720, 0xfe83b964
--
2.30.2
[-- Attachment #3: Type: text/plain, Size: 251 bytes --]
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [FFmpeg-devel] [PATCH v3] Add avpriv_slicethread_create2() and avpriv_slicethread_execute2(), make execute() and execute2() return FFMIN() of thread return codes
2022-09-26 14:02 ` Tomas Härdin
@ 2022-09-26 14:28 ` Andreas Rheinhardt
2022-09-26 14:44 ` Tomas Härdin
0 siblings, 1 reply; 9+ messages in thread
From: Andreas Rheinhardt @ 2022-09-26 14:28 UTC (permalink / raw)
To: ffmpeg-devel
Tomas Härdin:
> mån 2022-09-26 klockan 15:58 +0200 skrev Andreas Rheinhardt:
>> Tomas Härdin:
>>> diff --git a/libswscale/swscale_internal.h
>>> b/libswscale/swscale_internal.h
>>> index abeebbb002..50e73c86fa 100644
>>> --- a/libswscale/swscale_internal.h
>>> +++ b/libswscale/swscale_internal.h
>>> @@ -306,7 +306,7 @@ typedef struct SwsContext {
>>>
>>> AVSliceThread *slicethread;
>>> struct SwsContext **slice_ctx;
>>> - int *slice_err;
>>> + attribute_deprecated int *slice_err; ///< @deprecated Not used
>>> any more. Removing it would require a bunch of asm to be rewritten.
>>> int nb_slice_ctx;
>>>
>>> // values passed to current sws_receive_slice() call
>>
>> What asm would need to be rewritten?
>
> swscale.c:
> /* yuv2gbrp uses the SwsContext for yuv coefficients
> if struct offsets change the asm needs to be updated too */
> av_assert0(offsetof(SwsContext, yuv2rgb_y_offset) == 40292);
>
>
>> Anyway, we don't deprecate internal fields; if we have to keep them
>> around for ABI compatibility, we wrap them in #if
>> LIBFOO_VERSION_MAJOR <
>> BAR.
>
> It's not actually an API/ABI issue but an asm issue
>
It seems to me that this is the only such issue that affects this patch.
If you modified line 583 of libswscale/x86/output.asm as well as the
assert, you could remove slice_err. (But let James confirm this.)
- Andreas
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [FFmpeg-devel] [PATCH v3] Add avpriv_slicethread_create2() and avpriv_slicethread_execute2(), make execute() and execute2() return FFMIN() of thread return codes
2022-09-26 14:28 ` Andreas Rheinhardt
@ 2022-09-26 14:44 ` Tomas Härdin
0 siblings, 0 replies; 9+ messages in thread
From: Tomas Härdin @ 2022-09-26 14:44 UTC (permalink / raw)
To: FFmpeg development discussions and patches
[-- Attachment #1: Type: text/plain, Size: 1807 bytes --]
mån 2022-09-26 klockan 16:28 +0200 skrev Andreas Rheinhardt:
> Tomas Härdin:
> > mån 2022-09-26 klockan 15:58 +0200 skrev Andreas Rheinhardt:
> > > Tomas Härdin:
> > > > diff --git a/libswscale/swscale_internal.h
> > > > b/libswscale/swscale_internal.h
> > > > index abeebbb002..50e73c86fa 100644
> > > > --- a/libswscale/swscale_internal.h
> > > > +++ b/libswscale/swscale_internal.h
> > > > @@ -306,7 +306,7 @@ typedef struct SwsContext {
> > > >
> > > > AVSliceThread *slicethread;
> > > > struct SwsContext **slice_ctx;
> > > > - int *slice_err;
> > > > + attribute_deprecated int *slice_err; ///< @deprecated Not
> > > > used
> > > > any more. Removing it would require a bunch of asm to be
> > > > rewritten.
> > > > int nb_slice_ctx;
> > > >
> > > > // values passed to current sws_receive_slice() call
> > >
> > > What asm would need to be rewritten?
> >
> > swscale.c:
> > /* yuv2gbrp uses the SwsContext for yuv coefficients
> > if struct offsets change the asm needs to be updated too
> > */
> > av_assert0(offsetof(SwsContext, yuv2rgb_y_offset) ==
> > 40292);
> >
> >
> > > Anyway, we don't deprecate internal fields; if we have to keep
> > > them
> > > around for ABI compatibility, we wrap them in #if
> > > LIBFOO_VERSION_MAJOR <
> > > BAR.
> >
> > It's not actually an API/ABI issue but an asm issue
> >
>
> It seems to me that this is the only such issue that affects this
> patch.
> If you modified line 583 of libswscale/x86/output.asm as well as the
> assert, you could remove slice_err. (But let James confirm this.)
Here's a yet further updated patch with this change implemented. Passes
FATE.
/Tomas
[-- Attachment #2: 0001-Add-avpriv_slicethread_create2-and-avpriv_slicethrea.patch --]
[-- Type: text/x-patch, Size: 23322 bytes --]
From 03bc38e6575f2f742157ed23608848b38b04bf6c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= <git@haerdin.se>
Date: Thu, 16 Jun 2022 12:16:44 +0200
Subject: [PATCH] Add avpriv_slicethread_create2() and
avpriv_slicethread_execute2(), make execute() and execute2() return FFMIN()
of thread return codes
Updates all internal uses of related APIs.
At the moment only fic.c actually checks return code of execute() hence the change to its FATE reference.
---
libavcodec/avcodec.c | 10 +++--
libavcodec/pthread_slice.c | 14 +++----
libavfilter/pthread.c | 8 ++--
libavutil/slicethread.c | 74 ++++++++++++++++++++++++++++++++---
libavutil/slicethread.h | 27 +++++++++++++
libavutil/version.h | 2 +-
libswscale/swscale.c | 20 ++--------
libswscale/swscale_internal.h | 5 +--
libswscale/utils.c | 8 ++--
libswscale/x86/output.asm | 2 +-
libswscale/x86/swscale.c | 2 +-
tests/fate/screen.mak | 1 +
tests/ref/fate/fic-avi | 30 ++++++--------
13 files changed, 138 insertions(+), 65 deletions(-)
diff --git a/libavcodec/avcodec.c b/libavcodec/avcodec.c
index a85d3c2309..ee75b3abe7 100644
--- a/libavcodec/avcodec.c
+++ b/libavcodec/avcodec.c
@@ -44,28 +44,30 @@
int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2), void *arg, int *ret, int count, int size)
{
- int i;
+ int i, rr = 0;
for (i = 0; i < count; i++) {
int r = func(c, (char *)arg + i * size);
+ rr = FFMIN(rr, r);
if (ret)
ret[i] = r;
}
emms_c();
- return 0;
+ return rr;
}
int avcodec_default_execute2(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2, int jobnr, int threadnr), void *arg, int *ret, int count)
{
- int i;
+ int i, rr = 0;
for (i = 0; i < count; i++) {
int r = func(c, arg, i, 0);
+ rr = FFMIN(rr, r);
if (ret)
ret[i] = r;
}
emms_c();
- return 0;
+ return rr;
}
static AVMutex codec_mutex = AV_MUTEX_INITIALIZER;
diff --git a/libavcodec/pthread_slice.c b/libavcodec/pthread_slice.c
index a4d31c6f4d..795d0c9c5a 100644
--- a/libavcodec/pthread_slice.c
+++ b/libavcodec/pthread_slice.c
@@ -61,13 +61,13 @@ typedef struct SliceThreadContext {
Progress *progress;
} SliceThreadContext;
-static void main_function(void *priv) {
+static int main_function(void *priv) {
AVCodecContext *avctx = priv;
SliceThreadContext *c = avctx->internal->thread_ctx;
- c->mainfunc(avctx);
+ return c->mainfunc(avctx);
}
-static void worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
+static int worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
{
AVCodecContext *avctx = priv;
SliceThreadContext *c = avctx->internal->thread_ctx;
@@ -77,6 +77,7 @@ static void worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb
: c->func2(avctx, c->args, jobnr, threadnr);
if (c->rets)
c->rets[jobnr] = ret;
+ return ret;
}
void ff_slice_thread_free(AVCodecContext *avctx)
@@ -112,8 +113,7 @@ static int thread_execute(AVCodecContext *avctx, action_func* func, void *arg, i
c->func = func;
c->rets = ret;
- avpriv_slicethread_execute(c->thread, job_count, !!c->mainfunc );
- return 0;
+ return avpriv_slicethread_execute2(c->thread, job_count, !!c->mainfunc);
}
static int thread_execute2(AVCodecContext *avctx, action_func2* func2, void *arg, int *ret, int job_count)
@@ -135,7 +135,7 @@ int ff_slice_thread_init(AVCodecContext *avctx)
{
SliceThreadContext *c;
int thread_count = avctx->thread_count;
- void (*mainfunc)(void *);
+ int (*mainfunc)(void *);
// We cannot do this in the encoder init as the threads are created before
if (av_codec_is_encoder(avctx->codec) &&
@@ -161,7 +161,7 @@ int ff_slice_thread_init(AVCodecContext *avctx)
avctx->internal->thread_ctx = c = av_mallocz(sizeof(*c));
mainfunc = ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_SLICE_THREAD_HAS_MF ? &main_function : NULL;
- if (!c || (thread_count = avpriv_slicethread_create(&c->thread, avctx, worker_func, mainfunc, thread_count)) <= 1) {
+ if (!c || (thread_count = avpriv_slicethread_create2(&c->thread, avctx, worker_func, mainfunc, thread_count)) <= 1) {
if (c)
avpriv_slicethread_free(&c->thread);
av_freep(&avctx->internal->thread_ctx);
diff --git a/libavfilter/pthread.c b/libavfilter/pthread.c
index 1a063d3cc0..855c842df9 100644
--- a/libavfilter/pthread.c
+++ b/libavfilter/pthread.c
@@ -43,12 +43,13 @@ typedef struct ThreadContext {
int *rets;
} ThreadContext;
-static void worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
+static int worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
{
ThreadContext *c = priv;
int ret = c->func(c->ctx, c->arg, jobnr, nb_jobs);
if (c->rets)
c->rets[jobnr] = ret;
+ return ret;
}
static void slice_thread_uninit(ThreadContext *c)
@@ -68,13 +69,12 @@ static int thread_execute(AVFilterContext *ctx, avfilter_action_func *func,
c->func = func;
c->rets = ret;
- avpriv_slicethread_execute(c->thread, nb_jobs, 0);
- return 0;
+ return avpriv_slicethread_execute2(c->thread, nb_jobs, 0);
}
static int thread_init_internal(ThreadContext *c, int nb_threads)
{
- nb_threads = avpriv_slicethread_create(&c->thread, c, worker_func, NULL, nb_threads);
+ nb_threads = avpriv_slicethread_create2(&c->thread, c, worker_func, NULL, nb_threads);
if (nb_threads <= 1)
avpriv_slicethread_free(&c->thread);
return FFMAX(nb_threads, 1);
diff --git a/libavutil/slicethread.c b/libavutil/slicethread.c
index 115b099736..9ce58ffa64 100644
--- a/libavutil/slicethread.c
+++ b/libavutil/slicethread.c
@@ -34,6 +34,7 @@ typedef struct WorkerContext {
pthread_cond_t cond;
pthread_t thread;
int done;
+ int ret;
} WorkerContext;
struct AVSliceThread {
@@ -50,11 +51,15 @@ struct AVSliceThread {
int finished;
void *priv;
+ // either worker_func and main_func are non-NULL or worker_func2 and main_func2 are
+ // all four are never non-NULL at the same time
void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads);
void (*main_func)(void *priv);
+ int (*worker_func2)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads);
+ int (*main_func2)(void *priv);
};
-static int run_jobs(AVSliceThread *ctx)
+static int run_jobs(AVSliceThread *ctx, int *ret_out)
{
unsigned nb_jobs = ctx->nb_jobs;
unsigned nb_active_threads = ctx->nb_active_threads;
@@ -62,7 +67,12 @@ static int run_jobs(AVSliceThread *ctx)
unsigned current_job = first_job;
do {
- ctx->worker_func(ctx->priv, current_job, first_job, nb_jobs, nb_active_threads);
+ if (ctx->worker_func2) {
+ int ret = ctx->worker_func2(ctx->priv, current_job, first_job, nb_jobs, nb_active_threads);
+ *ret_out = FFMIN(*ret_out, ret);
+ } else {
+ ctx->worker_func(ctx->priv, current_job, first_job, nb_jobs, nb_active_threads);
+ }
} while ((current_job = atomic_fetch_add_explicit(&ctx->current_job, 1, memory_order_acq_rel)) < nb_jobs);
return current_job == nb_jobs + nb_active_threads - 1;
@@ -86,7 +96,7 @@ static void *attribute_align_arg thread_worker(void *v)
return NULL;
}
- if (run_jobs(ctx)) {
+ if (run_jobs(ctx, &w->ret)) {
pthread_mutex_lock(&ctx->done_mutex);
ctx->done = 1;
pthread_cond_signal(&ctx->done_cond);
@@ -95,9 +105,11 @@ static void *attribute_align_arg thread_worker(void *v)
}
}
-int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
+static int slicethread_create(AVSliceThread **pctx, void *priv,
void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
void (*main_func)(void *priv),
+ int (*worker_func2)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
+ int (*main_func2)(void *priv),
int nb_threads)
{
AVSliceThread *ctx;
@@ -128,6 +140,8 @@ int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
ctx->priv = priv;
ctx->worker_func = worker_func;
ctx->main_func = main_func;
+ ctx->worker_func2= worker_func2;
+ ctx->main_func2 = main_func2;
ctx->nb_threads = nb_threads;
ctx->nb_active_threads = 0;
ctx->nb_jobs = 0;
@@ -165,9 +179,34 @@ int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
return nb_threads;
}
+#if LIBAVUTIL_VERSION_MAJOR < 58
+int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
+ void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
+ void (*main_func)(void *priv),
+ int nb_threads)
+{
+ return slicethread_create(pctx, priv, worker_func, main_func, NULL, NULL, nb_threads);
+}
+#endif // LIBAVUTIL_VERSION_MAJOR
+
+int avpriv_slicethread_create2(AVSliceThread **pctx, void *priv,
+ int (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
+ int (*main_func)(void *priv),
+ int nb_threads)
+{
+ return slicethread_create(pctx, priv, NULL, NULL, worker_func, main_func, nb_threads);
+}
+
+#if LIBAVUTIL_VERSION_MAJOR < 58
void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main)
{
- int nb_workers, i, is_last = 0;
+ (void)avpriv_slicethread_execute2(ctx, nb_jobs, execute_main);
+}
+#endif // LIBAVUTIL_VERSION_MAJOR
+
+int avpriv_slicethread_execute2(AVSliceThread *ctx, int nb_jobs, int execute_main)
+{
+ int nb_workers, i, is_last = 0, ret = 0;
av_assert0(nb_jobs > 0);
ctx->nb_jobs = nb_jobs;
@@ -182,14 +221,17 @@ void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_mai
WorkerContext *w = &ctx->workers[i];
pthread_mutex_lock(&w->mutex);
w->done = 0;
+ w->ret = 0;
pthread_cond_signal(&w->cond);
pthread_mutex_unlock(&w->mutex);
}
if (ctx->main_func && execute_main)
ctx->main_func(ctx->priv);
+ else if (ctx->main_func2 && execute_main)
+ ret = ctx->main_func2(ctx->priv);
else
- is_last = run_jobs(ctx);
+ is_last = run_jobs(ctx, &ret);
if (!is_last) {
pthread_mutex_lock(&ctx->done_mutex);
@@ -198,6 +240,11 @@ void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_mai
ctx->done = 0;
pthread_mutex_unlock(&ctx->done_mutex);
}
+
+ for (i = 0; i < nb_workers; i++)
+ ret = FFMIN(ret, ctx->workers[i].ret);
+
+ return ret;
}
void avpriv_slicethread_free(AVSliceThread **pctx)
@@ -246,11 +293,26 @@ int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
return AVERROR(ENOSYS);
}
+int avpriv_slicethread_create2(AVSliceThread **pctx, void *priv,
+ int (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
+ int (*main_func)(void *priv),
+ int nb_threads)
+{
+ *pctx = NULL;
+ return AVERROR(ENOSYS);
+}
+
void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main)
{
av_assert0(0);
}
+int avpriv_slicethread_execute2(AVSliceThread *ctx, int nb_jobs, int execute_main)
+{
+ av_assert0(0);
+ return AVERROR(ENOSYS);
+}
+
void avpriv_slicethread_free(AVSliceThread **pctx)
{
av_assert0(!pctx || !*pctx);
diff --git a/libavutil/slicethread.h b/libavutil/slicethread.h
index f6f6f302c4..912ea13ce0 100644
--- a/libavutil/slicethread.h
+++ b/libavutil/slicethread.h
@@ -21,6 +21,7 @@
typedef struct AVSliceThread AVSliceThread;
+#if LIBAVUTIL_VERSION_MAJOR < 58
/**
* Create slice threading context.
* @param pctx slice threading context returned here
@@ -34,7 +35,23 @@ int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
void (*main_func)(void *priv),
int nb_threads);
+#endif // LIBAVUTIL_VERSION_MAJOR
+/**
+ * Like avpriv_slicethread_create() except worker_func and main_func return int.
+ * @param pctx slice threading context returned here
+ * @param priv private pointer to be passed to callback function
+ * @param worker_func callback function to be executed
+ * @param main_func special callback function, called from main thread, may be NULL
+ * @param nb_threads number of threads, 0 for automatic, must be >= 0
+ * @return return number of threads or negative AVERROR on failure
+ */
+int avpriv_slicethread_create2(AVSliceThread **pctx, void *priv,
+ int (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads),
+ int (*main_func)(void *priv),
+ int nb_threads);
+
+#if LIBAVUTIL_VERSION_MAJOR < 58
/**
* Execute slice threading.
* @param ctx slice threading context
@@ -42,6 +59,16 @@ int avpriv_slicethread_create(AVSliceThread **pctx, void *priv,
* @param execute_main also execute main_func
*/
void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main);
+#endif // LIBAVUTIL_VERSION_MAJOR
+
+/**
+ * Like avpriv_slicethread_execute() except returns FFMIN(0, main_func(), worker_func()).
+ * @param ctx slice threading context
+ * @param nb_jobs number of jobs, must be > 0
+ * @param execute_main also execute main_func
+ * @return AVERROR on error.
+ */
+int avpriv_slicethread_execute2(AVSliceThread *ctx, int nb_jobs, int execute_main);
/**
* Destroy slice threading context.
diff --git a/libavutil/version.h b/libavutil/version.h
index 9c44cef6aa..5aca550f45 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -79,7 +79,7 @@
*/
#define LIBAVUTIL_VERSION_MAJOR 57
-#define LIBAVUTIL_VERSION_MINOR 37
+#define LIBAVUTIL_VERSION_MINOR 38
#define LIBAVUTIL_VERSION_MICRO 100
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
diff --git a/libswscale/swscale.c b/libswscale/swscale.c
index 367d045a02..500b74c099 100644
--- a/libswscale/swscale.c
+++ b/libswscale/swscale.c
@@ -1150,23 +1150,11 @@ int sws_receive_slice(struct SwsContext *c, unsigned int slice_start,
if (c->slicethread) {
int nb_jobs = c->slice_ctx[0]->dither == SWS_DITHER_ED ? 1 : c->nb_slice_ctx;
- int ret = 0;
c->dst_slice_start = slice_start;
c->dst_slice_height = slice_height;
- avpriv_slicethread_execute(c->slicethread, nb_jobs, 0);
-
- for (int i = 0; i < c->nb_slice_ctx; i++) {
- if (c->slice_err[i] < 0) {
- ret = c->slice_err[i];
- break;
- }
- }
-
- memset(c->slice_err, 0, c->nb_slice_ctx * sizeof(*c->slice_err));
-
- return ret;
+ return avpriv_slicethread_execute2(c->slicethread, nb_jobs, 0);
}
for (int i = 0; i < FF_ARRAY_ELEMS(dst); i++) {
@@ -1213,8 +1201,8 @@ int attribute_align_arg sws_scale(struct SwsContext *c,
dst, dstStride, 0, c->dstH);
}
-void ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
- int nb_jobs, int nb_threads)
+int ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
+ int nb_jobs, int nb_threads)
{
SwsContext *parent = priv;
SwsContext *c = parent->slice_ctx[threadnr];
@@ -1242,5 +1230,5 @@ void ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
parent->dst_slice_start + slice_start, slice_end - slice_start);
}
- parent->slice_err[threadnr] = err;
+ return err;
}
diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h
index abeebbb002..204bafb6f4 100644
--- a/libswscale/swscale_internal.h
+++ b/libswscale/swscale_internal.h
@@ -306,7 +306,6 @@ typedef struct SwsContext {
AVSliceThread *slicethread;
struct SwsContext **slice_ctx;
- int *slice_err;
int nb_slice_ctx;
// values passed to current sws_receive_slice() call
@@ -1152,8 +1151,8 @@ void ff_init_vscale_pfn(SwsContext *c, yuv2planar1_fn yuv2plane1, yuv2planarX_fn
yuv2interleavedX_fn yuv2nv12cX, yuv2packed1_fn yuv2packed1, yuv2packed2_fn yuv2packed2,
yuv2packedX_fn yuv2packedX, yuv2anyX_fn yuv2anyX, int use_mmx);
-void ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
- int nb_jobs, int nb_threads);
+int ff_sws_slice_worker(void *priv, int jobnr, int threadnr,
+ int nb_jobs, int nb_threads);
//number of extra lines to process
#define MAX_LINES_AHEAD 4
diff --git a/libswscale/utils.c b/libswscale/utils.c
index 45baa22b23..8bfd3a64ac 100644
--- a/libswscale/utils.c
+++ b/libswscale/utils.c
@@ -1273,8 +1273,8 @@ static int context_init_threaded(SwsContext *c,
{
int ret;
- ret = avpriv_slicethread_create(&c->slicethread, (void*)c,
- ff_sws_slice_worker, NULL, c->nb_threads);
+ ret = avpriv_slicethread_create2(&c->slicethread, (void*)c,
+ ff_sws_slice_worker, NULL, c->nb_threads);
if (ret == AVERROR(ENOSYS)) {
c->nb_threads = 1;
return 0;
@@ -1284,8 +1284,7 @@ static int context_init_threaded(SwsContext *c,
c->nb_threads = ret;
c->slice_ctx = av_calloc(c->nb_threads, sizeof(*c->slice_ctx));
- c->slice_err = av_calloc(c->nb_threads, sizeof(*c->slice_err));
- if (!c->slice_ctx || !c->slice_err)
+ if (!c->slice_ctx)
return AVERROR(ENOMEM);
for (int i = 0; i < c->nb_threads; i++) {
@@ -2421,7 +2420,6 @@ void sws_freeContext(SwsContext *c)
for (i = 0; i < c->nb_slice_ctx; i++)
sws_freeContext(c->slice_ctx[i]);
av_freep(&c->slice_ctx);
- av_freep(&c->slice_err);
avpriv_slicethread_free(&c->slicethread);
diff --git a/libswscale/x86/output.asm b/libswscale/x86/output.asm
index 84e94baaf6..b468c0f264 100644
--- a/libswscale/x86/output.asm
+++ b/libswscale/x86/output.asm
@@ -580,7 +580,7 @@ yuv2nv12cX_fn yuv2nv21
%if ARCH_X86_64
struc SwsContext
- .padding: resb 40292 ; offsetof(SwsContext, yuv2rgb_y_offset)
+ .padding: resb 40276 ; offsetof(SwsContext, yuv2rgb_y_offset)
.yuv2rgb_y_offset: resd 1
.yuv2rgb_y_coeff: resd 1
.yuv2rgb_v2r_coeff: resd 1
diff --git a/libswscale/x86/swscale.c b/libswscale/x86/swscale.c
index ff16398988..9d1f539bba 100644
--- a/libswscale/x86/swscale.c
+++ b/libswscale/x86/swscale.c
@@ -748,7 +748,7 @@ switch(c->dstBpc){ \
/* yuv2gbrp uses the SwsContext for yuv coefficients
if struct offsets change the asm needs to be updated too */
- av_assert0(offsetof(SwsContext, yuv2rgb_y_offset) == 40292);
+ av_assert0(offsetof(SwsContext, yuv2rgb_y_offset) == 40276);
#define YUV2ANYX_FUNC_CASE(fmt, name, opt) \
case fmt: \
diff --git a/tests/fate/screen.mak b/tests/fate/screen.mak
index bd6d228544..b572f67b55 100644
--- a/tests/fate/screen.mak
+++ b/tests/fate/screen.mak
@@ -5,6 +5,7 @@ fate-cscd: CMD = framecrc -i $(TARGET_SAMPLES)/CSCD/sample_video.avi -an -pix_fm
FATE_SCREEN-$(call FRAMECRC, AVI, DXTORY) += fate-dxtory
fate-dxtory: CMD = framecrc -i $(TARGET_SAMPLES)/dxtory/dxtory_mic.avi -an
+# fic sample is broken. some packets are truncated and one packet has length zero
FATE_SCREEN-$(call FRAMECRC, AVI, FIC) += fate-fic-avi
fate-fic-avi: CMD = framecrc -i $(TARGET_SAMPLES)/fic/fic-partial-2MB.avi -an
diff --git a/tests/ref/fate/fic-avi b/tests/ref/fate/fic-avi
index df55789d54..4546f230b1 100644
--- a/tests/ref/fate/fic-avi
+++ b/tests/ref/fate/fic-avi
@@ -76,19 +76,18 @@
0, 70, 70, 1, 1566720, 0x40f7d39a
0, 71, 71, 1, 1566720, 0x40f7d39a
0, 72, 72, 1, 1566720, 0x40f7d39a
-0, 73, 73, 1, 1566720, 0xa7d6e25f
-0, 74, 74, 1, 1566720, 0xa7d6e25f
-0, 75, 75, 1, 1566720, 0xa7d6e25f
-0, 76, 76, 1, 1566720, 0xa7d6e25f
-0, 77, 77, 1, 1566720, 0xa7d6e25f
-0, 78, 78, 1, 1566720, 0xa7d6e25f
-0, 79, 79, 1, 1566720, 0xa7d6e25f
-0, 80, 80, 1, 1566720, 0xa7d6e25f
-0, 81, 81, 1, 1566720, 0xa7d6e25f
-0, 82, 82, 1, 1566720, 0xa7d6e25f
-0, 83, 83, 1, 1566720, 0xa7d6e25f
-0, 84, 84, 1, 1566720, 0xa7d6e25f
-0, 85, 85, 1, 1566720, 0xa7d6e25f
+0, 74, 74, 1, 1566720, 0x40f7d39a
+0, 75, 75, 1, 1566720, 0x40f7d39a
+0, 76, 76, 1, 1566720, 0x40f7d39a
+0, 77, 77, 1, 1566720, 0x40f7d39a
+0, 78, 78, 1, 1566720, 0x40f7d39a
+0, 79, 79, 1, 1566720, 0x40f7d39a
+0, 80, 80, 1, 1566720, 0x40f7d39a
+0, 81, 81, 1, 1566720, 0x40f7d39a
+0, 82, 82, 1, 1566720, 0x40f7d39a
+0, 83, 83, 1, 1566720, 0x40f7d39a
+0, 84, 84, 1, 1566720, 0x40f7d39a
+0, 85, 85, 1, 1566720, 0x40f7d39a
0, 86, 86, 1, 1566720, 0xa7d6e25f
0, 87, 87, 1, 1566720, 0xa7d6e25f
0, 88, 88, 1, 1566720, 0xa7d6e25f
@@ -104,7 +103,6 @@
0, 98, 98, 1, 1566720, 0xa7d6e25f
0, 99, 99, 1, 1566720, 0xa7d6e25f
0, 100, 100, 1, 1566720, 0xeaf8d207
-0, 101, 101, 1, 1566720, 0x6724983e
0, 102, 102, 1, 1566720, 0x0e95d209
0, 103, 103, 1, 1566720, 0x0e95d209
0, 104, 104, 1, 1566720, 0x0e95d209
@@ -121,6 +119,4 @@
0, 115, 115, 1, 1566720, 0xfe83b964
0, 116, 116, 1, 1566720, 0xfe83b964
0, 117, 117, 1, 1566720, 0xfe83b964
-0, 118, 118, 1, 1566720, 0x25dc30a6
-0, 119, 119, 1, 1566720, 0x25dc30a6
-0, 120, 120, 1, 1566720, 0x25dc30a6
+0, 119, 119, 1, 1566720, 0xfe83b964
--
2.30.2
[-- Attachment #3: Type: text/plain, Size: 251 bytes --]
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2022-09-26 14:44 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-26 13:46 [FFmpeg-devel] [PATCH v3] Add avpriv_slicethread_create2() and avpriv_slicethread_execute2(), make execute() and execute2() return FFMIN() of thread return codes Tomas Härdin
2022-09-26 13:50 ` Andreas Rheinhardt
2022-09-26 13:54 ` James Almer
2022-09-26 14:14 ` Tomas Härdin
2022-09-26 13:58 ` Andreas Rheinhardt
2022-09-26 14:01 ` Andreas Rheinhardt
2022-09-26 14:02 ` Tomas Härdin
2022-09-26 14:28 ` Andreas Rheinhardt
2022-09-26 14:44 ` Tomas Härdin
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git