* [FFmpeg-devel] [PATCH 01/42] tests/fate-run: Ensure that THREADS=random is actually random
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
@ 2023-09-19 19:56 ` Andreas Rheinhardt
2023-09-25 20:01 ` Andreas Rheinhardt
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 02/42] avcodec/refstruct: Add simple API for refcounted objects Andreas Rheinhardt
` (47 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:56 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 01/42] tests/fate-run: Ensure that THREADS=random is actually random
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 01/42] tests/fate-run: Ensure that THREADS=random is actually random Andreas Rheinhardt
@ 2023-09-25 20:01 ` Andreas Rheinhardt
0 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-25 20:01 UTC (permalink / raw)
To: ffmpeg-devel
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 <andreas.rheinhardt@outlook.com>
> ---
> 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
>
Will apply.
- 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] 106+ messages in thread
* [FFmpeg-devel] [PATCH 02/42] avcodec/refstruct: Add simple API for refcounted objects
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 01/42] tests/fate-run: Ensure that THREADS=random is actually random Andreas Rheinhardt
@ 2023-09-19 19:56 ` Andreas Rheinhardt
2023-09-21 19:58 ` Nicolas George
` (2 more replies)
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 03/42] avcodec/get_buffer: Use RefStruct API for FramePool Andreas Rheinhardt
` (46 subsequent siblings)
48 siblings, 3 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:56 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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 a/libavcodec/refstruct.c b/libavcodec/refstruct.c
new file mode 100644
index 0000000000..917cf6b7ac
--- /dev/null
+++ b/libavcodec/refstruct.c
@@ -0,0 +1,139 @@
+/*
+ * 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 <stdatomic.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "internal.h"
+#include "refstruct.h"
+
+#include "libavutil/macros.h"
+#include "libavutil/mem.h"
+
+typedef struct RefCount {
+ /**
+ * An uintptr_t is big enough to hold the address of every reference,
+ * so no overflow can happen when incrementing the refcount as long as
+ * the user does not throw away references.
+ */
+ atomic_uintptr_t refcount;
+ FFRefStructOpaque opaque;
+ void (*free_cb)(FFRefStructOpaque opaque, void *obj);
+} RefCount;
+
+#if __STDC_VERSION__ >= 201112L
+#define REFCOUNT_OFFSET FFALIGN(sizeof(RefCount), FFMAX3(STRIDE_ALIGN, 16, _Alignof(max_align_t)))
+#else
+#define REFCOUNT_OFFSET FFALIGN(sizeof(RefCount), FFMAX(STRIDE_ALIGN, 16))
+#endif
+
+static RefCount *get_refcount(void *obj)
+{
+ return (RefCount*)((char*)obj - REFCOUNT_OFFSET);
+}
+
+static void *get_userdata(void *buf)
+{
+ return (char*)buf + REFCOUNT_OFFSET;
+}
+
+static void refcount_init(RefCount *ref, FFRefStructOpaque opaque,
+ void (*free_cb)(FFRefStructOpaque opaque, void *obj))
+{
+ atomic_init(&ref->refcount, 1);
+ ref->opaque = opaque;
+ ref->free_cb = free_cb;
+}
+
+void *ff_refstruct_alloc_ext_c(size_t size, unsigned flags, FFRefStructOpaque opaque,
+ void (*free_cb)(FFRefStructOpaque opaque, void *obj))
+{
+ void *buf, *obj;
+
+ if (size > SIZE_MAX - REFCOUNT_OFFSET)
+ return NULL;
+ buf = av_malloc(size + REFCOUNT_OFFSET);
+ if (!buf)
+ return NULL;
+ refcount_init(buf, opaque, free_cb);
+ obj = get_userdata(buf);
+ if (!(flags & FF_REFSTRUCT_FLAG_NO_ZEROING))
+ memset(obj, 0, size);
+
+ return obj;
+}
+
+void *ff_refstruct_allocz(size_t size)
+{
+ return ff_refstruct_alloc_ext(size, 0, NULL, NULL);
+}
+
+void ff_refstruct_unref(void *objp)
+{
+ void *obj;
+ RefCount *ref;
+
+ memcpy(&obj, objp, sizeof(obj));
+ if (!obj)
+ return;
+ memcpy(objp, &(void *){ NULL }, sizeof(obj));
+
+ ref = get_refcount(obj);
+ if (atomic_fetch_sub_explicit(&ref->refcount, 1, memory_order_acq_rel) == 1) {
+ if (ref->free_cb)
+ ref->free_cb(ref->opaque, obj);
+ av_free(ref);
+ }
+
+ return;
+}
+
+void *ff_refstruct_ref(void *obj)
+{
+ RefCount *ref = get_refcount(obj);
+
+ atomic_fetch_add_explicit(&ref->refcount, 1, memory_order_relaxed);
+
+ return obj;
+}
+
+const void *ff_refstruct_ref_c(const void *obj)
+{
+ /* Casting const away here is fine, as it is only supposed
+ * to apply to the user's data and not our bookkeeping data. */
+ RefCount *ref = get_refcount((void*)obj);
+
+ atomic_fetch_add_explicit(&ref->refcount, 1, memory_order_relaxed);
+
+ return obj;
+}
+
+void ff_refstruct_replace(void *dstp, const void *src)
+{
+ const void *dst;
+ memcpy(&dst, dstp, sizeof(dst));
+
+ if (src == dst)
+ return;
+ ff_refstruct_unref(dstp);
+ if (src) {
+ dst = ff_refstruct_ref_c(src);
+ memcpy(dstp, &dst, sizeof(dst));
+ }
+}
diff --git a/libavcodec/refstruct.h b/libavcodec/refstruct.h
new file mode 100644
index 0000000000..0086717c17
--- /dev/null
+++ b/libavcodec/refstruct.h
@@ -0,0 +1,145 @@
+/*
+ * 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_REFSTRUCT_H
+#define AVCODEC_REFSTRUCT_H
+
+#include <stddef.h>
+
+/**
+ * RefStruct is an API for creating reference-counted objects
+ * with minimal overhead. The API is designed for objects,
+ * not buffers like the AVBuffer API. The main differences
+ * to the AVBuffer API are as follows:
+ *
+ * - It uses void* instead of uint8_t* as its base type due to
+ * its focus on objects.
+ * - There are no equivalents of AVBuffer and AVBufferRef.
+ * E.g. there is no way to get the usable size of the object:
+ * The user is supposed to know what is at the other end of
+ * the pointer. It also avoids one level of indirection.
+ * - Custom allocators are not supported. This allows to simplify
+ * the implementation and reduce the amount of allocations.
+ * - It also has the advantage that the user's free callback need
+ * only free the resources owned by the object, but not the
+ * object itself.
+ * - Because referencing (and replacing) an object managed by the
+ * RefStruct API does not involve allocations, they can not fail
+ * and therefore need not be checked.
+ *
+ * @note Referencing and unreferencing the buffers is thread-safe and thus
+ * may be done from multiple threads simultaneously without any need for
+ * additional locking.
+ */
+
+/**
+ * This union is used for all opaque parameters in this API to spare the user
+ * to cast const away in case the opaque to use is const-qualified.
+ *
+ * The functions provided by this API with an FFRefStructOpaque come in pairs
+ * named foo_c and foo. The foo function accepts void* as opaque and is just
+ * a wrapper around the foo_c function; "_c" means "(potentially) const".
+ */
+typedef union {
+ void *nc;
+ const void *c;
+} FFRefStructOpaque;
+
+/**
+ * If this flag is set in ff_refstruct_alloc_ext_c(), the object will not
+ * be initially zeroed.
+ */
+#define FF_REFSTRUCT_FLAG_NO_ZEROING (1 << 0)
+
+/**
+ * Allocate a refcounted object of usable size `size` managed via
+ * the RefStruct API.
+ *
+ * By default (in the absence of flags to the contrary),
+ * the returned object is initially zeroed.
+ *
+ * @param size Desired usable size of the returned object.
+ * @param flags A bitwise combination of FF_REFSTRUCT_FLAG_* flags.
+ * @param opaque A pointer that will be passed to the free_cb callback.
+ * @param free_cb A callback for freeing this object's content
+ * when its reference count reaches zero;
+ * it must not free the object itself.
+ * @return A pointer to an object of the desired size or NULL on failure.
+ */
+void *ff_refstruct_alloc_ext_c(size_t size, unsigned flags, FFRefStructOpaque opaque,
+ void (*free_cb)(FFRefStructOpaque opaque, void *obj));
+
+/**
+ * A wrapper around ff_refstruct_alloc_ext_c() for the common case
+ * of a non-const qualified opaque.
+ *
+ * @see ff_refstruct_alloc_ext_c()
+ */
+static inline
+void *ff_refstruct_alloc_ext(size_t size, unsigned flags, void *opaque,
+ void (*free_cb)(FFRefStructOpaque opaque, void *obj))
+{
+ return ff_refstruct_alloc_ext_c(size, flags, (FFRefStructOpaque){.nc = opaque},
+ free_cb);
+}
+
+/**
+ * Equivalent to ff_refstruct_alloc_ext(size, 0, NULL, NULL)
+ */
+void *ff_refstruct_allocz(size_t size);
+
+/**
+ * Decrement the reference count of the underlying object and automatically
+ * free the object if there are no more references to it.
+ *
+ * `*objp == NULL` is legal and a no-op.
+ *
+ * @param objp Pointer to a pointer that is either NULL or points to an object
+ * managed via this API. `*objp` is set to NULL on return.
+ */
+void ff_refstruct_unref(void *objp);
+
+/**
+ * Create a new reference to an object managed via this API,
+ * i.e. increment the reference count of the underlying object
+ * and return obj.
+ * @return a pointer equal to obj.
+ */
+void *ff_refstruct_ref(void *obj);
+
+/**
+ * Analog of ff_refstruct_ref(), but for constant objects.
+ * @see ff_refstruct_ref()
+ */
+const void *ff_refstruct_ref_c(const void *obj);
+
+/**
+ * Ensure `*dstp` refers to the same object as src.
+ *
+ * If `*dstp` is already equal to src, do nothing. Otherwise unreference `*dstp`
+ * and replace it with a new reference to src in case `src != NULL` (this
+ * involves incrementing the reference count of src's underlying object) or
+ * with NULL otherwise.
+ *
+ * @param dstp Pointer to a pointer that is either NULL or points to an object
+ * managed via this API.
+ * @param src A pointer to an object managed via this API or NULL.
+ */
+void ff_refstruct_replace(void *dstp, const void *src);
+
+#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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 02/42] avcodec/refstruct: Add simple API for refcounted objects
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 02/42] avcodec/refstruct: Add simple API for refcounted objects Andreas Rheinhardt
@ 2023-09-21 19:58 ` Nicolas George
2023-09-21 23:07 ` Andreas Rheinhardt
2023-10-06 18:24 ` Andreas Rheinhardt
2023-10-07 21:03 ` James Almer
2 siblings, 1 reply; 106+ messages in thread
From: Nicolas George @ 2023-09-21 19:58 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
[-- Attachment #1.1: Type: text/plain, Size: 2035 bytes --]
Andreas Rheinhardt (12023-09-19):
> 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:
<snip>
Thanks for stating qualms that I have had for a long time about this
API.
An API like this one would have been really useful when the new channel
layout structure was integrated. On a brighter note, it will be really
useful if we finally turn the library's global state into a structure
that can exist in multiple instances.
> 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).
I do not count it as a downside: it is just how the C language is
supposed to work. When we get a pointer, there is nothing written on it
that says whether we are supposed to free(), av_free(), g_object_unref()
it or just do nothing. People who cannot track static pointer ownership
in their sleep should do Java.
Also, you probably do not remember, three years ago I started proposing
a similar idea, and it got bikeshedded to death:
http://ffmpeg.org/pipermail/ffmpeg-devel/2020-June/265227.html
The difference is:
You make this API universal using void pointers and callbacks, and you
make it convenient by hiding the internals using pointer arithmetic.
I achieve more or less the same using a template to generate code, with
the extra benefit that it is type-safe.
I see a few places in the code below where you pay the price for your
design choice. I think you should consider taking a few ideas from my
version.
Regards,
--
Nicolas George
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
[-- Attachment #2: 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] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 02/42] avcodec/refstruct: Add simple API for refcounted objects
2023-09-21 19:58 ` Nicolas George
@ 2023-09-21 23:07 ` Andreas Rheinhardt
0 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-21 23:07 UTC (permalink / raw)
To: ffmpeg-devel
Nicolas George:
> Andreas Rheinhardt (12023-09-19):
>> 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:
>
> <snip>
>
> Thanks for stating qualms that I have had for a long time about this
> API.
>
> An API like this one would have been really useful when the new channel
> layout structure was integrated. On a brighter note, it will be really
> useful if we finally turn the library's global state into a structure
> that can exist in multiple instances.
>
>> 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).
>
> I do not count it as a downside: it is just how the C language is
> supposed to work. When we get a pointer, there is nothing written on it
> that says whether we are supposed to free(), av_free(), g_object_unref()
> it or just do nothing. People who cannot track static pointer ownership
> in their sleep should do Java.
>
I agree that this is not a major issue; I just wanted to be honest and
mention it in the commit message.
> Also, you probably do not remember, three years ago I started proposing
> a similar idea, and it got bikeshedded to death:
>
> http://ffmpeg.org/pipermail/ffmpeg-devel/2020-June/265227.html
>
> The difference is:
>
> You make this API universal using void pointers and callbacks, and you
> make it convenient by hiding the internals using pointer arithmetic.
>
> I achieve more or less the same using a template to generate code, with
> the extra benefit that it is type-safe.
>
1. I do not agree that your approach simplifies creating refcounted
structures.
Think of e.g. the H.264 and HEVC parameter sets patches in this series:
Using your approach I would need to include this header five times, each
time preceded by custom defines. I would also need to give the
referencing and unreferencing functions external linkage and therefore
add them to the headers (this is not true for init_ref_count and
get_ref_count (which would be unused in this scenario), so your template
would need to be updated to enable this usecase, further complicating
it). This is more boilerplate code than both current master and vastly
more than my approach.
(Also notice that in this case the references are of type pointer to
const, so the ref and unref functions would need to accept such
pointers, yet the init_ref_count and free functions would not, so this
means your template would need to be a bit more complex again (although
with sane defaults this can be made to affect only users that
const-references).)
2. Your solution lacks universality and this makes it even more unusable
for e.g. CBS: To support it with your approach one would basically have
to add a structure like from Anton's counterproposal (or a structure
like RefCount from refstruct.c) to the beginning of every CBS unit
context, which would be very instrusive and ugly (unless you hide it
like RefStruct does).
3. Your solution to the indirection caused by the custom free callbacks
basically amounts to "Add custom unref function for every refcounted
structure and inline the freeing code into it". I don't think that this
indirection matters and agree with Anton's "If you constantly alloc and
free objects in tight loops then you have way bigger problems than a
single pointer dereference", but I also want to add that this adds more
code into the binary.
4. I assume that if you extended your proposal to pools, we would end up
with typed pools where every callback is inlined and lots of code in the
binary will be duplicated. I don't like this result.
5. With both your and Anton's approach one would need to allocate a
structure oneself, followed by initializing the refcount. In this API
this is only one action, making every creation simpler.
6. I also like that RefStruct completely hides its internals, whereas
your solution needs an atomic integer in the structure.
To sum it up: I don't consider indirection to be an issue and the
type-unsafety is also not really worrisome. The gain in type-safety from
custom referencing and unreferencing functions would be far outweighed
by the boilerplate code to create them as well as the space said
boilerplate code will take up in the binary.
> I see a few places in the code below where you pay the price for your
> design choice. I think you should consider taking a few ideas from my
> version.
Could you be more specific? Is it just the inherent type-unsafety and
the indirection caused by function pointers?
- 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] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 02/42] avcodec/refstruct: Add simple API for refcounted objects
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 02/42] avcodec/refstruct: Add simple API for refcounted objects Andreas Rheinhardt
2023-09-21 19:58 ` Nicolas George
@ 2023-10-06 18:24 ` Andreas Rheinhardt
2023-10-06 19:43 ` Nicolas George
2023-10-07 21:03 ` James Almer
2 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-10-06 18:24 UTC (permalink / raw)
To: ffmpeg-devel
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 <andreas.rheinhardt@outlook.com>
> ---
> 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 a/libavcodec/refstruct.c b/libavcodec/refstruct.c
> new file mode 100644
> index 0000000000..917cf6b7ac
> --- /dev/null
> +++ b/libavcodec/refstruct.c
> @@ -0,0 +1,139 @@
> +/*
> + * 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 <stdatomic.h>
> +#include <stdint.h>
> +#include <string.h>
> +
> +#include "internal.h"
> +#include "refstruct.h"
> +
> +#include "libavutil/macros.h"
> +#include "libavutil/mem.h"
> +
> +typedef struct RefCount {
> + /**
> + * An uintptr_t is big enough to hold the address of every reference,
> + * so no overflow can happen when incrementing the refcount as long as
> + * the user does not throw away references.
> + */
> + atomic_uintptr_t refcount;
> + FFRefStructOpaque opaque;
> + void (*free_cb)(FFRefStructOpaque opaque, void *obj);
> +} RefCount;
> +
> +#if __STDC_VERSION__ >= 201112L
> +#define REFCOUNT_OFFSET FFALIGN(sizeof(RefCount), FFMAX3(STRIDE_ALIGN, 16, _Alignof(max_align_t)))
> +#else
> +#define REFCOUNT_OFFSET FFALIGN(sizeof(RefCount), FFMAX(STRIDE_ALIGN, 16))
> +#endif
> +
> +static RefCount *get_refcount(void *obj)
> +{
> + return (RefCount*)((char*)obj - REFCOUNT_OFFSET);
> +}
> +
> +static void *get_userdata(void *buf)
> +{
> + return (char*)buf + REFCOUNT_OFFSET;
> +}
> +
> +static void refcount_init(RefCount *ref, FFRefStructOpaque opaque,
> + void (*free_cb)(FFRefStructOpaque opaque, void *obj))
> +{
> + atomic_init(&ref->refcount, 1);
> + ref->opaque = opaque;
> + ref->free_cb = free_cb;
> +}
> +
> +void *ff_refstruct_alloc_ext_c(size_t size, unsigned flags, FFRefStructOpaque opaque,
> + void (*free_cb)(FFRefStructOpaque opaque, void *obj))
> +{
> + void *buf, *obj;
> +
> + if (size > SIZE_MAX - REFCOUNT_OFFSET)
> + return NULL;
> + buf = av_malloc(size + REFCOUNT_OFFSET);
> + if (!buf)
> + return NULL;
> + refcount_init(buf, opaque, free_cb);
> + obj = get_userdata(buf);
> + if (!(flags & FF_REFSTRUCT_FLAG_NO_ZEROING))
> + memset(obj, 0, size);
> +
> + return obj;
> +}
> +
> +void *ff_refstruct_allocz(size_t size)
> +{
> + return ff_refstruct_alloc_ext(size, 0, NULL, NULL);
> +}
> +
> +void ff_refstruct_unref(void *objp)
> +{
> + void *obj;
> + RefCount *ref;
> +
> + memcpy(&obj, objp, sizeof(obj));
> + if (!obj)
> + return;
> + memcpy(objp, &(void *){ NULL }, sizeof(obj));
> +
> + ref = get_refcount(obj);
> + if (atomic_fetch_sub_explicit(&ref->refcount, 1, memory_order_acq_rel) == 1) {
> + if (ref->free_cb)
> + ref->free_cb(ref->opaque, obj);
> + av_free(ref);
> + }
> +
> + return;
> +}
> +
> +void *ff_refstruct_ref(void *obj)
> +{
> + RefCount *ref = get_refcount(obj);
> +
> + atomic_fetch_add_explicit(&ref->refcount, 1, memory_order_relaxed);
> +
> + return obj;
> +}
> +
> +const void *ff_refstruct_ref_c(const void *obj)
> +{
> + /* Casting const away here is fine, as it is only supposed
> + * to apply to the user's data and not our bookkeeping data. */
> + RefCount *ref = get_refcount((void*)obj);
> +
> + atomic_fetch_add_explicit(&ref->refcount, 1, memory_order_relaxed);
> +
> + return obj;
> +}
> +
> +void ff_refstruct_replace(void *dstp, const void *src)
> +{
> + const void *dst;
> + memcpy(&dst, dstp, sizeof(dst));
> +
> + if (src == dst)
> + return;
> + ff_refstruct_unref(dstp);
> + if (src) {
> + dst = ff_refstruct_ref_c(src);
> + memcpy(dstp, &dst, sizeof(dst));
> + }
> +}
> diff --git a/libavcodec/refstruct.h b/libavcodec/refstruct.h
> new file mode 100644
> index 0000000000..0086717c17
> --- /dev/null
> +++ b/libavcodec/refstruct.h
> @@ -0,0 +1,145 @@
> +/*
> + * 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_REFSTRUCT_H
> +#define AVCODEC_REFSTRUCT_H
> +
> +#include <stddef.h>
> +
> +/**
> + * RefStruct is an API for creating reference-counted objects
> + * with minimal overhead. The API is designed for objects,
> + * not buffers like the AVBuffer API. The main differences
> + * to the AVBuffer API are as follows:
> + *
> + * - It uses void* instead of uint8_t* as its base type due to
> + * its focus on objects.
> + * - There are no equivalents of AVBuffer and AVBufferRef.
> + * E.g. there is no way to get the usable size of the object:
> + * The user is supposed to know what is at the other end of
> + * the pointer. It also avoids one level of indirection.
> + * - Custom allocators are not supported. This allows to simplify
> + * the implementation and reduce the amount of allocations.
> + * - It also has the advantage that the user's free callback need
> + * only free the resources owned by the object, but not the
> + * object itself.
> + * - Because referencing (and replacing) an object managed by the
> + * RefStruct API does not involve allocations, they can not fail
> + * and therefore need not be checked.
> + *
> + * @note Referencing and unreferencing the buffers is thread-safe and thus
> + * may be done from multiple threads simultaneously without any need for
> + * additional locking.
> + */
> +
> +/**
> + * This union is used for all opaque parameters in this API to spare the user
> + * to cast const away in case the opaque to use is const-qualified.
> + *
> + * The functions provided by this API with an FFRefStructOpaque come in pairs
> + * named foo_c and foo. The foo function accepts void* as opaque and is just
> + * a wrapper around the foo_c function; "_c" means "(potentially) const".
> + */
> +typedef union {
> + void *nc;
> + const void *c;
> +} FFRefStructOpaque;
> +
> +/**
> + * If this flag is set in ff_refstruct_alloc_ext_c(), the object will not
> + * be initially zeroed.
> + */
> +#define FF_REFSTRUCT_FLAG_NO_ZEROING (1 << 0)
> +
> +/**
> + * Allocate a refcounted object of usable size `size` managed via
> + * the RefStruct API.
> + *
> + * By default (in the absence of flags to the contrary),
> + * the returned object is initially zeroed.
> + *
> + * @param size Desired usable size of the returned object.
> + * @param flags A bitwise combination of FF_REFSTRUCT_FLAG_* flags.
> + * @param opaque A pointer that will be passed to the free_cb callback.
> + * @param free_cb A callback for freeing this object's content
> + * when its reference count reaches zero;
> + * it must not free the object itself.
> + * @return A pointer to an object of the desired size or NULL on failure.
> + */
> +void *ff_refstruct_alloc_ext_c(size_t size, unsigned flags, FFRefStructOpaque opaque,
> + void (*free_cb)(FFRefStructOpaque opaque, void *obj));
> +
> +/**
> + * A wrapper around ff_refstruct_alloc_ext_c() for the common case
> + * of a non-const qualified opaque.
> + *
> + * @see ff_refstruct_alloc_ext_c()
> + */
> +static inline
> +void *ff_refstruct_alloc_ext(size_t size, unsigned flags, void *opaque,
> + void (*free_cb)(FFRefStructOpaque opaque, void *obj))
> +{
> + return ff_refstruct_alloc_ext_c(size, flags, (FFRefStructOpaque){.nc = opaque},
> + free_cb);
> +}
> +
> +/**
> + * Equivalent to ff_refstruct_alloc_ext(size, 0, NULL, NULL)
> + */
> +void *ff_refstruct_allocz(size_t size);
> +
> +/**
> + * Decrement the reference count of the underlying object and automatically
> + * free the object if there are no more references to it.
> + *
> + * `*objp == NULL` is legal and a no-op.
> + *
> + * @param objp Pointer to a pointer that is either NULL or points to an object
> + * managed via this API. `*objp` is set to NULL on return.
> + */
> +void ff_refstruct_unref(void *objp);
> +
> +/**
> + * Create a new reference to an object managed via this API,
> + * i.e. increment the reference count of the underlying object
> + * and return obj.
> + * @return a pointer equal to obj.
> + */
> +void *ff_refstruct_ref(void *obj);
> +
> +/**
> + * Analog of ff_refstruct_ref(), but for constant objects.
> + * @see ff_refstruct_ref()
> + */
> +const void *ff_refstruct_ref_c(const void *obj);
> +
> +/**
> + * Ensure `*dstp` refers to the same object as src.
> + *
> + * If `*dstp` is already equal to src, do nothing. Otherwise unreference `*dstp`
> + * and replace it with a new reference to src in case `src != NULL` (this
> + * involves incrementing the reference count of src's underlying object) or
> + * with NULL otherwise.
> + *
> + * @param dstp Pointer to a pointer that is either NULL or points to an object
> + * managed via this API.
> + * @param src A pointer to an object managed via this API or NULL.
> + */
> +void ff_refstruct_replace(void *dstp, const void *src);
> +
> +#endif /* AVCODEC_REFSTRUCT_H */
Will apply patches 2-16 (i.e. up to the pool API) tomorrow unless there
are objections.
- 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] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 02/42] avcodec/refstruct: Add simple API for refcounted objects
2023-10-06 18:24 ` Andreas Rheinhardt
@ 2023-10-06 19:43 ` Nicolas George
2023-10-06 20:20 ` Andreas Rheinhardt
0 siblings, 1 reply; 106+ messages in thread
From: Nicolas George @ 2023-10-06 19:43 UTC (permalink / raw)
To: FFmpeg development discussions and patches
[-- Attachment #1.1: Type: text/plain, Size: 254 bytes --]
Andreas Rheinhardt (12023-10-06):
> Will apply patches 2-16 (i.e. up to the pool API) tomorrow unless there
> are objections.
Have you given some thought to using a template to make the API
type-safe directly?
Regards,
--
Nicolas George
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
[-- Attachment #2: 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] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 02/42] avcodec/refstruct: Add simple API for refcounted objects
2023-10-06 19:43 ` Nicolas George
@ 2023-10-06 20:20 ` Andreas Rheinhardt
2023-10-06 20:37 ` Nicolas George
0 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-10-06 20:20 UTC (permalink / raw)
To: ffmpeg-devel
Nicolas George:
> Andreas Rheinhardt (12023-10-06):
>> Will apply patches 2-16 (i.e. up to the pool API) tomorrow unless there
>> are objections.
>
> Have you given some thought to using a template to make the API
> type-safe directly?
Do you mean a template that generates functions like
HEVCVPS *ff_hevc_vps_ref(HEVCVPS *vps)
{
return ff_refstruct_ref(vps);
}
automatically? I don't think that's worth it.
- 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] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 02/42] avcodec/refstruct: Add simple API for refcounted objects
2023-10-06 20:20 ` Andreas Rheinhardt
@ 2023-10-06 20:37 ` Nicolas George
2023-10-06 20:50 ` Andreas Rheinhardt
0 siblings, 1 reply; 106+ messages in thread
From: Nicolas George @ 2023-10-06 20:37 UTC (permalink / raw)
To: FFmpeg development discussions and patches
[-- Attachment #1.1: Type: text/plain, Size: 631 bytes --]
Andreas Rheinhardt (12023-10-06):
> Do you mean a template that generates functions like
>
> HEVCVPS *ff_hevc_vps_ref(HEVCVPS *vps)
> {
> return ff_refstruct_ref(vps);
> }
>
> automatically?
Yes, but better, directly:
void ff_hevc_vps_unref(HEVCVPS *vps)
{
if (atomic_fetch_sub_explicit(&(*vps)->AVRC_FIELD, 1, memory_order_acq_rel) == 1) {
AVRC_FREE(*vps);
*vps = NULL;
}
}
Apart from the type safety, I see a significant benefit in having the
free function hard-coded in the unref function rather than having to
spare a pointer for it.
Regards,
--
Nicolas George
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
[-- Attachment #2: 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] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 02/42] avcodec/refstruct: Add simple API for refcounted objects
2023-10-06 20:37 ` Nicolas George
@ 2023-10-06 20:50 ` Andreas Rheinhardt
2023-10-06 21:22 ` Nicolas George
0 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-10-06 20:50 UTC (permalink / raw)
To: ffmpeg-devel
Nicolas George:
> Andreas Rheinhardt (12023-10-06):
>> Do you mean a template that generates functions like
>>
>> HEVCVPS *ff_hevc_vps_ref(HEVCVPS *vps)
>> {
>> return ff_refstruct_ref(vps);
>> }
>>
>> automatically?
>
> Yes, but better, directly:
>
> void ff_hevc_vps_unref(HEVCVPS *vps)
> {
> if (atomic_fetch_sub_explicit(&(*vps)->AVRC_FIELD, 1, memory_order_acq_rel) == 1) {
> AVRC_FREE(*vps);
> *vps = NULL;
> }
> }
>
> Apart from the type safety, I see a significant benefit in having the
> free function hard-coded in the unref function rather than having to
> spare a pointer for it.
>
And as I have already explained, I do not think that this benefit is
significant and you have provided no evidence (i.e. an example) that it
is so. Additionally, the flexibility provided by function pointers is
useful for stuff like CBS.
- 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] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 02/42] avcodec/refstruct: Add simple API for refcounted objects
2023-10-06 20:50 ` Andreas Rheinhardt
@ 2023-10-06 21:22 ` Nicolas George
0 siblings, 0 replies; 106+ messages in thread
From: Nicolas George @ 2023-10-06 21:22 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Andreas Rheinhardt (12023-10-06):
> And as I have already explained, I do not think that this benefit is
> significant and you have provided no evidence (i.e. an example) that it
> is so. Additionally, the flexibility provided by function pointers is
> useful for stuff like CBS.
I must have missed that reply, sorry.
Regards,
--
Nicolas George
_______________________________________________
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] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 02/42] avcodec/refstruct: Add simple API for refcounted objects
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 02/42] avcodec/refstruct: Add simple API for refcounted objects Andreas Rheinhardt
2023-09-21 19:58 ` Nicolas George
2023-10-06 18:24 ` Andreas Rheinhardt
@ 2023-10-07 21:03 ` James Almer
2 siblings, 0 replies; 106+ messages in thread
From: James Almer @ 2023-10-07 21:03 UTC (permalink / raw)
To: ffmpeg-devel
On 9/19/2023 4:56 PM, Andreas Rheinhardt wrote:
> +
> +/**
> + * Allocate a refcounted object of usable size `size` managed via
> + * the RefStruct API.
> + *
> + * By default (in the absence of flags to the contrary),
> + * the returned object is initially zeroed.
> + *
> + * @param size Desired usable size of the returned object.
> + * @param flags A bitwise combination of FF_REFSTRUCT_FLAG_* flags.
> + * @param opaque A pointer that will be passed to the free_cb callback.
> + * @param free_cb A callback for freeing this object's content
> + * when its reference count reaches zero;
> + * it must not free the object itself.
> + * @return A pointer to an object of the desired size or NULL on failure.
> + */
> +void *ff_refstruct_alloc_ext_c(size_t size, unsigned flags, FFRefStructOpaque opaque,
> + void (*free_cb)(FFRefStructOpaque opaque, void *obj));
> +
> +/**
> + * A wrapper around ff_refstruct_alloc_ext_c() for the common case
> + * of a non-const qualified opaque.
> + *
> + * @see ff_refstruct_alloc_ext_c()
> + */
> +static inline
> +void *ff_refstruct_alloc_ext(size_t size, unsigned flags, void *opaque,
> + void (*free_cb)(FFRefStructOpaque opaque, void *obj))
> +{
> + return ff_refstruct_alloc_ext_c(size, flags, (FFRefStructOpaque){.nc = opaque},
> + free_cb);
> +}
> +
> +/**
> + * Equivalent to ff_refstruct_alloc_ext(size, 0, NULL, NULL)
Why is this not inlined, then?
> + */
> +void *ff_refstruct_allocz(size_t size);
_______________________________________________
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] 106+ messages in thread
* [FFmpeg-devel] [PATCH 03/42] avcodec/get_buffer: Use RefStruct API for FramePool
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 01/42] tests/fate-run: Ensure that THREADS=random is actually random Andreas Rheinhardt
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 02/42] avcodec/refstruct: Add simple API for refcounted objects Andreas Rheinhardt
@ 2023-09-19 19:56 ` Andreas Rheinhardt
2023-09-28 12:36 ` Anton Khirnov
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 04/42] avcodec/h264_ps: Use RefStruct API for SPS/PPS Andreas Rheinhardt
` (45 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:56 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
Avoids allocations and frees and error checks for said allocations;
also avoids a few indirections and casts.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
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(&avci->in_frame);
av_frame_free(&avci->recon_frame);
- av_buffer_unref(&avci->pool);
+ ff_refstruct_unref(&avci->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(&pool->pools[i]);
-
- av_freep(&data);
-}
-
-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(&pool);
- 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(&avctx->internal->pool);
- avctx->internal->pool = pool_buf;
+ ff_refstruct_unref(&avctx->internal->pool);
+ avctx->internal->pool = pool;
return 0;
fail:
- av_buffer_unref(&pool_buf);
+ ff_refstruct_unref(&pool);
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(&dst->internal->pool, src->internal->pool);
- if (err < 0)
- return err;
+ ff_refstruct_replace(&dst->internal->pool, src->internal->pool);
}
if (for_user) {
@@ -740,7 +739,7 @@ void ff_frame_thread_free(AVCodecContext *avctx, int thread_count)
av_freep(&ctx->priv_data);
}
- av_buffer_unref(&ctx->internal->pool);
+ ff_refstruct_unref(&ctx->internal->pool);
av_packet_free(&ctx->internal->last_pkt_props);
av_freep(&ctx->internal);
av_buffer_unref(&ctx->hw_frames_ctx);
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 03/42] avcodec/get_buffer: Use RefStruct API for FramePool
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 03/42] avcodec/get_buffer: Use RefStruct API for FramePool Andreas Rheinhardt
@ 2023-09-28 12:36 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-09-28 12:36 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:56:55)
> Avoids allocations and frees and error checks for said allocations;
> also avoids a few indirections and casts.
>
> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
> ---
> 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(-)
LGTM
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 04/42] avcodec/h264_ps: Use RefStruct API for SPS/PPS
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (2 preceding siblings ...)
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 03/42] avcodec/get_buffer: Use RefStruct API for FramePool Andreas Rheinhardt
@ 2023-09-19 19:56 ` Andreas Rheinhardt
2023-09-28 13:03 ` Anton Khirnov
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 05/42] avcodec/hevc_ps: Use RefStruct API for parameter sets Andreas Rheinhardt
` (44 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:56 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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(&p->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(&p->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(&pic->qscale_table_buf);
av_buffer_unref(&pic->mb_type_buf);
- av_buffer_unref(&pic->pps_buf);
+ ff_refstruct_unref(&pic->pps);
for (i = 0; i < 2; i++) {
av_buffer_unref(&pic->motion_val_buf[i]);
av_buffer_unref(&pic->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(&dst->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(&dst->qscale_table_buf, src->qscale_table_buf);
ret |= av_buffer_replace(&dst->mb_type_buf, src->mb_type_buf);
- ret |= av_buffer_replace(&dst->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_NUM 4
@@ -85,7 +86,7 @@ static const int level_max_dpb_mbs[][2] = {
static void remove_pps(H264ParamSets *s, int id)
{
- av_buffer_unref(&s->pps_list[id]);
+ ff_refstruct_unref(&s->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(&s->sps_list[id]);
+ ff_refstruct_unref(&s->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(&ps->sps_list[i]);
+ ff_refstruct_unref(&ps->sps_list[i]);
for (i = 0; i < MAX_PPS_COUNT; i++)
- av_buffer_unref(&ps->pps_list[i]);
+ ff_refstruct_unref(&ps->pps_list[i]);
- av_buffer_unref(&ps->pps_ref);
-
- ps->pps = NULL;
+ ff_refstruct_unref(&ps->pps);
ps->sps = NULL;
}
int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx,
H264ParamSets *ps, int ignore_truncation)
{
- AVBufferRef *sps_buf;
int profile_idc, level_idc, constraint_set_flags = 0;
unsigned int sps_id;
int i, log2_max_frame_num_minus4;
SPS *sps;
int ret;
- sps_buf = av_buffer_allocz(sizeof(*sps));
- if (!sps_buf)
+ sps = ff_refstruct_allocz(sizeof(*sps));
+ if (!sps)
return AVERROR(ENOMEM);
- sps = (SPS*)sps_buf->data;
sps->data_size = gb->buffer_end - gb->buffer;
if (sps->data_size > sizeof(sps->data)) {
@@ -580,17 +577,17 @@ int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx,
* original one.
* otherwise drop all PPSes that depend on it */
if (ps->sps_list[sps_id] &&
- !memcmp(ps->sps_list[sps_id]->data, sps_buf->data, sps_buf->size)) {
- av_buffer_unref(&sps_buf);
+ !memcmp(ps->sps_list[sps_id], sps, sizeof(*sps))) {
+ ff_refstruct_unref(&sps);
} else {
remove_sps(ps, sps_id);
- ps->sps_list[sps_id] = sps_buf;
+ ps->sps_list[sps_id] = sps;
}
return 0;
fail:
- av_buffer_unref(&sps_buf);
+ ff_refstruct_unref(&sps);
return AVERROR_INVALIDDATA;
}
@@ -689,19 +686,16 @@ static int more_rbsp_data_in_pps(const SPS *sps, void *logctx)
return 1;
}
-static void pps_free(void *opaque, uint8_t *data)
+static void pps_free(FFRefStructOpaque unused, void *obj)
{
- PPS *pps = (PPS*)data;
-
- av_buffer_unref(&pps->sps_ref);
+ PPS *pps = obj;
- av_freep(&data);
+ ff_refstruct_unref(&pps->sps);
}
int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avctx,
H264ParamSets *ps, int bit_length)
{
- AVBufferRef *pps_buf;
const SPS *sps;
unsigned int pps_id = get_ue_golomb(gb);
PPS *pps;
@@ -714,15 +708,9 @@ int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avct
return AVERROR_INVALIDDATA;
}
- pps = av_mallocz(sizeof(*pps));
+ pps = ff_refstruct_alloc_ext(sizeof(*pps), 0, NULL, pps_free);
if (!pps)
return AVERROR(ENOMEM);
- pps_buf = av_buffer_create((uint8_t*)pps, sizeof(*pps),
- pps_free, NULL, 0);
- if (!pps_buf) {
- av_freep(&pps);
- return AVERROR(ENOMEM);
- }
pps->data_size = gb->buffer_end - gb->buffer;
if (pps->data_size > sizeof(pps->data)) {
@@ -745,12 +733,7 @@ int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avct
ret = AVERROR_INVALIDDATA;
goto fail;
}
- pps->sps_ref = av_buffer_ref(ps->sps_list[pps->sps_id]);
- if (!pps->sps_ref) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
- pps->sps = (const SPS*)pps->sps_ref->data;
+ pps->sps = ff_refstruct_ref_c(ps->sps_list[pps->sps_id]);
sps = pps->sps;
if (sps->bit_depth_luma > 14) {
@@ -852,11 +835,11 @@ int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avct
}
remove_pps(ps, pps_id);
- ps->pps_list[pps_id] = pps_buf;
+ ps->pps_list[pps_id] = pps;
return 0;
fail:
- av_buffer_unref(&pps_buf);
+ ff_refstruct_unref(&pps);
return ret;
}
diff --git a/libavcodec/h264_ps.h b/libavcodec/h264_ps.h
index e675619635..80af4832fe 100644
--- a/libavcodec/h264_ps.h
+++ b/libavcodec/h264_ps.h
@@ -26,7 +26,6 @@
#include <stdint.h>
-#include "libavutil/buffer.h"
#include "libavutil/pixfmt.h"
#include "libavutil/rational.h"
@@ -139,18 +138,16 @@ typedef struct PPS {
uint32_t(*dequant4_coeff[6])[16];
uint32_t(*dequant8_coeff[6])[64];
- AVBufferRef *sps_ref;
- const SPS *sps;
+ const SPS *sps; ///< RefStruct reference
} PPS;
typedef struct H264ParamSets {
- AVBufferRef *sps_list[MAX_SPS_COUNT];
- AVBufferRef *pps_list[MAX_PPS_COUNT];
+ const SPS *sps_list[MAX_SPS_COUNT]; ///< RefStruct references
+ const PPS *pps_list[MAX_PPS_COUNT]; ///< RefStruct references
- AVBufferRef *pps_ref;
/* currently active parameters sets */
- const PPS *pps;
- const SPS *sps;
+ const PPS *pps; ///< RefStruct reference
+ const SPS *sps; ///< ordinary pointer, no RefStruct reference
int overread_warning_printed[2];
} H264ParamSets;
diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c
index 50bbe94917..1b24c493df 100644
--- a/libavcodec/h264_refs.c
+++ b/libavcodec/h264_refs.c
@@ -807,7 +807,7 @@ int ff_h264_execute_ref_pic_marking(H264Context *h)
for (i = 0; i < FF_ARRAY_ELEMS(h->ps.pps_list); i++) {
if (h->ps.pps_list[i]) {
- const PPS *pps = (const PPS *)h->ps.pps_list[i]->data;
+ const PPS *pps = h->ps.pps_list[i];
pps_ref_count[0] = FFMAX(pps_ref_count[0], pps->ref_count[0]);
pps_ref_count[1] = FFMAX(pps_ref_count[1], pps->ref_count[1]);
}
diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c
index 668204959f..8d6dc77943 100644
--- a/libavcodec/h264_sei.c
+++ b/libavcodec/h264_sei.c
@@ -179,7 +179,7 @@ static int decode_buffering_period(H264SEIBufferingPeriod *h, GetBitContext *gb,
"non-existing SPS %d referenced in buffering period\n", sps_id);
return sps_id > 31 ? AVERROR_INVALIDDATA : AVERROR_PS_NOT_FOUND;
}
- sps = (const SPS*)ps->sps_list[sps_id]->data;
+ sps = ps->sps_list[sps_id];
// NOTE: This is really so duplicated in the standard... See H.264, D.1.1
if (sps->nal_hrd_parameters_present_flag) {
diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index 5657327f0c..632f5b23b2 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -44,6 +44,7 @@
#include "mathops.h"
#include "mpegutils.h"
#include "rectangle.h"
+#include "refstruct.h"
#include "thread.h"
#include "threadframe.h"
@@ -254,10 +255,7 @@ static int alloc_picture(H264Context *h, H264Picture *pic)
pic->ref_index[i] = pic->ref_index_buf[i]->data;
}
- pic->pps_buf = av_buffer_ref(h->ps.pps_ref);
- if (!pic->pps_buf)
- goto fail;
- pic->pps = (const PPS*)pic->pps_buf->data;
+ pic->pps = ff_refstruct_ref_c(h->ps.pps);
pic->mb_width = h->mb_width;
pic->mb_height = h->mb_height;
@@ -363,25 +361,16 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
// SPS/PPS
for (i = 0; i < FF_ARRAY_ELEMS(h->ps.sps_list); i++) {
- ret = av_buffer_replace(&h->ps.sps_list[i], h1->ps.sps_list[i]);
- if (ret < 0)
- return ret;
+ ff_refstruct_replace(&h->ps.sps_list[i], h1->ps.sps_list[i]);
}
for (i = 0; i < FF_ARRAY_ELEMS(h->ps.pps_list); i++) {
- ret = av_buffer_replace(&h->ps.pps_list[i], h1->ps.pps_list[i]);
- if (ret < 0)
- return ret;
+ ff_refstruct_replace(&h->ps.pps_list[i], h1->ps.pps_list[i]);
}
- ret = av_buffer_replace(&h->ps.pps_ref, h1->ps.pps_ref);
- if (ret < 0)
- return ret;
- h->ps.pps = NULL;
+ ff_refstruct_replace(&h->ps.pps, h1->ps.pps);
h->ps.sps = NULL;
- if (h1->ps.pps_ref) {
- h->ps.pps = (const PPS*)h->ps.pps_ref->data;
+ if (h1->ps.pps)
h->ps.sps = h->ps.pps->sps;
- }
if (need_reinit || !inited) {
h->width = h1->width;
@@ -935,7 +924,7 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback)
/* export coded and cropped frame dimensions to AVCodecContext */
static void init_dimensions(H264Context *h)
{
- const SPS *sps = (const SPS*)h->ps.sps;
+ const SPS *sps = h->ps.sps;
int cr = sps->crop_right;
int cl = sps->crop_left;
int ct = sps->crop_top;
@@ -1071,17 +1060,11 @@ static int h264_init_ps(H264Context *h, const H264SliceContext *sl, int first_sl
const SPS *sps;
int needs_reinit = 0, must_reinit, ret;
- if (first_slice) {
- av_buffer_unref(&h->ps.pps_ref);
- h->ps.pps = NULL;
- h->ps.pps_ref = av_buffer_ref(h->ps.pps_list[sl->pps_id]);
- if (!h->ps.pps_ref)
- return AVERROR(ENOMEM);
- h->ps.pps = (const PPS*)h->ps.pps_ref->data;
- }
+ if (first_slice)
+ ff_refstruct_replace(&h->ps.pps, h->ps.pps_list[sl->pps_id]);
if (h->ps.sps != h->ps.pps->sps) {
- h->ps.sps = (const SPS*)h->ps.pps->sps;
+ h->ps.sps = h->ps.pps->sps;
if (h->mb_width != h->ps.sps->mb_width ||
h->mb_height != h->ps.sps->mb_height ||
@@ -1753,7 +1736,7 @@ static int h264_slice_header_parse(const H264Context *h, H264SliceContext *sl,
sl->pps_id);
return AVERROR_INVALIDDATA;
}
- pps = (const PPS*)h->ps.pps_list[sl->pps_id]->data;
+ pps = h->ps.pps_list[sl->pps_id];
sps = pps->sps;
sl->frame_num = get_bits(&sl->gb, sps->log2_max_frame_num);
@@ -2140,7 +2123,7 @@ int ff_h264_queue_decode_slice(H264Context *h, const H2645NAL *nal)
}
if (!first_slice) {
- const PPS *pps = (const PPS*)h->ps.pps_list[sl->pps_id]->data;
+ const PPS *pps = h->ps.pps_list[sl->pps_id];
if (h->ps.pps->sps_id != pps->sps_id ||
h->ps.pps->transform_8x8_mode != pps->transform_8x8_mode /*||
diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h
index 322c06a19c..513856749a 100644
--- a/libavcodec/h264dec.h
+++ b/libavcodec/h264dec.h
@@ -147,7 +147,6 @@ typedef struct H264Picture {
int sei_recovery_frame_cnt;
int needs_fg; ///< whether picture needs film grain synthesis (see `f_grain`)
- AVBufferRef *pps_buf;
const PPS *pps;
int mb_width, mb_height;
diff --git a/libavcodec/mediacodecdec.c b/libavcodec/mediacodecdec.c
index 44f55947be..52b3a2c1f7 100644
--- a/libavcodec/mediacodecdec.c
+++ b/libavcodec/mediacodecdec.c
@@ -146,14 +146,14 @@ static int h264_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format)
for (i = 0; i < MAX_PPS_COUNT; i++) {
if (ps.pps_list[i]) {
- pps = (const PPS*)ps.pps_list[i]->data;
+ pps = ps.pps_list[i];
break;
}
}
if (pps) {
if (ps.sps_list[pps->sps_id]) {
- sps = (const SPS*)ps.sps_list[pps->sps_id]->data;
+ sps = ps.sps_list[pps->sps_id];
}
}
diff --git a/libavcodec/vulkan_h264.c b/libavcodec/vulkan_h264.c
index 32ef32d640..cdc2c7fe30 100644
--- a/libavcodec/vulkan_h264.c
+++ b/libavcodec/vulkan_h264.c
@@ -321,7 +321,7 @@ static int vk_h264_create_params(AVCodecContext *avctx, AVBufferRef **buf)
/* SPS list */
for (int i = 0; i < FF_ARRAY_ELEMS(h->ps.sps_list); i++) {
if (h->ps.sps_list[i]) {
- const SPS *sps_l = (const SPS *)h->ps.sps_list[i]->data;
+ const SPS *sps_l = h->ps.sps_list[i];
int idx = h264_params_info.stdSPSCount;
set_sps(sps_l, &vksps_scaling[idx], &vksps_vui_header[idx], &vksps_vui[idx], &vksps[idx]);
h264_params_info.stdSPSCount++;
@@ -331,7 +331,7 @@ static int vk_h264_create_params(AVCodecContext *avctx, AVBufferRef **buf)
/* PPS list */
for (int i = 0; i < FF_ARRAY_ELEMS(h->ps.pps_list); i++) {
if (h->ps.pps_list[i]) {
- const PPS *pps_l = (const PPS *)h->ps.pps_list[i]->data;
+ const PPS *pps_l = h->ps.pps_list[i];
int idx = h264_params_info.stdPPSCount;
set_pps(pps_l, pps_l->sps, &vkpps_scaling[idx], &vkpps[idx]);
h264_params_info.stdPPSCount++;
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 04/42] avcodec/h264_ps: Use RefStruct API for SPS/PPS
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 04/42] avcodec/h264_ps: Use RefStruct API for SPS/PPS Andreas Rheinhardt
@ 2023-09-28 13:03 ` Anton Khirnov
2023-09-28 15:49 ` Andreas Rheinhardt
0 siblings, 1 reply; 106+ messages in thread
From: Anton Khirnov @ 2023-09-28 13:03 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:56:56)
> diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
> index 5657327f0c..632f5b23b2 100644
> --- a/libavcodec/h264_slice.c
> +++ b/libavcodec/h264_slice.c
> @@ -363,25 +361,16 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
>
> // SPS/PPS
> for (i = 0; i < FF_ARRAY_ELEMS(h->ps.sps_list); i++) {
> - ret = av_buffer_replace(&h->ps.sps_list[i], h1->ps.sps_list[i]);
> - if (ret < 0)
> - return ret;
> + ff_refstruct_replace(&h->ps.sps_list[i], h1->ps.sps_list[i]);
> }
> for (i = 0; i < FF_ARRAY_ELEMS(h->ps.pps_list); i++) {
> - ret = av_buffer_replace(&h->ps.pps_list[i], h1->ps.pps_list[i]);
> - if (ret < 0)
> - return ret;
> + ff_refstruct_replace(&h->ps.pps_list[i], h1->ps.pps_list[i]);
> }
>
> - ret = av_buffer_replace(&h->ps.pps_ref, h1->ps.pps_ref);
> - if (ret < 0)
> - return ret;
> - h->ps.pps = NULL;
> + ff_refstruct_replace(&h->ps.pps, h1->ps.pps);
> h->ps.sps = NULL;
> - if (h1->ps.pps_ref) {
> - h->ps.pps = (const PPS*)h->ps.pps_ref->data;
> + if (h1->ps.pps)
> h->ps.sps = h->ps.pps->sps;
nit: this would look better as
h->ps.sps = h->ps.pps ? h->ps.pps->sps : NULL
Otherwise LGTM
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 04/42] avcodec/h264_ps: Use RefStruct API for SPS/PPS
2023-09-28 13:03 ` Anton Khirnov
@ 2023-09-28 15:49 ` Andreas Rheinhardt
2023-10-02 9:39 ` Anton Khirnov
0 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-28 15:49 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Anton Khirnov:
> Quoting Andreas Rheinhardt (2023-09-19 21:56:56)
>> diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
>> index 5657327f0c..632f5b23b2 100644
>> --- a/libavcodec/h264_slice.c
>> +++ b/libavcodec/h264_slice.c
>> @@ -363,25 +361,16 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
>>
>> // SPS/PPS
>> for (i = 0; i < FF_ARRAY_ELEMS(h->ps.sps_list); i++) {
>> - ret = av_buffer_replace(&h->ps.sps_list[i], h1->ps.sps_list[i]);
>> - if (ret < 0)
>> - return ret;
>> + ff_refstruct_replace(&h->ps.sps_list[i], h1->ps.sps_list[i]);
>> }
>> for (i = 0; i < FF_ARRAY_ELEMS(h->ps.pps_list); i++) {
>> - ret = av_buffer_replace(&h->ps.pps_list[i], h1->ps.pps_list[i]);
>> - if (ret < 0)
>> - return ret;
>> + ff_refstruct_replace(&h->ps.pps_list[i], h1->ps.pps_list[i]);
>> }
>>
>> - ret = av_buffer_replace(&h->ps.pps_ref, h1->ps.pps_ref);
>> - if (ret < 0)
>> - return ret;
>> - h->ps.pps = NULL;
>> + ff_refstruct_replace(&h->ps.pps, h1->ps.pps);
>> h->ps.sps = NULL;
>> - if (h1->ps.pps_ref) {
>> - h->ps.pps = (const PPS*)h->ps.pps_ref->data;
>> + if (h1->ps.pps)
>> h->ps.sps = h->ps.pps->sps;
>
> nit: this would look better as
> h->ps.sps = h->ps.pps ? h->ps.pps->sps : NULL
>
Is there actually a reason not to just use h->ps.sps = h1->ps.sps?
- 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] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 04/42] avcodec/h264_ps: Use RefStruct API for SPS/PPS
2023-09-28 15:49 ` Andreas Rheinhardt
@ 2023-10-02 9:39 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-10-02 9:39 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Quoting Andreas Rheinhardt (2023-09-28 17:49:15)
> Anton Khirnov:
> > Quoting Andreas Rheinhardt (2023-09-19 21:56:56)
> >> diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
> >> index 5657327f0c..632f5b23b2 100644
> >> --- a/libavcodec/h264_slice.c
> >> +++ b/libavcodec/h264_slice.c
> >> @@ -363,25 +361,16 @@ int ff_h264_update_thread_context(AVCodecContext *dst,
> >>
> >> // SPS/PPS
> >> for (i = 0; i < FF_ARRAY_ELEMS(h->ps.sps_list); i++) {
> >> - ret = av_buffer_replace(&h->ps.sps_list[i], h1->ps.sps_list[i]);
> >> - if (ret < 0)
> >> - return ret;
> >> + ff_refstruct_replace(&h->ps.sps_list[i], h1->ps.sps_list[i]);
> >> }
> >> for (i = 0; i < FF_ARRAY_ELEMS(h->ps.pps_list); i++) {
> >> - ret = av_buffer_replace(&h->ps.pps_list[i], h1->ps.pps_list[i]);
> >> - if (ret < 0)
> >> - return ret;
> >> + ff_refstruct_replace(&h->ps.pps_list[i], h1->ps.pps_list[i]);
> >> }
> >>
> >> - ret = av_buffer_replace(&h->ps.pps_ref, h1->ps.pps_ref);
> >> - if (ret < 0)
> >> - return ret;
> >> - h->ps.pps = NULL;
> >> + ff_refstruct_replace(&h->ps.pps, h1->ps.pps);
> >> h->ps.sps = NULL;
> >> - if (h1->ps.pps_ref) {
> >> - h->ps.pps = (const PPS*)h->ps.pps_ref->data;
> >> + if (h1->ps.pps)
> >> h->ps.sps = h->ps.pps->sps;
> >
> > nit: this would look better as
> > h->ps.sps = h->ps.pps ? h->ps.pps->sps : NULL
> >
>
> Is there actually a reason not to just use h->ps.sps = h1->ps.sps?
Probably not a good one.
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 05/42] avcodec/hevc_ps: Use RefStruct API for parameter sets
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (3 preceding siblings ...)
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 04/42] avcodec/h264_ps: Use RefStruct API for SPS/PPS Andreas Rheinhardt
@ 2023-09-19 19:56 ` Andreas Rheinhardt
2023-09-28 13:13 ` Anton Khirnov
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 06/42] avcodec/vp8: Use RefStruct API for seg_map Andreas Rheinhardt
` (43 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:56 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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 = &ps->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(&s->pps_list[id]);
+ ff_refstruct_unref(&s->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(&s->sps_list[id]);
}
- av_buffer_unref(&s->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(&s->vps_list[id]);
}
- av_buffer_unref(&s->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(&vps_buf);
+ !memcmp(ps->vps_list[vps_id], vps, sizeof(*vps))) {
+ ff_refstruct_unref(&vps);
} 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(&vps_buf);
+ ff_refstruct_unref(&vps);
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, unsigned int *sps_id,
- int apply_defdispwin, AVBufferRef **vps_list, AVCodecContext *avctx)
+ int apply_defdispwin, const HEVCVPS * const *vps_list,
+ AVCodecContext *avctx)
{
HEVCWindow *ow;
int ret = 0;
@@ -1269,15 +1269,13 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id,
int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx,
HEVCParamSets *ps, int apply_defdispwin)
{
- HEVCSPS *sps;
- AVBufferRef *sps_buf = av_buffer_allocz(sizeof(*sps));
+ HEVCSPS *sps = ff_refstruct_allocz(sizeof(*sps));
unsigned int sps_id;
int ret;
ptrdiff_t nal_size;
- if (!sps_buf)
+ if (!sps)
return AVERROR(ENOMEM);
- sps = (HEVCSPS*)sps_buf->data;
av_log(avctx, AV_LOG_DEBUG, "Decoding SPS\n");
@@ -1296,7 +1294,7 @@ int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx,
apply_defdispwin,
ps->vps_list, avctx);
if (ret < 0) {
- av_buffer_unref(&sps_buf);
+ ff_refstruct_unref(&sps);
return ret;
}
@@ -1314,19 +1312,19 @@ int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx,
* original one.
* otherwise drop all PPSes that depend on it */
if (ps->sps_list[sps_id] &&
- !memcmp(ps->sps_list[sps_id]->data, sps_buf->data, sps_buf->size)) {
- av_buffer_unref(&sps_buf);
+ !memcmp(ps->sps_list[sps_id], sps, sizeof(*sps))) {
+ ff_refstruct_unref(&sps);
} else {
remove_sps(ps, sps_id);
- ps->sps_list[sps_id] = sps_buf;
+ ps->sps_list[sps_id] = sps;
}
return 0;
}
-static void hevc_pps_free(void *opaque, uint8_t *data)
+static void hevc_pps_free(FFRefStructOpaque unused, void *obj)
{
- HEVCPPS *pps = (HEVCPPS*)data;
+ HEVCPPS *pps = obj;
av_freep(&pps->column_width);
av_freep(&pps->row_height);
@@ -1338,8 +1336,6 @@ static void hevc_pps_free(void *opaque, uint8_t *data)
av_freep(&pps->tile_pos_rs);
av_freep(&pps->tile_id);
av_freep(&pps->min_tb_addr_zs_tab);
-
- av_freep(&pps);
}
static void colour_mapping_octants(GetBitContext *gb, HEVCPPS *pps, int inp_depth,
@@ -1742,19 +1738,11 @@ int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx,
ptrdiff_t nal_size;
unsigned log2_parallel_merge_level_minus2;
- AVBufferRef *pps_buf;
- HEVCPPS *pps = av_mallocz(sizeof(*pps));
+ HEVCPPS *pps = ff_refstruct_alloc_ext(sizeof(*pps), 0, NULL, hevc_pps_free);
if (!pps)
return AVERROR(ENOMEM);
- pps_buf = av_buffer_create((uint8_t *)pps, sizeof(*pps),
- hevc_pps_free, NULL, 0);
- if (!pps_buf) {
- av_freep(&pps);
- return AVERROR(ENOMEM);
- }
-
av_log(avctx, AV_LOG_DEBUG, "Decoding PPS\n");
nal_size = gb->buffer_end - gb->buffer;
@@ -1796,8 +1784,8 @@ int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx,
ret = AVERROR_INVALIDDATA;
goto err;
}
- sps = (HEVCSPS *)ps->sps_list[pps->sps_id]->data;
- vps = (HEVCVPS *)ps->vps_list[sps->vps_id]->data;
+ sps = ps->sps_list[pps->sps_id];
+ vps = ps->vps_list[sps->vps_id];
pps->dependent_slice_segments_enabled_flag = get_bits1(gb);
pps->output_flag_present_flag = get_bits1(gb);
@@ -1998,12 +1986,12 @@ int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx,
}
remove_pps(ps, pps_id);
- ps->pps_list[pps_id] = pps_buf;
+ ps->pps_list[pps_id] = pps;
return 0;
err:
- av_buffer_unref(&pps_buf);
+ ff_refstruct_unref(&pps);
return ret;
}
@@ -2012,11 +2000,11 @@ void ff_hevc_ps_uninit(HEVCParamSets *ps)
int i;
for (i = 0; i < FF_ARRAY_ELEMS(ps->vps_list); i++)
- av_buffer_unref(&ps->vps_list[i]);
+ ff_refstruct_unref(&ps->vps_list[i]);
for (i = 0; i < FF_ARRAY_ELEMS(ps->sps_list); i++)
- av_buffer_unref(&ps->sps_list[i]);
+ ff_refstruct_unref(&ps->sps_list[i]);
for (i = 0; i < FF_ARRAY_ELEMS(ps->pps_list); i++)
- av_buffer_unref(&ps->pps_list[i]);
+ ff_refstruct_unref(&ps->pps_list[i]);
ps->sps = NULL;
ps->pps = NULL;
diff --git a/libavcodec/hevc_ps.h b/libavcodec/hevc_ps.h
index ef11e51ee7..786c896709 100644
--- a/libavcodec/hevc_ps.h
+++ b/libavcodec/hevc_ps.h
@@ -23,7 +23,6 @@
#include <stdint.h>
-#include "libavutil/buffer.h"
#include "libavutil/pixfmt.h"
#include "libavutil/rational.h"
@@ -437,9 +436,9 @@ typedef struct HEVCPPS {
} HEVCPPS;
typedef struct HEVCParamSets {
- AVBufferRef *vps_list[HEVC_MAX_VPS_COUNT];
- AVBufferRef *sps_list[HEVC_MAX_SPS_COUNT];
- AVBufferRef *pps_list[HEVC_MAX_PPS_COUNT];
+ const HEVCVPS *vps_list[HEVC_MAX_VPS_COUNT]; ///< RefStruct references
+ const HEVCSPS *sps_list[HEVC_MAX_SPS_COUNT]; ///< RefStruct references
+ const HEVCPPS *pps_list[HEVC_MAX_PPS_COUNT]; ///< RefStruct references
/* currently active parameter sets */
const HEVCVPS *vps;
@@ -457,7 +456,8 @@ typedef struct HEVCParamSets {
* to an existing VPS
*/
int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id,
- int apply_defdispwin, AVBufferRef **vps_list, AVCodecContext *avctx);
+ int apply_defdispwin, const HEVCVPS * const *vps_list,
+ AVCodecContext *avctx);
int ff_hevc_decode_nal_vps(GetBitContext *gb, AVCodecContext *avctx,
HEVCParamSets *ps);
diff --git a/libavcodec/hevc_sei.c b/libavcodec/hevc_sei.c
index 351e699726..abdb52acd3 100644
--- a/libavcodec/hevc_sei.c
+++ b/libavcodec/hevc_sei.c
@@ -53,11 +53,10 @@ static int decode_nal_sei_pic_timing(HEVCSEI *s, GetBitContext *gb,
const HEVCParamSets *ps, void *logctx)
{
HEVCSEIPictureTiming *h = &s->picture_timing;
- HEVCSPS *sps;
+ const HEVCSPS *sps = ps->sps_list[s->active_seq_parameter_set_id];
- if (!ps->sps_list[s->active_seq_parameter_set_id])
+ if (!sps)
return(AVERROR(ENOMEM));
- sps = (HEVCSPS*)ps->sps_list[s->active_seq_parameter_set_id]->data;
if (sps->vui.frame_field_info_present_flag) {
int pic_struct = get_bits(gb, 4);
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index 81b9c5e089..d64055e1f9 100644
--- a/libavcodec/hevcdec.c
+++ b/libavcodec/hevcdec.c
@@ -50,6 +50,7 @@
#include "hwconfig.h"
#include "internal.h"
#include "profiles.h"
+#include "refstruct.h"
#include "thread.h"
#include "threadframe.h"
@@ -326,7 +327,7 @@ static void export_stream_params(HEVCContext *s, const HEVCSPS *sps)
{
AVCodecContext *avctx = s->avctx;
const HEVCParamSets *ps = &s->ps;
- const HEVCVPS *vps = (const HEVCVPS*)ps->vps_list[sps->vps_id]->data;
+ const HEVCVPS *vps = ps->vps_list[sps->vps_id];
const HEVCWindow *ow = &sps->output_window;
unsigned int num = 0, den = 0;
@@ -573,7 +574,7 @@ static int set_sps(HEVCContext *s, const HEVCSPS *sps,
}
s->ps.sps = sps;
- s->ps.vps = (HEVCVPS*) s->ps.vps_list[s->ps.sps->vps_id]->data;
+ s->ps.vps = s->ps.vps_list[s->ps.sps->vps_id];
return 0;
@@ -616,16 +617,16 @@ static int hls_slice_header(HEVCContext *s)
return AVERROR_INVALIDDATA;
}
if (!sh->first_slice_in_pic_flag &&
- s->ps.pps != (HEVCPPS*)s->ps.pps_list[sh->pps_id]->data) {
+ s->ps.pps != s->ps.pps_list[sh->pps_id]) {
av_log(s->avctx, AV_LOG_ERROR, "PPS changed between slices.\n");
return AVERROR_INVALIDDATA;
}
- s->ps.pps = (HEVCPPS*)s->ps.pps_list[sh->pps_id]->data;
+ s->ps.pps = s->ps.pps_list[sh->pps_id];
if (s->nal_unit_type == HEVC_NAL_CRA_NUT && s->last_eos == 1)
sh->no_output_of_prior_pics_flag = 1;
- if (s->ps.sps != (HEVCSPS*)s->ps.sps_list[s->ps.pps->sps_id]->data) {
- const HEVCSPS *sps = (HEVCSPS*)s->ps.sps_list[s->ps.pps->sps_id]->data;
+ if (s->ps.sps != s->ps.sps_list[s->ps.pps->sps_id]) {
+ const HEVCSPS *sps = s->ps.sps_list[s->ps.pps->sps_id];
enum AVPixelFormat pix_fmt;
ff_hevc_clear_refs(s);
@@ -3301,7 +3302,7 @@ static int hevc_decode_extradata(HEVCContext *s, uint8_t *buf, int length, int f
/* export stream parameters from the first SPS */
for (i = 0; i < FF_ARRAY_ELEMS(s->ps.sps_list); i++) {
if (first && s->ps.sps_list[i]) {
- const HEVCSPS *sps = (const HEVCSPS*)s->ps.sps_list[i]->data;
+ const HEVCSPS *sps = s->ps.sps_list[i];
export_stream_params(s, sps);
break;
}
@@ -3539,23 +3540,14 @@ static int hevc_update_thread_context(AVCodecContext *dst,
if (s->ps.sps != s0->ps.sps)
s->ps.sps = NULL;
- for (i = 0; i < FF_ARRAY_ELEMS(s->ps.vps_list); i++) {
- ret = av_buffer_replace(&s->ps.vps_list[i], s0->ps.vps_list[i]);
- if (ret < 0)
- return ret;
- }
+ for (int i = 0; i < FF_ARRAY_ELEMS(s->ps.vps_list); i++)
+ ff_refstruct_replace(&s->ps.vps_list[i], s0->ps.vps_list[i]);
- for (i = 0; i < FF_ARRAY_ELEMS(s->ps.sps_list); i++) {
- ret = av_buffer_replace(&s->ps.sps_list[i], s0->ps.sps_list[i]);
- if (ret < 0)
- return ret;
- }
+ for (int i = 0; i < FF_ARRAY_ELEMS(s->ps.sps_list); i++)
+ ff_refstruct_replace(&s->ps.sps_list[i], s0->ps.sps_list[i]);
- for (i = 0; i < FF_ARRAY_ELEMS(s->ps.pps_list); i++) {
- ret = av_buffer_replace(&s->ps.pps_list[i], s0->ps.pps_list[i]);
- if (ret < 0)
- return ret;
- }
+ for (int i = 0; i < FF_ARRAY_ELEMS(s->ps.pps_list); i++)
+ ff_refstruct_replace(&s->ps.pps_list[i], s0->ps.pps_list[i]);
if (s->ps.sps != s0->ps.sps)
if ((ret = set_sps(s, s0->ps.sps, src->pix_fmt)) < 0)
diff --git a/libavcodec/mediacodecdec.c b/libavcodec/mediacodecdec.c
index 52b3a2c1f7..b8587289a2 100644
--- a/libavcodec/mediacodecdec.c
+++ b/libavcodec/mediacodecdec.c
@@ -223,21 +223,21 @@ static int hevc_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format)
for (i = 0; i < HEVC_MAX_VPS_COUNT; i++) {
if (ps.vps_list[i]) {
- vps = (const HEVCVPS*)ps.vps_list[i]->data;
+ vps = ps.vps_list[i];
break;
}
}
for (i = 0; i < HEVC_MAX_PPS_COUNT; i++) {
if (ps.pps_list[i]) {
- pps = (const HEVCPPS*)ps.pps_list[i]->data;
+ pps = ps.pps_list[i];
break;
}
}
if (pps) {
if (ps.sps_list[pps->sps_id]) {
- sps = (const HEVCSPS*)ps.sps_list[pps->sps_id]->data;
+ sps = ps.sps_list[pps->sps_id];
}
}
diff --git a/libavcodec/videotoolbox.c b/libavcodec/videotoolbox.c
index 963379d483..43fd2e3fea 100644
--- a/libavcodec/videotoolbox.c
+++ b/libavcodec/videotoolbox.c
@@ -246,7 +246,7 @@ CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx)
#define COUNT_SIZE_PS(T, t) \
for (i = 0; i < HEVC_MAX_##T##PS_COUNT; i++) { \
if (h->ps.t##ps_list[i]) { \
- const HEVC##T##PS *lps = (const HEVC##T##PS *)h->ps.t##ps_list[i]->data; \
+ const HEVC##T##PS *lps = h->ps.t##ps_list[i]; \
vt_extradata_size += 2 + escape_ps(NULL, lps->data, lps->data_size); \
num_##t##ps++; \
} \
@@ -369,7 +369,7 @@ CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx)
p += 3; \
for (i = 0; i < HEVC_MAX_##T##PS_COUNT; i++) { \
if (h->ps.t##ps_list[i]) { \
- const HEVC##T##PS *lps = (const HEVC##T##PS *)h->ps.t##ps_list[i]->data; \
+ const HEVC##T##PS *lps = h->ps.t##ps_list[i]; \
int size = escape_ps(p + 2, lps->data, lps->data_size); \
/* unsigned int(16) nalUnitLength; */ \
AV_WB16(p, size); \
diff --git a/libavcodec/vulkan_hevc.c b/libavcodec/vulkan_hevc.c
index 52f223ceb2..395cbd3008 100644
--- a/libavcodec/vulkan_hevc.c
+++ b/libavcodec/vulkan_hevc.c
@@ -70,14 +70,14 @@ typedef struct HEVCHeaderSet {
static int alloc_hevc_header_structs(FFVulkanDecodeContext *s,
int nb_vps,
- AVBufferRef * const vps_list[HEVC_MAX_VPS_COUNT])
+ const HEVCVPS * const vps_list[HEVC_MAX_VPS_COUNT])
{
uint8_t *data_ptr;
HEVCHeaderSet *hdr;
size_t buf_size = sizeof(HEVCHeaderSet) + nb_vps*sizeof(HEVCHeaderVPS);
for (int i = 0; i < nb_vps; i++) {
- const HEVCVPS *vps = (const HEVCVPS *)vps_list[i]->data;
+ const HEVCVPS *vps = vps_list[i];
buf_size += sizeof(HEVCHeaderVPSSet)*vps->vps_num_hrd_parameters;
}
@@ -96,7 +96,7 @@ static int alloc_hevc_header_structs(FFVulkanDecodeContext *s,
hdr->hvps = (HEVCHeaderVPS *)(data_ptr + sizeof(HEVCHeaderSet));
data_ptr += sizeof(HEVCHeaderSet) + nb_vps*sizeof(HEVCHeaderVPS);
for (int i = 0; i < nb_vps; i++) {
- const HEVCVPS *vps = (const HEVCVPS *)vps_list[i]->data;
+ const HEVCVPS *vps = vps_list[i];
hdr->hvps[i].sls = (HEVCHeaderVPSSet *)data_ptr;
data_ptr += sizeof(HEVCHeaderVPSSet)*vps->vps_num_hrd_parameters;
}
@@ -673,7 +673,7 @@ static int vk_hevc_create_params(AVCodecContext *avctx, AVBufferRef **buf)
/* SPS list */
for (int i = 0; h->ps.sps_list[i]; i++) {
- const HEVCSPS *sps_l = (const HEVCSPS *)h->ps.sps_list[i]->data;
+ const HEVCSPS *sps_l = h->ps.sps_list[i];
set_sps(sps_l, i, &hdr->hsps[i].scaling, &hdr->hsps[i].vui_header,
&hdr->hsps[i].vui, &hdr->sps[i], hdr->hsps[i].nal_hdr,
hdr->hsps[i].vcl_hdr, &hdr->hsps[i].ptl, &hdr->hsps[i].dpbm,
@@ -683,15 +683,15 @@ static int vk_hevc_create_params(AVCodecContext *avctx, AVBufferRef **buf)
/* PPS list */
for (int i = 0; h->ps.pps_list[i]; i++) {
- const HEVCPPS *pps_l = (const HEVCPPS *)h->ps.pps_list[i]->data;
- const HEVCSPS *sps_l = (const HEVCSPS *)h->ps.sps_list[pps_l->sps_id]->data;
+ const HEVCPPS *pps_l = h->ps.pps_list[i];
+ const HEVCSPS *sps_l = h->ps.sps_list[pps_l->sps_id];
set_pps(pps_l, sps_l, &hdr->hpps[i].scaling, &hdr->pps[i], &hdr->hpps[i].pal);
h265_params_info.stdPPSCount++;
}
/* VPS list */
for (int i = 0; i < nb_vps; i++) {
- const HEVCVPS *vps_l = (const HEVCVPS *)h->ps.vps_list[i]->data;
+ const HEVCVPS *vps_l = h->ps.vps_list[i];
set_vps(vps_l, &hdr->vps[i], &hdr->hvps[i].ptl, &hdr->hvps[i].dpbm,
hdr->hvps[i].hdr, hdr->hvps[i].sls);
h265_params_info.stdVPSCount++;
@@ -871,7 +871,7 @@ static int vk_hevc_end_frame(AVCodecContext *avctx)
if (!pps) {
unsigned int pps_id = h->sh.pps_id;
if (pps_id < HEVC_MAX_PPS_COUNT && h->ps.pps_list[pps_id] != NULL)
- pps = (const HEVCPPS *)h->ps.pps_list[pps_id]->data;
+ pps = h->ps.pps_list[pps_id];
}
if (!pps) {
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 05/42] avcodec/hevc_ps: Use RefStruct API for parameter sets
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 05/42] avcodec/hevc_ps: Use RefStruct API for parameter sets Andreas Rheinhardt
@ 2023-09-28 13:13 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-09-28 13:13 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:56:57)
> 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 <andreas.rheinhardt@outlook.com>
> ---
> 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(-)
LGTM
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 06/42] avcodec/vp8: Use RefStruct API for seg_map
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (4 preceding siblings ...)
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 05/42] avcodec/hevc_ps: Use RefStruct API for parameter sets Andreas Rheinhardt
@ 2023-09-19 19:56 ` Andreas Rheinhardt
2023-10-02 9:44 ` Anton Khirnov
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 07/42] avcodec/wavpack: Use RefStruct API for DSD context Andreas Rheinhardt
` (42 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:56 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
Avoids allocations and error checks when syncing the buffers.
Also avoids indirections.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
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, &f->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, &f->hwaccel_picture_private,
&f->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(&f->seg_map);
+ ff_refstruct_unref(&f->seg_map);
ff_thread_release_ext_buffer(s->avctx, &f->tf);
return ret;
}
static void vp8_release_frame(VP8Context *s, VP8Frame *f)
{
- av_buffer_unref(&f->seg_map);
+ ff_refstruct_unref(&f->seg_map);
av_buffer_unref(&f->hwaccel_priv_buf);
f->hwaccel_picture_private = NULL;
ff_thread_release_ext_buffer(s->avctx, &f->tf);
@@ -139,11 +138,7 @@ static int vp8_ref_frame(VP8Context *s, VP8Frame *dst, const VP8Frame *src)
if ((ret = ff_thread_ref_frame(&dst->tf, &src->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(&dst->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, &s->mv_bounds, mb, mb_x, mb_y, curframe->seg_map->data + mb_xy,
+ decode_mb_mode(s, &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, &td->mv_bounds, mb, mb_x, mb_y, curframe->seg_map->data + mb_xy,
+ decode_mb_mode(s, &td->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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 06/42] avcodec/vp8: Use RefStruct API for seg_map
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 06/42] avcodec/vp8: Use RefStruct API for seg_map Andreas Rheinhardt
@ 2023-10-02 9:44 ` Anton Khirnov
2023-10-02 10:04 ` Andreas Rheinhardt
0 siblings, 1 reply; 106+ messages in thread
From: Anton Khirnov @ 2023-10-02 9:44 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:56:58)
> @@ -139,11 +138,7 @@ static int vp8_ref_frame(VP8Context *s, VP8Frame *dst, const VP8Frame *src)
>
> if ((ret = ff_thread_ref_frame(&dst->tf, &src->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(&dst->seg_map, src->seg_map);
It seems misleading to use replace rather than ref when dst is clean at
this point.
Otherwise looks ok.
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 06/42] avcodec/vp8: Use RefStruct API for seg_map
2023-10-02 9:44 ` Anton Khirnov
@ 2023-10-02 10:04 ` Andreas Rheinhardt
2023-10-02 10:14 ` Anton Khirnov
0 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-10-02 10:04 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Anton Khirnov:
> Quoting Andreas Rheinhardt (2023-09-19 21:56:58)
>> @@ -139,11 +138,7 @@ static int vp8_ref_frame(VP8Context *s, VP8Frame *dst, const VP8Frame *src)
>>
>> if ((ret = ff_thread_ref_frame(&dst->tf, &src->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(&dst->seg_map, src->seg_map);
>
> It seems misleading to use replace rather than ref when dst is clean at
> this point.
>
This is done with an eye towards 37/42, in which vp8_ref_frame() will be
replaced by vp8_replace_frame().
> Otherwise looks ok.
>
_______________________________________________
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] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 06/42] avcodec/vp8: Use RefStruct API for seg_map
2023-10-02 10:04 ` Andreas Rheinhardt
@ 2023-10-02 10:14 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-10-02 10:14 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Quoting Andreas Rheinhardt (2023-10-02 12:04:02)
> Anton Khirnov:
> > Quoting Andreas Rheinhardt (2023-09-19 21:56:58)
> >> @@ -139,11 +138,7 @@ static int vp8_ref_frame(VP8Context *s, VP8Frame *dst, const VP8Frame *src)
> >>
> >> if ((ret = ff_thread_ref_frame(&dst->tf, &src->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(&dst->seg_map, src->seg_map);
> >
> > It seems misleading to use replace rather than ref when dst is clean at
> > this point.
> >
>
> This is done with an eye towards 37/42, in which vp8_ref_frame() will be
> replaced by vp8_replace_frame().
ah, nevermind then
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 07/42] avcodec/wavpack: Use RefStruct API for DSD context
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (5 preceding siblings ...)
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 06/42] avcodec/vp8: Use RefStruct API for seg_map Andreas Rheinhardt
@ 2023-09-19 19:56 ` Andreas Rheinhardt
2023-10-02 9:46 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 08/42] avcodec/dovi_rpu: Use RefStruct API for Vdr data Andreas Rheinhardt
` (41 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:56 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
It avoids allocations and the corresponding error checks.
It also avoids indirections and casts.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
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(&s->dsd_ref);
+ ff_refstruct_unref(&s->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(&fdst->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(&fdst->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, &s->prev_frame);
av_frame_free(&s->prev_frame.f);
- av_buffer_unref(&s->dsd_ref);
+ ff_refstruct_unref(&s->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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 08/42] avcodec/dovi_rpu: Use RefStruct API for Vdr data
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (6 preceding siblings ...)
2023-09-19 19:56 ` [FFmpeg-devel] [PATCH 07/42] avcodec/wavpack: Use RefStruct API for DSD context Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-10-02 9:51 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 09/42] avcodec/refstruct: Allow checking for exclusive ownership Andreas Rheinhardt
` (40 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
It avoids allocations and the corresponding error checks.
Also avoids casts and indirections.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
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(&s->vdr_ref[i]);
+ for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr); i++)
+ ff_refstruct_unref(&s->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(&s->vdr_ref[i]);
+ for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr); i++)
+ ff_refstruct_unref(&s->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(&s->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(&s->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 = &s->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 = &vdr->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 = &vdr->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 = &vdr->color;
/* Update values of affected_dm_id */
- vdr = (DOVIVdrRef *) s->vdr_ref[affected_dm_id]->data;
+ vdr = s->vdr[affected_dm_id];
color = &vdr->color;
color->dm_metadata_id = affected_dm_id;
color->scene_refresh_flag = get_ue_golomb_31(gb);
diff --git a/libavcodec/dovi_rpu.h b/libavcodec/dovi_rpu.h
index f6ca5bbbc5..51c5fdbb87 100644
--- a/libavcodec/dovi_rpu.h
+++ b/libavcodec/dovi_rpu.h
@@ -47,12 +47,12 @@ typedef struct DOVIContext {
/**
* Private fields internal to dovi_rpu.c
*/
- AVBufferRef *vdr_ref[DOVI_MAX_DM_ID+1];
+ struct DOVIVdr *vdr[DOVI_MAX_DM_ID+1]; ///< RefStruct references
uint8_t dv_profile;
} DOVIContext;
-int ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0);
+void ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0);
/**
* Completely reset a DOVIContext, preserving only logctx.
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index d64055e1f9..44a9680415 100644
--- a/libavcodec/hevcdec.c
+++ b/libavcodec/hevcdec.c
@@ -3584,9 +3584,7 @@ static int hevc_update_thread_context(AVCodecContext *dst,
if (ret < 0)
return ret;
- ret = ff_dovi_ctx_replace(&s->dovi_ctx, &s0->dovi_ctx);
- if (ret < 0)
- return ret;
+ ff_dovi_ctx_replace(&s->dovi_ctx, &s0->dovi_ctx);
ret = av_buffer_replace(&s->sei.common.dynamic_hdr_vivid.info,
s0->sei.common.dynamic_hdr_vivid.info);
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 08/42] avcodec/dovi_rpu: Use RefStruct API for Vdr data
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 08/42] avcodec/dovi_rpu: Use RefStruct API for Vdr data Andreas Rheinhardt
@ 2023-10-02 9:51 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-10-02 9:51 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:00)
> It avoids allocations and the corresponding error checks.
> Also avoids casts and indirections.
>
> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
> ---
> 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.
Should update the comment as well.
Otherwise looks good.
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 09/42] avcodec/refstruct: Allow checking for exclusive ownership
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (7 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 08/42] avcodec/dovi_rpu: Use RefStruct API for Vdr data Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 10/42] avcodec/cbs: Use RefStruct-API for unit content Andreas Rheinhardt
` (39 subsequent siblings)
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
This is the analog of av_buffer_is_writable();
it will be used in the next commit.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
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, &dst, 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*)&ref->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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 10/42] avcodec/cbs: Use RefStruct-API for unit content
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (8 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 09/42] avcodec/refstruct: Allow checking for exclusive ownership Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 11/42] avcodec/cbs_sei: Use RefStruct API for SEI messages Andreas Rheinhardt
` (38 subsequent siblings)
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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(&f->hwaccel_priv_buf);
f->hwaccel_picture_private = NULL;
- av_buffer_unref(&f->header_ref);
+ ff_refstruct_unref(&f->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(&dst->header_ref, src->header_ref);
- if (ret < 0)
- return ret;
+ ff_refstruct_replace(&dst->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, &s->cur_frame);
av_frame_free(&s->cur_frame.f);
- av_buffer_unref(&s->seq_ref);
- av_buffer_unref(&s->header_ref);
- av_buffer_unref(&s->cll_ref);
- av_buffer_unref(&s->mdcv_ref);
+ ff_refstruct_unref(&s->seq_ref);
+ ff_refstruct_unref(&s->header_ref);
+ ff_refstruct_unref(&s->cll_ref);
+ ff_refstruct_unref(&s->mdcv_ref);
av_freep(&s->tile_group_info);
while (s->itut_t35_fifo && av_fifo_read(s->itut_t35_fifo, &itut_t35, 1) >= 0)
@@ -1160,9 +1159,7 @@ static int get_current_frame(AVCodecContext *avctx)
av1_frame_unref(avctx, &s->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(&s->seq_ref);
- s->seq_ref = av_buffer_ref(unit->content_ref);
- if (!s->seq_ref) {
- ret = AVERROR(ENOMEM);
- goto end;
- }
+ ff_refstruct_replace(&s->seq_ref, unit->content_ref);
s->raw_seq = &obu->obu.sequence_header;
@@ -1264,12 +1256,7 @@ static int av1_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame)
goto end;
}
- av_buffer_unref(&s->header_ref);
- s->header_ref = av_buffer_ref(unit->content_ref);
- if (!s->header_ref) {
- ret = AVERROR(ENOMEM);
- goto end;
- }
+ ff_refstruct_replace(&s->header_ref, unit->content_ref);
if (unit->type == AV1_OBU_FRAME)
s->raw_frame_header = &obu->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(&s->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(&s->cll_ref, unit->content_ref);
s->cll = &obu->obu.metadata.metadata.hdr_cll;
break;
case AV1_METADATA_TYPE_HDR_MDCV:
- av_buffer_unref(&s->mdcv_ref);
- s->mdcv_ref = av_buffer_ref(unit->content_ref);
- if (!s->mdcv_ref) {
- s->mdcv = NULL;
- ret = AVERROR(ENOMEM);
- goto end;
- }
+ ff_refstruct_replace(&s->mdcv_ref, unit->content_ref);
s->mdcv = &obu->obu.metadata.metadata.hdr_mdcv;
break;
case AV1_METADATA_TYPE_ITUT_T35: {
diff --git a/libavcodec/av1dec.h b/libavcodec/av1dec.h
index 59ffed1d9b..acbeec4af3 100644
--- a/libavcodec/av1dec.h
+++ b/libavcodec/av1dec.h
@@ -38,7 +38,7 @@ typedef struct AV1Frame {
AVBufferRef *hwaccel_priv_buf;
void *hwaccel_picture_private;
- AVBufferRef *header_ref;
+ AV1RawOBU *header_ref; ///< RefStruct reference backing raw_frame_header.
AV1RawFrameHeader *raw_frame_header;
int temporal_id;
@@ -71,15 +71,15 @@ typedef struct AV1DecContext {
CodedBitstreamFragment current_obu;
AVPacket *pkt;
- AVBufferRef *seq_ref;
+ AV1RawOBU *seq_ref; ///< RefStruct reference backing raw_seq
AV1RawSequenceHeader *raw_seq;
- AVBufferRef *header_ref;
+ AV1RawOBU *header_ref; ///< RefStruct reference backing raw_frame_header
AV1RawFrameHeader *raw_frame_header;
TileGroupInfo *tile_group_info;
- AVBufferRef *cll_ref;
+ AV1RawOBU *cll_ref; ///< RefStruct reference backing cll
AV1RawMetadataHDRCLL *cll;
- AVBufferRef *mdcv_ref;
+ AV1RawOBU *mdcv_ref; ///< RefStruct reference backing mdcv
AV1RawMetadataHDRMDCV *mdcv;
AVFifo *itut_t35_fifo;
diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c
index 3ec8285e21..00c462b09d 100644
--- a/libavcodec/cbs.c
+++ b/libavcodec/cbs.c
@@ -28,6 +28,7 @@
#include "avcodec.h"
#include "cbs.h"
#include "cbs_internal.h"
+#include "refstruct.h"
static const CodedBitstreamType *const cbs_type_table[] = {
@@ -151,7 +152,7 @@ av_cold void ff_cbs_close(CodedBitstreamContext **ctx_ptr)
static void cbs_unit_uninit(CodedBitstreamUnit *unit)
{
- av_buffer_unref(&unit->content_ref);
+ ff_refstruct_unref(&unit->content_ref);
unit->content = NULL;
av_buffer_unref(&unit->data_ref);
@@ -199,7 +200,7 @@ static int cbs_read_fragment_content(CodedBitstreamContext *ctx,
continue;
}
- av_buffer_unref(&unit->content_ref);
+ ff_refstruct_unref(&unit->content_ref);
unit->content = NULL;
av_assert0(unit->data && unit->data_ref);
@@ -213,7 +214,7 @@ static int cbs_read_fragment_content(CodedBitstreamContext *ctx,
av_log(ctx->log_ctx, AV_LOG_VERBOSE,
"Skipping decomposition of unit %d "
"(type %"PRIu32").\n", i, unit->type);
- av_buffer_unref(&unit->content_ref);
+ ff_refstruct_unref(&unit->content_ref);
unit->content = NULL;
} else if (err < 0) {
av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to read unit %d "
@@ -773,28 +774,22 @@ int ff_cbs_insert_unit_content(CodedBitstreamFragment *frag,
int position,
CodedBitstreamUnitType type,
void *content,
- AVBufferRef *content_buf)
+ void *content_ref)
{
CodedBitstreamUnit *unit;
- AVBufferRef *content_ref;
int err;
if (position == -1)
position = frag->nb_units;
av_assert0(position >= 0 && position <= frag->nb_units);
- if (content_buf) {
- content_ref = av_buffer_ref(content_buf);
- if (!content_ref)
- return AVERROR(ENOMEM);
- } else {
- content_ref = NULL;
- }
-
err = cbs_insert_unit(frag, position);
- if (err < 0) {
- av_buffer_unref(&content_ref);
+ if (err < 0)
return err;
+
+ if (content_ref) {
+ // Create our own reference out of the user-supplied one.
+ content_ref = ff_refstruct_ref(content_ref);
}
unit = &frag->units[position];
@@ -868,15 +863,14 @@ void ff_cbs_delete_unit(CodedBitstreamFragment *frag,
(frag->nb_units - position) * sizeof(*frag->units));
}
-static void cbs_default_free_unit_content(void *opaque, uint8_t *data)
+static void cbs_default_free_unit_content(FFRefStructOpaque opaque, void *content)
{
- const CodedBitstreamUnitTypeDescriptor *desc = opaque;
+ const CodedBitstreamUnitTypeDescriptor *desc = opaque.c;
for (int i = 0; i < desc->type.ref.nb_offsets; i++) {
- void **ptr = (void**)(data + desc->type.ref.offsets[i]);
+ void **ptr = (void**)((char*)content + desc->type.ref.offsets[i]);
av_buffer_unref((AVBufferRef**)(ptr + 1));
}
- av_free(data);
}
static const CodedBitstreamUnitTypeDescriptor
@@ -907,6 +901,15 @@ static const CodedBitstreamUnitTypeDescriptor
return NULL;
}
+static void *cbs_alloc_content(const CodedBitstreamUnitTypeDescriptor *desc)
+{
+ 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);
+}
+
int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx,
CodedBitstreamUnit *unit)
{
@@ -918,27 +921,17 @@ int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx,
if (!desc)
return AVERROR(ENOSYS);
- unit->content = av_mallocz(desc->content_size);
- if (!unit->content)
+ unit->content_ref = cbs_alloc_content(desc);
+ if (!unit->content_ref)
return AVERROR(ENOMEM);
-
- unit->content_ref =
- av_buffer_create(unit->content, desc->content_size,
- desc->content_type == CBS_CONTENT_TYPE_COMPLEX
- ? desc->type.complex.content_free
- : cbs_default_free_unit_content,
- (void*)desc, 0);
- if (!unit->content_ref) {
- av_freep(&unit->content);
- return AVERROR(ENOMEM);
- }
+ unit->content = unit->content_ref;
return 0;
}
-static int cbs_clone_internal_refs_unit_content(AVBufferRef **clone_ref,
- const CodedBitstreamUnit *unit,
- const CodedBitstreamUnitTypeDescriptor *desc)
+static int cbs_clone_noncomplex_unit_content(void **clonep,
+ const CodedBitstreamUnit *unit,
+ const CodedBitstreamUnitTypeDescriptor *desc)
{
const uint8_t *src;
uint8_t *copy;
@@ -947,9 +940,15 @@ static int cbs_clone_internal_refs_unit_content(AVBufferRef **clone_ref,
av_assert0(unit->content);
src = unit->content;
- copy = av_memdup(src, desc->content_size);
+ copy = cbs_alloc_content(desc);
if (!copy)
return AVERROR(ENOMEM);
+ memcpy(copy, src, desc->content_size);
+ for (int i = 0; i < desc->type.ref.nb_offsets; i++) {
+ void **ptr = (void**)(copy + desc->type.ref.offsets[i]);
+ /* Zero all the AVBufferRefs as they are owned by src. */
+ *(ptr + 1) = NULL;
+ }
for (i = 0; i < desc->type.ref.nb_offsets; i++) {
const uint8_t *const *src_ptr = (const uint8_t* const*)(src + desc->type.ref.offsets[i]);
@@ -975,22 +974,12 @@ static int cbs_clone_internal_refs_unit_content(AVBufferRef **clone_ref,
goto fail;
}
}
-
- *clone_ref = av_buffer_create(copy, desc->content_size,
- cbs_default_free_unit_content,
- (void*)desc, 0);
- if (!*clone_ref) {
- err = AVERROR(ENOMEM);
- goto fail;
- }
+ *clonep = copy;
return 0;
fail:
- for (--i; i >= 0; i--)
- av_buffer_unref((AVBufferRef**)(copy + desc->type.ref.offsets[i]));
- av_freep(©);
- *clone_ref = NULL;
+ ff_refstruct_unref(©);
return err;
}
@@ -1003,7 +992,7 @@ static int cbs_clone_unit_content(CodedBitstreamContext *ctx,
CodedBitstreamUnit *unit)
{
const CodedBitstreamUnitTypeDescriptor *desc;
- AVBufferRef *ref;
+ void *new_content;
int err;
desc = cbs_find_unit_type_desc(ctx, unit);
@@ -1012,13 +1001,13 @@ static int cbs_clone_unit_content(CodedBitstreamContext *ctx,
switch (desc->content_type) {
case CBS_CONTENT_TYPE_INTERNAL_REFS:
- err = cbs_clone_internal_refs_unit_content(&ref, unit, desc);
+ err = cbs_clone_noncomplex_unit_content(&new_content, unit, desc);
break;
case CBS_CONTENT_TYPE_COMPLEX:
if (!desc->type.complex.content_clone)
return AVERROR_PATCHWELCOME;
- err = desc->type.complex.content_clone(&ref, unit);
+ err = desc->type.complex.content_clone(&new_content, unit);
break;
default:
@@ -1028,8 +1017,8 @@ static int cbs_clone_unit_content(CodedBitstreamContext *ctx,
if (err < 0)
return err;
- unit->content_ref = ref;
- unit->content = ref->data;
+ unit->content_ref = new_content;
+ unit->content = new_content;
return 0;
}
@@ -1045,17 +1034,17 @@ int ff_cbs_make_unit_refcounted(CodedBitstreamContext *ctx,
int ff_cbs_make_unit_writable(CodedBitstreamContext *ctx,
CodedBitstreamUnit *unit)
{
- AVBufferRef *ref = unit->content_ref;
+ void *ref = unit->content_ref;
int err;
av_assert0(unit->content);
- if (ref && av_buffer_is_writable(ref))
+ if (ref && ff_refstruct_exclusive(ref))
return 0;
err = cbs_clone_unit_content(ctx, unit);
if (err < 0)
return err;
- av_buffer_unref(&ref);
+ ff_refstruct_unref(&ref);
return 0;
}
diff --git a/libavcodec/cbs.h b/libavcodec/cbs.h
index b4131db5fe..68f7e4b0a9 100644
--- a/libavcodec/cbs.h
+++ b/libavcodec/cbs.h
@@ -106,10 +106,10 @@ typedef struct CodedBitstreamUnit {
*/
void *content;
/**
- * If content is reference counted, a reference to the buffer containing
- * content. Null if content is not reference counted.
+ * If content is reference counted, a RefStruct reference backing content.
+ * NULL if content is not reference counted.
*/
- AVBufferRef *content_ref;
+ void *content_ref;
} CodedBitstreamUnit;
/**
@@ -375,14 +375,16 @@ int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx,
/**
* Insert a new unit into a fragment with the given content.
*
+ * If content_ref is supplied, it has to be a RefStruct reference
+ * backing content; the user keeps ownership of the supplied reference.
* The content structure continues to be owned by the caller if
- * content_buf is not supplied.
+ * content_ref is not supplied.
*/
int ff_cbs_insert_unit_content(CodedBitstreamFragment *frag,
int position,
CodedBitstreamUnitType type,
void *content,
- AVBufferRef *content_buf);
+ void *content_ref);
/**
* Add a new unit to a fragment with the given data bitstream.
diff --git a/libavcodec/cbs_av1.c b/libavcodec/cbs_av1.c
index 7fb5bd8b42..50a5c3e117 100644
--- a/libavcodec/cbs_av1.c
+++ b/libavcodec/cbs_av1.c
@@ -24,6 +24,7 @@
#include "cbs_internal.h"
#include "cbs_av1.h"
#include "defs.h"
+#include "refstruct.h"
static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc,
@@ -953,12 +954,7 @@ static int cbs_av1_read_unit(CodedBitstreamContext *ctx,
priv->operating_point_idc = sequence_header->operating_point_idc[priv->operating_point];
}
- av_buffer_unref(&priv->sequence_header_ref);
- priv->sequence_header = NULL;
-
- priv->sequence_header_ref = av_buffer_ref(unit->content_ref);
- if (!priv->sequence_header_ref)
- return AVERROR(ENOMEM);
+ ff_refstruct_replace(&priv->sequence_header_ref, unit->content_ref);
priv->sequence_header = &obu->obu.sequence_header;
}
break;
@@ -1077,9 +1073,7 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
av1ctx = *priv;
if (priv->sequence_header_ref) {
- av1ctx.sequence_header_ref = av_buffer_ref(priv->sequence_header_ref);
- if (!av1ctx.sequence_header_ref)
- return AVERROR(ENOMEM);
+ av1ctx.sequence_header_ref = ff_refstruct_ref(priv->sequence_header_ref);
}
if (priv->frame_header_ref) {
@@ -1112,19 +1106,14 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
if (err < 0)
goto error;
- av_buffer_unref(&priv->sequence_header_ref);
+ ff_refstruct_unref(&priv->sequence_header_ref);
priv->sequence_header = NULL;
err = ff_cbs_make_unit_refcounted(ctx, unit);
if (err < 0)
goto error;
- priv->sequence_header_ref = av_buffer_ref(unit->content_ref);
- if (!priv->sequence_header_ref) {
- err = AVERROR(ENOMEM);
- goto error;
- }
-
+ priv->sequence_header_ref = ff_refstruct_ref(unit->content_ref);
priv->sequence_header = &obu->obu.sequence_header;
}
break;
@@ -1227,7 +1216,7 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
av_assert0(data_pos <= start_pos);
if (8 * obu->obu_size > put_bits_left(pbc)) {
- av_buffer_unref(&priv->sequence_header_ref);
+ ff_refstruct_unref(&priv->sequence_header_ref);
av_buffer_unref(&priv->frame_header_ref);
*priv = av1ctx;
@@ -1251,7 +1240,7 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx,
err = 0;
error:
- av_buffer_unref(&av1ctx.sequence_header_ref);
+ ff_refstruct_unref(&av1ctx.sequence_header_ref);
av_buffer_unref(&av1ctx.frame_header_ref);
return err;
@@ -1303,13 +1292,13 @@ static void cbs_av1_close(CodedBitstreamContext *ctx)
{
CodedBitstreamAV1Context *priv = ctx->priv_data;
- av_buffer_unref(&priv->sequence_header_ref);
+ ff_refstruct_unref(&priv->sequence_header_ref);
av_buffer_unref(&priv->frame_header_ref);
}
-static void cbs_av1_free_metadata(void *unit, uint8_t *content)
+static void cbs_av1_free_metadata(FFRefStructOpaque unused, void *content)
{
- AV1RawOBU *obu = (AV1RawOBU*)content;
+ AV1RawOBU *obu = content;
AV1RawMetadata *md;
av_assert0(obu->header.obu_type == AV1_OBU_METADATA);
@@ -1327,7 +1316,6 @@ static void cbs_av1_free_metadata(void *unit, uint8_t *content)
default:
av_buffer_unref(&md->metadata.unknown.payload_ref);
}
- av_free(content);
}
static const CodedBitstreamUnitTypeDescriptor cbs_av1_unit_types[] = {
diff --git a/libavcodec/cbs_av1.h b/libavcodec/cbs_av1.h
index 64dfdce9c4..63917f2f16 100644
--- a/libavcodec/cbs_av1.h
+++ b/libavcodec/cbs_av1.h
@@ -437,7 +437,8 @@ typedef struct CodedBitstreamAV1Context {
const AVClass *class;
AV1RawSequenceHeader *sequence_header;
- AVBufferRef *sequence_header_ref;
+ /** A RefStruct reference backing sequence_header. */
+ AV1RawOBU *sequence_header_ref;
int seen_frame_header;
AVBufferRef *frame_header_ref;
diff --git a/libavcodec/cbs_h264.h b/libavcodec/cbs_h264.h
index ca9b688c05..db91231337 100644
--- a/libavcodec/cbs_h264.h
+++ b/libavcodec/cbs_h264.h
@@ -407,10 +407,8 @@ typedef struct CodedBitstreamH264Context {
// All currently available parameter sets. These are updated when
// any parameter set NAL unit is read/written with this context.
- AVBufferRef *sps_ref[H264_MAX_SPS_COUNT];
- AVBufferRef *pps_ref[H264_MAX_PPS_COUNT];
- H264RawSPS *sps[H264_MAX_SPS_COUNT];
- H264RawPPS *pps[H264_MAX_PPS_COUNT];
+ H264RawSPS *sps[H264_MAX_SPS_COUNT]; ///< RefStruct references
+ H264RawPPS *pps[H264_MAX_PPS_COUNT]; ///< RefStruct references
// The currently active parameter sets. These are updated when any
// NAL unit refers to the relevant parameter set. These pointers
diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c
index 318c997d94..e071442c31 100644
--- a/libavcodec/cbs_h2645.c
+++ b/libavcodec/cbs_h2645.c
@@ -28,6 +28,7 @@
#include "h264.h"
#include "h2645_parse.h"
#include "hevc.h"
+#include "refstruct.h"
#include "vvc.h"
@@ -759,12 +760,8 @@ static int cbs_h26 ## h26n ## _replace_ ## ps_var(CodedBitstreamContext *ctx, \
return err; \
if (priv->ps_var[id] == priv->active_ ## ps_var) \
priv->active_ ## ps_var = NULL ; \
- av_buffer_unref(&priv->ps_var ## _ref[id]); \
av_assert0(unit->content_ref); \
- priv->ps_var ## _ref[id] = av_buffer_ref(unit->content_ref); \
- if (!priv->ps_var ## _ref[id]) \
- return AVERROR(ENOMEM); \
- priv->ps_var[id] = (H26 ## h26n ## Raw ## ps_name *)priv->ps_var ## _ref[id]->data; \
+ ff_refstruct_replace(&priv->ps_var[id], unit->content_ref); \
return 0; \
}
@@ -784,12 +781,8 @@ static int cbs_h26 ## h26n ## _replace_ ## ps_var(CodedBitstreamContext *ctx, \
int err = ff_cbs_make_unit_refcounted(ctx, unit); \
if (err < 0) \
return err; \
- av_buffer_unref(&priv->ps_var ## _ref[id]); \
av_assert0(unit->content_ref); \
- priv->ps_var ## _ref[id] = av_buffer_ref(unit->content_ref); \
- if (!priv->ps_var ## _ref[id]) \
- return AVERROR(ENOMEM); \
- priv->ps_var[id] = (H26 ## h26n ## Raw ## ps_name *)priv->ps_var ## _ref[id]->data; \
+ ff_refstruct_replace(&priv->ps_var[id], unit->content_ref); \
return 0; \
}
@@ -808,9 +801,7 @@ static int cbs_h266_replace_ph(CodedBitstreamContext *ctx,
if (err < 0)
return err;
av_assert0(unit->content_ref);
- err = av_buffer_replace(&h266->ph_ref, unit->content_ref);
- if (err < 0)
- return err;
+ ff_refstruct_replace(&h266->ph_ref, unit->content_ref);
h266->ph = ph;
return 0;
}
@@ -1874,14 +1865,10 @@ static void cbs_h264_flush(CodedBitstreamContext *ctx)
{
CodedBitstreamH264Context *h264 = ctx->priv_data;
- for (int i = 0; i < FF_ARRAY_ELEMS(h264->sps); i++) {
- av_buffer_unref(&h264->sps_ref[i]);
- h264->sps[i] = NULL;
- }
- for (int i = 0; i < FF_ARRAY_ELEMS(h264->pps); i++) {
- av_buffer_unref(&h264->pps_ref[i]);
- h264->pps[i] = NULL;
- }
+ for (int i = 0; i < FF_ARRAY_ELEMS(h264->sps); i++)
+ ff_refstruct_unref(&h264->sps[i]);
+ for (int i = 0; i < FF_ARRAY_ELEMS(h264->pps); i++)
+ ff_refstruct_unref(&h264->pps[i]);
h264->active_sps = NULL;
h264->active_pps = NULL;
@@ -1896,27 +1883,21 @@ static void cbs_h264_close(CodedBitstreamContext *ctx)
ff_h2645_packet_uninit(&h264->common.read_packet);
for (i = 0; i < FF_ARRAY_ELEMS(h264->sps); i++)
- av_buffer_unref(&h264->sps_ref[i]);
+ ff_refstruct_unref(&h264->sps[i]);
for (i = 0; i < FF_ARRAY_ELEMS(h264->pps); i++)
- av_buffer_unref(&h264->pps_ref[i]);
+ ff_refstruct_unref(&h264->pps[i]);
}
static void cbs_h265_flush(CodedBitstreamContext *ctx)
{
CodedBitstreamH265Context *h265 = ctx->priv_data;
- for (int i = 0; i < FF_ARRAY_ELEMS(h265->vps); i++) {
- av_buffer_unref(&h265->vps_ref[i]);
- h265->vps[i] = NULL;
- }
- for (int i = 0; i < FF_ARRAY_ELEMS(h265->sps); i++) {
- av_buffer_unref(&h265->sps_ref[i]);
- h265->sps[i] = NULL;
- }
- for (int i = 0; i < FF_ARRAY_ELEMS(h265->pps); i++) {
- av_buffer_unref(&h265->pps_ref[i]);
- h265->pps[i] = NULL;
- }
+ for (int i = 0; i < FF_ARRAY_ELEMS(h265->vps); i++)
+ ff_refstruct_unref(&h265->vps[i]);
+ for (int i = 0; i < FF_ARRAY_ELEMS(h265->sps); i++)
+ ff_refstruct_unref(&h265->sps[i]);
+ for (int i = 0; i < FF_ARRAY_ELEMS(h265->pps); i++)
+ ff_refstruct_unref(&h265->pps[i]);
h265->active_vps = NULL;
h265->active_sps = NULL;
@@ -1931,32 +1912,24 @@ static void cbs_h265_close(CodedBitstreamContext *ctx)
ff_h2645_packet_uninit(&h265->common.read_packet);
for (i = 0; i < FF_ARRAY_ELEMS(h265->vps); i++)
- av_buffer_unref(&h265->vps_ref[i]);
+ ff_refstruct_unref(&h265->vps[i]);
for (i = 0; i < FF_ARRAY_ELEMS(h265->sps); i++)
- av_buffer_unref(&h265->sps_ref[i]);
+ ff_refstruct_unref(&h265->sps[i]);
for (i = 0; i < FF_ARRAY_ELEMS(h265->pps); i++)
- av_buffer_unref(&h265->pps_ref[i]);
+ ff_refstruct_unref(&h265->pps[i]);
}
static void cbs_h266_flush(CodedBitstreamContext *ctx)
{
CodedBitstreamH266Context *h266 = ctx->priv_data;
- for (int i = 0; i < FF_ARRAY_ELEMS(h266->vps); i++) {
- av_buffer_unref(&h266->vps_ref[i]);
- h266->vps[i] = NULL;
- }
-
- for (int i = 0; i < FF_ARRAY_ELEMS(h266->sps); i++) {
- av_buffer_unref(&h266->sps_ref[i]);
- h266->sps[i] = NULL;
- }
- for (int i = 0; i < FF_ARRAY_ELEMS(h266->pps); i++) {
- av_buffer_unref(&h266->pps_ref[i]);
- h266->pps[i] = NULL;
- }
- av_buffer_unref(&h266->ph_ref);
- h266->ph = NULL;
+ for (int i = 0; i < FF_ARRAY_ELEMS(h266->vps); i++)
+ ff_refstruct_unref(&h266->vps[i]);
+ for (int i = 0; i < FF_ARRAY_ELEMS(h266->sps); i++)
+ ff_refstruct_unref(&h266->sps[i]);
+ for (int i = 0; i < FF_ARRAY_ELEMS(h266->pps); i++)
+ ff_refstruct_unref(&h266->pps[i]);
+ ff_refstruct_unref(&h266->ph_ref);
}
static void cbs_h266_close(CodedBitstreamContext *ctx)
@@ -1967,11 +1940,10 @@ static void cbs_h266_close(CodedBitstreamContext *ctx)
ff_h2645_packet_uninit(&h266->common.read_packet);
}
-static void cbs_h264_free_sei(void *opaque, uint8_t *content)
+static void cbs_h264_free_sei(FFRefStructOpaque unused, void *content)
{
- H264RawSEI *sei = (H264RawSEI*)content;
+ H264RawSEI *sei = content;
ff_cbs_sei_free_message_list(&sei->message_list);
- av_free(content);
}
static const CodedBitstreamUnitTypeDescriptor cbs_h264_unit_types[] = {
@@ -1994,11 +1966,10 @@ static const CodedBitstreamUnitTypeDescriptor cbs_h264_unit_types[] = {
CBS_UNIT_TYPE_END_OF_LIST
};
-static void cbs_h265_free_sei(void *opaque, uint8_t *content)
+static void cbs_h265_free_sei(FFRefStructOpaque unused, void *content)
{
- H265RawSEI *sei = (H265RawSEI*)content;
+ H265RawSEI *sei = content;
ff_cbs_sei_free_message_list(&sei->message_list);
- av_free(content);
}
static const CodedBitstreamUnitTypeDescriptor cbs_h265_unit_types[] = {
@@ -2021,11 +1992,10 @@ static const CodedBitstreamUnitTypeDescriptor cbs_h265_unit_types[] = {
CBS_UNIT_TYPE_END_OF_LIST
};
-static void cbs_h266_free_sei(void *opaque, uint8_t *content)
+static void cbs_h266_free_sei(FFRefStructOpaque unused, void *content)
{
- H266RawSEI *sei = (H266RawSEI*)content;
+ H266RawSEI *sei = content;
ff_cbs_sei_free_message_list(&sei->message_list);
- av_free(content);
}
static const CodedBitstreamUnitTypeDescriptor cbs_h266_unit_types[] = {
diff --git a/libavcodec/cbs_h265.h b/libavcodec/cbs_h265.h
index f7cbd4970d..1b1195f198 100644
--- a/libavcodec/cbs_h265.h
+++ b/libavcodec/cbs_h265.h
@@ -681,12 +681,9 @@ typedef struct CodedBitstreamH265Context {
// All currently available parameter sets. These are updated when
// any parameter set NAL unit is read/written with this context.
- AVBufferRef *vps_ref[HEVC_MAX_VPS_COUNT];
- AVBufferRef *sps_ref[HEVC_MAX_SPS_COUNT];
- AVBufferRef *pps_ref[HEVC_MAX_PPS_COUNT];
- H265RawVPS *vps[HEVC_MAX_VPS_COUNT];
- H265RawSPS *sps[HEVC_MAX_SPS_COUNT];
- H265RawPPS *pps[HEVC_MAX_PPS_COUNT];
+ H265RawVPS *vps[HEVC_MAX_VPS_COUNT]; ///< RefStruct references
+ H265RawSPS *sps[HEVC_MAX_SPS_COUNT]; ///< RefStruct references
+ H265RawPPS *pps[HEVC_MAX_PPS_COUNT]; ///< RefStruct references
// The currently active parameter sets. These are updated when any
// NAL unit refers to the relevant parameter set. These pointers
diff --git a/libavcodec/cbs_h266.h b/libavcodec/cbs_h266.h
index 3a6f6d96b5..d2ba99f522 100644
--- a/libavcodec/cbs_h266.h
+++ b/libavcodec/cbs_h266.h
@@ -867,14 +867,11 @@ typedef struct CodedBitstreamH266Context {
// All currently available parameter sets. These are updated when
// any parameter set NAL unit is read/written with this context.
- AVBufferRef *vps_ref[VVC_MAX_VPS_COUNT];
- AVBufferRef *sps_ref[VVC_MAX_SPS_COUNT];
- AVBufferRef *pps_ref[VVC_MAX_PPS_COUNT];
- AVBufferRef *ph_ref;
- H266RawVPS *vps[VVC_MAX_VPS_COUNT];
- H266RawSPS *sps[VVC_MAX_SPS_COUNT];
- H266RawPPS *pps[VVC_MAX_PPS_COUNT];
+ H266RawVPS *vps[VVC_MAX_VPS_COUNT]; ///< RefStruct references
+ H266RawSPS *sps[VVC_MAX_SPS_COUNT]; ///< RefStruct references
+ H266RawPPS *pps[VVC_MAX_PPS_COUNT]; ///< RefStruct references
H266RawPictureHeader *ph;
+ void *ph_ref; ///< RefStruct reference backing ph above
} CodedBitstreamH266Context;
#endif /* AVCODEC_CBS_H266_H */
diff --git a/libavcodec/cbs_h266_syntax_template.c b/libavcodec/cbs_h266_syntax_template.c
index 4075897b9a..a0f48a86c3 100644
--- a/libavcodec/cbs_h266_syntax_template.c
+++ b/libavcodec/cbs_h266_syntax_template.c
@@ -1072,17 +1072,13 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw,
ub(4, sps_seq_parameter_set_id);
ub(4, sps_video_parameter_set_id);
- if (current->sps_video_parameter_set_id == 0 && !h266->vps_ref[0]) {
- H266RawVPS *vps;
- AVBufferRef *ref = av_buffer_allocz(sizeof(H266RawVPS));
- if (!ref) {
+ if (current->sps_video_parameter_set_id == 0 && !h266->vps[0]) {
+ H266RawVPS *vps = ff_refstruct_allocz(sizeof(*vps));
+ if (!vps)
return AVERROR(ENOMEM);
- }
- vps = (H266RawVPS *) ref->data;
vps->vps_max_layers_minus1 = 0;
vps->vps_independent_layer_flag[0] = 1;
vps->vps_layer_id[0] = current->nal_unit_header.nuh_layer_id;
- h266->vps_ref[0] = ref;
h266->vps[0] = vps;
}
diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h
index da84697a29..10a95d7d6e 100644
--- a/libavcodec/cbs_internal.h
+++ b/libavcodec/cbs_internal.h
@@ -19,15 +19,16 @@
#ifndef AVCODEC_CBS_INTERNAL_H
#define AVCODEC_CBS_INTERNAL_H
+#include <stddef.h>
#include <stdint.h>
-#include "libavutil/buffer.h"
#include "libavutil/log.h"
#include "cbs.h"
#include "codec_id.h"
#include "get_bits.h"
#include "put_bits.h"
+#include "refstruct.h"
enum CBSContentType {
@@ -92,8 +93,8 @@ typedef const struct CodedBitstreamUnitTypeDescriptor {
} ref;
struct {
- void (*content_free)(void *opaque, uint8_t *data);
- int (*content_clone)(AVBufferRef **ref, CodedBitstreamUnit *unit);
+ void (*content_free)(FFRefStructOpaque opaque, void *content);
+ int (*content_clone)(void **new_content, CodedBitstreamUnit *unit);
} complex;
} type;
} CodedBitstreamUnitTypeDescriptor;
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 11/42] avcodec/cbs_sei: Use RefStruct API for SEI messages
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (9 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 10/42] avcodec/cbs: Use RefStruct-API for unit content Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 12/42] avcodec/decode: Use RefStruct API for hwaccel_picture_private Andreas Rheinhardt
` (37 subsequent siblings)
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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(&udr->data_ref);
- av_free(udr);
+ SEIRawUserDataRegistered *udr = obj;
+ ff_refstruct_unref(&udr->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(&udu->data_ref);
- av_free(udu);
+ SEIRawUserDataUnregistered *udu = obj;
+ ff_refstruct_unref(&udu->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 = &cbs_free_user_data_registered;
else if (desc->type == SEI_TYPE_USER_DATA_UNREGISTERED)
free_func = &cbs_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(&message->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; i < list->nb_messages; i++) {
SEIRawMessage *message = &list->messages[i];
- av_buffer_unref(&message->payload_ref);
- av_buffer_unref(&message->extension_data_ref);
+ ff_refstruct_unref(&message->payload_ref);
+ ff_refstruct_unref(&message->extension_data);
}
av_free(list->messages);
}
@@ -278,13 +270,12 @@ int ff_cbs_sei_add_message(CodedBitstreamContext *ctx,
int prefix,
uint32_t payload_type,
void *payload_data,
- AVBufferRef *payload_buf)
+ void *payload_ref)
{
const SEIMessageTypeDescriptor *desc;
CodedBitstreamUnit *unit;
SEIRawMessageList *list;
SEIRawMessage *message;
- AVBufferRef *payload_ref;
int err;
desc = ff_cbs_sei_find_type(ctx, payload_type);
@@ -306,12 +297,10 @@ int ff_cbs_sei_add_message(CodedBitstreamContext *ctx,
if (err < 0)
return err;
- if (payload_buf) {
- payload_ref = av_buffer_ref(payload_buf);
- if (!payload_ref)
- return AVERROR(ENOMEM);
- } else {
- payload_ref = NULL;
+ if (payload_ref) {
+ /* The following just increments payload_ref's refcount,
+ * so that payload_ref is now owned by us. */
+ payload_ref = ff_refstruct_ref(payload_ref);
}
message = &list->messages[list->nb_messages - 1];
@@ -364,8 +353,8 @@ static void cbs_sei_delete_message(SEIRawMessageList *list,
av_assert0(0 <= position && position < list->nb_messages);
message = &list->messages[position];
- av_buffer_unref(&message->payload_ref);
- av_buffer_unref(&message->extension_data_ref);
+ ff_refstruct_unref(&message->payload_ref);
+ ff_refstruct_unref(&message->extension_data);
--list->nb_messages;
diff --git a/libavcodec/cbs_sei.h b/libavcodec/cbs_sei.h
index 1c327a4689..4511c506cc 100644
--- a/libavcodec/cbs_sei.h
+++ b/libavcodec/cbs_sei.h
@@ -22,8 +22,6 @@
#include <stddef.h>
#include <stdint.h>
-#include "libavutil/buffer.h"
-
#include "cbs.h"
#include "sei.h"
@@ -35,15 +33,13 @@ typedef struct SEIRawFillerPayload {
typedef struct SEIRawUserDataRegistered {
uint8_t itu_t_t35_country_code;
uint8_t itu_t_t35_country_code_extension_byte;
- uint8_t *data;
- AVBufferRef *data_ref;
+ uint8_t *data; ///< RefStruct reference
size_t data_length;
} SEIRawUserDataRegistered;
typedef struct SEIRawUserDataUnregistered {
uint8_t uuid_iso_iec_11578[16];
- uint8_t *data;
- AVBufferRef *data_ref;
+ uint8_t *data; ///< RefStruct reference
size_t data_length;
} SEIRawUserDataUnregistered;
@@ -75,9 +71,8 @@ typedef struct SEIRawMessage {
uint32_t payload_type;
uint32_t payload_size;
void *payload;
- AVBufferRef *payload_ref;
- uint8_t *extension_data;
- AVBufferRef *extension_data_ref;
+ void *payload_ref; ///< RefStruct reference
+ uint8_t *extension_data; ///< RefStruct reference
size_t extension_bit_length;
} SEIRawMessage;
@@ -174,15 +169,16 @@ void ff_cbs_sei_free_message_list(SEIRawMessageList *list);
* Will add to an existing SEI NAL unit, or create a new one for the
* message if there is no suitable existing one.
*
- * Takes a new reference to payload_buf, if set. If payload_buf is
- * NULL then the new message will not be reference counted.
+ * If set, payload_ref must be a RefStruct reference backing payload_data.
+ * This function creates a new reference to payload_ref in this case.
+ * If payload_ref is NULL, the new message will not be reference counted.
*/
int ff_cbs_sei_add_message(CodedBitstreamContext *ctx,
CodedBitstreamFragment *au,
int prefix,
uint32_t payload_type,
void *payload_data,
- AVBufferRef *payload_buf);
+ void *payload_ref);
/**
* Iterate over messages with the given payload type in an access unit.
diff --git a/libavcodec/cbs_sei_syntax_template.c b/libavcodec/cbs_sei_syntax_template.c
index 6a7cc36dda..62dd1dabaa 100644
--- a/libavcodec/cbs_sei_syntax_template.c
+++ b/libavcodec/cbs_sei_syntax_template.c
@@ -234,7 +234,12 @@ static int FUNC(message)(CodedBitstreamContext *ctx, RWContext *rw,
} else {
uint8_t *data;
+#ifdef READ
+ allocate(current->payload_ref, current->payload_size);
+ current->payload = current->payload_ref;
+#else
allocate(current->payload, current->payload_size);
+#endif
data = current->payload;
for (i = 0; i < current->payload_size; i++)
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 12/42] avcodec/decode: Use RefStruct API for hwaccel_picture_private
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (10 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 11/42] avcodec/cbs_sei: Use RefStruct API for SEI messages Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-10-02 10:39 ` Anton Khirnov
2023-10-02 12:30 ` Lynne
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 13/42] avcodec/vulkan_decode: Use RefStruct API for shared_ref Andreas Rheinhardt
` (36 subsequent siblings)
48 siblings, 2 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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(&f->hwaccel_priv_buf);
- f->hwaccel_picture_private = NULL;
+ ff_refstruct_unref(&f->hwaccel_picture_private);
ff_refstruct_unref(&f->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(&dst->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, &f->hwaccel_picture_private,
- &f->hwaccel_priv_buf);
+ ret = ff_hwaccel_frame_priv_alloc(avctx, &f->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 <stdint.h>
#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;
av_assert0(!*hwaccel_picture_private);
- data = av_mallocz(hwaccel->frame_priv_data_size);
- if (!data)
- return AVERROR(ENOMEM);
frames_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data;
-
- ref = av_buffer_create(data, hwaccel->frame_priv_data_size,
- hwaccel->free_frame_priv,
- frames_ctx->device_ctx, 0);
- if (!ref) {
- av_free(data);
+ *hwaccel_picture_private = ff_refstruct_alloc_ext(hwaccel->frame_priv_data_size, 0,
+ frames_ctx->device_ctx,
+ hwaccel->free_frame_priv);
+ if (!*hwaccel_picture_private)
return AVERROR(ENOMEM);
- }
-
- *hwaccel_priv_buf = ref;
- *hwaccel_picture_private = ref->data;
return 0;
}
diff --git a/libavcodec/decode.h b/libavcodec/decode.h
index a52152e4a7..ce97c53933 100644
--- a/libavcodec/decode.h
+++ b/libavcodec/decode.h
@@ -21,7 +21,6 @@
#ifndef AVCODEC_DECODE_H
#define AVCODEC_DECODE_H
-#include "libavutil/buffer.h"
#include "libavutil/frame.h"
#include "libavutil/hwcontext.h"
@@ -141,16 +140,13 @@ int ff_side_data_update_matrix_encoding(AVFrame *frame,
/**
* Allocate a hwaccel frame private data if the provided avctx
- * uses a hwaccel method that needs it. The private data will
- * be refcounted via the AVBuffer API (if allocated).
+ * uses a hwaccel method that needs it. The returned data is
+ * a RefStruct reference (if allocated).
*
* @param avctx The codec context
* @param hwaccel_picture_private Pointer to return hwaccel_picture_private
- * @param hwaccel_priv_buf Pointer to return the AVBufferRef owning
- * hwaccel_picture_private
* @return 0 on success, < 0 on error
*/
-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);
#endif /* AVCODEC_DECODE_H */
diff --git a/libavcodec/h264_picture.c b/libavcodec/h264_picture.c
index 25d0d96ddb..9353e4b445 100644
--- a/libavcodec/h264_picture.c
+++ b/libavcodec/h264_picture.c
@@ -46,7 +46,7 @@ void ff_h264_unref_picture(H264Context *h, H264Picture *pic)
ff_thread_release_ext_buffer(h->avctx, &pic->tf);
ff_thread_release_buffer(h->avctx, pic->f_grain);
- av_buffer_unref(&pic->hwaccel_priv_buf);
+ ff_refstruct_unref(&pic->hwaccel_picture_private);
av_buffer_unref(&pic->qscale_table_buf);
av_buffer_unref(&pic->mb_type_buf);
@@ -129,14 +129,8 @@ int ff_h264_ref_picture(H264Context *h, H264Picture *dst, H264Picture *src)
}
}
- if (src->hwaccel_picture_private) {
- dst->hwaccel_priv_buf = av_buffer_ref(src->hwaccel_priv_buf);
- if (!dst->hwaccel_priv_buf) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
- dst->hwaccel_picture_private = dst->hwaccel_priv_buf->data;
- }
+ ff_refstruct_replace(&dst->hwaccel_picture_private,
+ src->hwaccel_picture_private);
ret = av_buffer_replace(&dst->decode_error_flags, src->decode_error_flags);
if (ret < 0)
@@ -185,11 +179,8 @@ int ff_h264_replace_picture(H264Context *h, H264Picture *dst, const H264Picture
goto fail;
}
- ret = av_buffer_replace(&dst->hwaccel_priv_buf, src->hwaccel_priv_buf);
- if (ret < 0)
- goto fail;
-
- dst->hwaccel_picture_private = src->hwaccel_picture_private;
+ ff_refstruct_replace(&dst->hwaccel_picture_private,
+ src->hwaccel_picture_private);
ret = av_buffer_replace(&dst->decode_error_flags, src->decode_error_flags);
if (ret < 0)
diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index 632f5b23b2..6df80c9522 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -206,8 +206,7 @@ static int alloc_picture(H264Context *h, H264Picture *pic)
goto fail;
}
- ret = ff_hwaccel_frame_priv_alloc(h->avctx, &pic->hwaccel_picture_private,
- &pic->hwaccel_priv_buf);
+ ret = ff_hwaccel_frame_priv_alloc(h->avctx, &pic->hwaccel_picture_private);
if (ret < 0)
goto fail;
diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h
index 513856749a..7436e0a54f 100644
--- a/libavcodec/h264dec.h
+++ b/libavcodec/h264dec.h
@@ -117,7 +117,6 @@ typedef struct H264Picture {
AVBufferRef *mb_type_buf;
uint32_t *mb_type;
- AVBufferRef *hwaccel_priv_buf;
void *hwaccel_picture_private; ///< hardware accelerator private data
AVBufferRef *ref_index_buf[2];
diff --git a/libavcodec/hevc_refs.c b/libavcodec/hevc_refs.c
index c5c1203ef8..8f49704b54 100644
--- a/libavcodec/hevc_refs.c
+++ b/libavcodec/hevc_refs.c
@@ -27,6 +27,7 @@
#include "thread.h"
#include "hevc.h"
#include "hevcdec.h"
+#include "refstruct.h"
#include "threadframe.h"
void ff_hevc_unref_frame(HEVCContext *s, HEVCFrame *frame, int flags)
@@ -51,8 +52,7 @@ void ff_hevc_unref_frame(HEVCContext *s, HEVCFrame *frame, int flags)
frame->collocated_ref = NULL;
- av_buffer_unref(&frame->hwaccel_priv_buf);
- frame->hwaccel_picture_private = NULL;
+ ff_refstruct_unref(&frame->hwaccel_picture_private);
}
}
@@ -118,8 +118,7 @@ static HEVCFrame *alloc_frame(HEVCContext *s)
(s->sei.picture_timing.picture_struct == AV_PICTURE_STRUCTURE_BOTTOM_FIELD))
frame->frame->flags |= AV_FRAME_FLAG_INTERLACED;
- ret = ff_hwaccel_frame_priv_alloc(s->avctx, &frame->hwaccel_picture_private,
- &frame->hwaccel_priv_buf);
+ ret = ff_hwaccel_frame_priv_alloc(s->avctx, &frame->hwaccel_picture_private);
if (ret < 0)
goto fail;
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index 44a9680415..8316a815e7 100644
--- a/libavcodec/hevcdec.c
+++ b/libavcodec/hevcdec.c
@@ -28,7 +28,6 @@
#include "libavutil/attributes.h"
#include "libavutil/avstring.h"
#include "libavutil/common.h"
-#include "libavutil/display.h"
#include "libavutil/film_grain_params.h"
#include "libavutil/internal.h"
#include "libavutil/md5.h"
@@ -37,13 +36,11 @@
#include "libavutil/timecode.h"
#include "bswapdsp.h"
-#include "bytestream.h"
#include "cabac_functions.h"
#include "codec_internal.h"
#include "decode.h"
#include "golomb.h"
#include "hevc.h"
-#include "hevc_data.h"
#include "hevc_parse.h"
#include "hevcdec.h"
#include "hwaccel_internal.h"
@@ -3416,12 +3413,8 @@ static int hevc_ref_frame(HEVCContext *s, HEVCFrame *dst, HEVCFrame *src)
dst->flags = src->flags;
dst->sequence = src->sequence;
- 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(&dst->hwaccel_picture_private,
+ src->hwaccel_picture_private);
return 0;
fail:
diff --git a/libavcodec/hevcdec.h b/libavcodec/hevcdec.h
index 94609e4699..1d29fc24d7 100644
--- a/libavcodec/hevcdec.h
+++ b/libavcodec/hevcdec.h
@@ -419,8 +419,7 @@ typedef struct HEVCFrame {
AVBufferRef *rpl_tab_buf;
AVBufferRef *rpl_buf;
- AVBufferRef *hwaccel_priv_buf;
- void *hwaccel_picture_private;
+ void *hwaccel_picture_private; ///< RefStruct reference
/**
* A sequence counter, so that old frames are output first
diff --git a/libavcodec/hwaccel_internal.h b/libavcodec/hwaccel_internal.h
index edfe283150..057b07323d 100644
--- a/libavcodec/hwaccel_internal.h
+++ b/libavcodec/hwaccel_internal.h
@@ -26,6 +26,7 @@
#include <stdint.h>
#include "avcodec.h"
+#include "refstruct.h"
#define HWACCEL_CAP_ASYNC_SAFE (1 << 0)
#define HWACCEL_CAP_THREAD_SAFE (1 << 1)
@@ -154,7 +155,7 @@ typedef struct FFHWAccel {
* @param hwctx a pointer to an AVHWDeviceContext.
* @param data the per-frame hardware accelerator private data to be freed.
*/
- void (*free_frame_priv)(void *hwctx, uint8_t *data);
+ void (*free_frame_priv)(FFRefStructOpaque hwctx, void *data);
/**
* Callback to flush the hwaccel state.
diff --git a/libavcodec/mpegpicture.c b/libavcodec/mpegpicture.c
index b7c804c8ec..4126756e9b 100644
--- a/libavcodec/mpegpicture.c
+++ b/libavcodec/mpegpicture.c
@@ -27,11 +27,11 @@
#include "avcodec.h"
#include "encode.h"
-#include "internal.h"
#include "decode.h"
#include "motion_est.h"
#include "mpegpicture.h"
#include "mpegutils.h"
+#include "refstruct.h"
#include "threadframe.h"
static void av_noinline free_picture_tables(Picture *pic)
@@ -171,8 +171,7 @@ static int alloc_frame_buffer(AVCodecContext *avctx, Picture *pic,
pic->f->height = avctx->height;
}
- ret = ff_hwaccel_frame_priv_alloc(avctx, &pic->hwaccel_picture_private,
- &pic->hwaccel_priv_buf);
+ ret = ff_hwaccel_frame_priv_alloc(avctx, &pic->hwaccel_picture_private);
if (ret < 0)
return ret;
@@ -316,12 +315,11 @@ void ff_mpeg_unref_picture(AVCodecContext *avctx, Picture *pic)
else if (pic->f)
av_frame_unref(pic->f);
- av_buffer_unref(&pic->hwaccel_priv_buf);
+ ff_refstruct_unref(&pic->hwaccel_picture_private);
if (pic->needs_realloc)
free_picture_tables(pic);
- pic->hwaccel_picture_private = NULL;
pic->field_picture = 0;
pic->b_frame_score = 0;
pic->needs_realloc = 0;
@@ -380,14 +378,8 @@ int ff_mpeg_ref_picture(AVCodecContext *avctx, Picture *dst, Picture *src)
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) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
- dst->hwaccel_picture_private = dst->hwaccel_priv_buf->data;
- }
+ ff_refstruct_replace(&dst->hwaccel_picture_private,
+ src->hwaccel_picture_private);
dst->field_picture = src->field_picture;
dst->b_frame_score = src->b_frame_score;
diff --git a/libavcodec/mpegpicture.h b/libavcodec/mpegpicture.h
index 7919aa402c..477b3ac535 100644
--- a/libavcodec/mpegpicture.h
+++ b/libavcodec/mpegpicture.h
@@ -66,7 +66,6 @@ typedef struct Picture {
int alloc_mb_height; ///< mb_height used to allocate tables
int alloc_mb_stride; ///< mb_stride used to allocate tables
- AVBufferRef *hwaccel_priv_buf;
void *hwaccel_picture_private; ///< Hardware accelerator private data
int field_picture; ///< whether or not the picture was encoded in separate fields
diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c
index db325dc90b..4a51c551b8 100644
--- a/libavcodec/vp8.c
+++ b/libavcodec/vp8.c
@@ -108,8 +108,7 @@ static int vp8_alloc_frame(VP8Context *s, VP8Frame *f, int ref)
return ret;
if (!(f->seg_map = ff_refstruct_allocz(s->mb_width * s->mb_height)))
goto fail;
- ret = ff_hwaccel_frame_priv_alloc(s->avctx, &f->hwaccel_picture_private,
- &f->hwaccel_priv_buf);
+ ret = ff_hwaccel_frame_priv_alloc(s->avctx, &f->hwaccel_picture_private);
if (ret < 0)
goto fail;
@@ -124,8 +123,7 @@ fail:
static void vp8_release_frame(VP8Context *s, VP8Frame *f)
{
ff_refstruct_unref(&f->seg_map);
- av_buffer_unref(&f->hwaccel_priv_buf);
- f->hwaccel_picture_private = NULL;
+ ff_refstruct_unref(&f->hwaccel_picture_private);
ff_thread_release_ext_buffer(s->avctx, &f->tf);
}
@@ -139,12 +137,8 @@ static int vp8_ref_frame(VP8Context *s, VP8Frame *dst, const VP8Frame *src)
if ((ret = ff_thread_ref_frame(&dst->tf, &src->tf)) < 0)
return ret;
ff_refstruct_replace(&dst->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)
- return AVERROR(ENOMEM);
- dst->hwaccel_picture_private = dst->hwaccel_priv_buf->data;
- }
+ ff_refstruct_replace(&dst->hwaccel_picture_private,
+ src->hwaccel_picture_private);
return 0;
}
diff --git a/libavcodec/vp8.h b/libavcodec/vp8.h
index cb752d4498..eb9fa2f166 100644
--- a/libavcodec/vp8.h
+++ b/libavcodec/vp8.h
@@ -28,7 +28,6 @@
#include <stdatomic.h>
-#include "libavutil/buffer.h"
#include "libavutil/mem_internal.h"
#include "libavutil/thread.h"
@@ -154,8 +153,7 @@ typedef struct VP8Frame {
ThreadFrame tf;
uint8_t *seg_map; ///< RefStruct reference
- AVBufferRef *hwaccel_priv_buf;
- void *hwaccel_picture_private;
+ void *hwaccel_picture_private; ///< RefStruct reference
} VP8Frame;
#define MAX_THREADS 8
diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c
index 3cc27aa812..c9cc81ec94 100644
--- a/libavcodec/vp9.c
+++ b/libavcodec/vp9.c
@@ -30,6 +30,7 @@
#include "hwaccel_internal.h"
#include "hwconfig.h"
#include "profiles.h"
+#include "refstruct.h"
#include "thread.h"
#include "threadframe.h"
#include "pthread_internal.h"
@@ -100,9 +101,8 @@ static void vp9_frame_unref(AVCodecContext *avctx, VP9Frame *f)
{
ff_thread_release_ext_buffer(avctx, &f->tf);
av_buffer_unref(&f->extradata);
- av_buffer_unref(&f->hwaccel_priv_buf);
+ ff_refstruct_unref(&f->hwaccel_picture_private);
f->segmentation_map = NULL;
- f->hwaccel_picture_private = NULL;
}
static int vp9_frame_alloc(AVCodecContext *avctx, VP9Frame *f)
@@ -135,8 +135,7 @@ static int vp9_frame_alloc(AVCodecContext *avctx, VP9Frame *f)
f->segmentation_map = f->extradata->data;
f->mv = (VP9mvrefPair *) (f->extradata->data + sz);
- ret = ff_hwaccel_frame_priv_alloc(avctx, &f->hwaccel_picture_private,
- &f->hwaccel_priv_buf);
+ ret = ff_hwaccel_frame_priv_alloc(avctx, &f->hwaccel_picture_private);
if (ret < 0)
goto fail;
@@ -163,12 +162,8 @@ static int vp9_frame_ref(AVCodecContext *avctx, VP9Frame *dst, VP9Frame *src)
dst->mv = src->mv;
dst->uses_2pass = src->uses_2pass;
- 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(&dst->hwaccel_picture_private,
+ src->hwaccel_picture_private);
return 0;
diff --git a/libavcodec/vp9shared.h b/libavcodec/vp9shared.h
index 543a496df8..e54f23544e 100644
--- a/libavcodec/vp9shared.h
+++ b/libavcodec/vp9shared.h
@@ -69,8 +69,7 @@ typedef struct VP9Frame {
VP9mvrefPair *mv;
int uses_2pass;
- AVBufferRef *hwaccel_priv_buf;
- void *hwaccel_picture_private;
+ void *hwaccel_picture_private; ///< RefStruct reference
} VP9Frame;
enum BlockLevel {
diff --git a/libavcodec/vulkan_av1.c b/libavcodec/vulkan_av1.c
index b1373722ef..7c8dda7798 100644
--- a/libavcodec/vulkan_av1.c
+++ b/libavcodec/vulkan_av1.c
@@ -536,10 +536,10 @@ static int vk_av1_end_frame(AVCodecContext *avctx)
return ff_vk_decode_frame(avctx, pic->f, vp, rav, rvp);
}
-static void vk_av1_free_frame_priv(void *_hwctx, uint8_t *data)
+static void vk_av1_free_frame_priv(FFRefStructOpaque _hwctx, void *data)
{
- AVHWDeviceContext *hwctx = _hwctx;
- AV1VulkanDecodePicture *ap = (AV1VulkanDecodePicture *)data;
+ AVHWDeviceContext *hwctx = _hwctx.nc;
+ AV1VulkanDecodePicture *ap = data;
/* Workaround for a spec issue. */
if (ap->frame_id_set)
@@ -547,9 +547,6 @@ static void vk_av1_free_frame_priv(void *_hwctx, uint8_t *data)
/* Free frame resources, this also destroys the session parameters. */
ff_vk_decode_free_frame(hwctx, &ap->vp);
-
- /* Free frame context */
- av_free(ap);
}
const FFHWAccel ff_av1_vulkan_hwaccel = {
diff --git a/libavcodec/vulkan_h264.c b/libavcodec/vulkan_h264.c
index cdc2c7fe30..2cb54bb1ff 100644
--- a/libavcodec/vulkan_h264.c
+++ b/libavcodec/vulkan_h264.c
@@ -530,16 +530,13 @@ static int vk_h264_end_frame(AVCodecContext *avctx)
return ff_vk_decode_frame(avctx, pic->f, vp, rav, rvp);
}
-static void vk_h264_free_frame_priv(void *_hwctx, uint8_t *data)
+static void vk_h264_free_frame_priv(FFRefStructOpaque _hwctx, void *data)
{
- AVHWDeviceContext *hwctx = _hwctx;
- H264VulkanDecodePicture *hp = (H264VulkanDecodePicture *)data;
+ AVHWDeviceContext *hwctx = _hwctx.nc;
+ H264VulkanDecodePicture *hp = data;
/* Free frame resources, this also destroys the session parameters. */
ff_vk_decode_free_frame(hwctx, &hp->vp);
-
- /* Free frame context */
- av_free(hp);
}
const FFHWAccel ff_h264_vulkan_hwaccel = {
diff --git a/libavcodec/vulkan_hevc.c b/libavcodec/vulkan_hevc.c
index 395cbd3008..d5116bb48c 100644
--- a/libavcodec/vulkan_hevc.c
+++ b/libavcodec/vulkan_hevc.c
@@ -901,16 +901,13 @@ static int vk_hevc_end_frame(AVCodecContext *avctx)
return ff_vk_decode_frame(avctx, pic->frame, vp, rav, rvp);
}
-static void vk_hevc_free_frame_priv(void *_hwctx, uint8_t *data)
+static void vk_hevc_free_frame_priv(FFRefStructOpaque _hwctx, void *data)
{
- AVHWDeviceContext *hwctx = _hwctx;
- HEVCVulkanDecodePicture *hp = (HEVCVulkanDecodePicture *)data;
+ AVHWDeviceContext *hwctx = _hwctx.nc;
+ HEVCVulkanDecodePicture *hp = data;
/* Free frame resources */
ff_vk_decode_free_frame(hwctx, &hp->vp);
-
- /* Free frame context */
- av_free(hp);
}
const FFHWAccel ff_hevc_vulkan_hwaccel = {
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 12/42] avcodec/decode: Use RefStruct API for hwaccel_picture_private
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 12/42] avcodec/decode: Use RefStruct API for hwaccel_picture_private Andreas Rheinhardt
@ 2023-10-02 10:39 ` Anton Khirnov
2023-10-02 12:30 ` Lynne
1 sibling, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-10-02 10:39 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:04)
> diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h
> index 513856749a..7436e0a54f 100644
> --- a/libavcodec/h264dec.h
> +++ b/libavcodec/h264dec.h
> @@ -117,7 +117,6 @@ typedef struct H264Picture {
> AVBufferRef *mb_type_buf;
> uint32_t *mb_type;
>
> - AVBufferRef *hwaccel_priv_buf;
> void *hwaccel_picture_private; ///< hardware accelerator private data
Is there a reason you didn't add a comment that this is a refstruct?
Same for mpegvideo
Otherwise looks good.
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 12/42] avcodec/decode: Use RefStruct API for hwaccel_picture_private
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 12/42] avcodec/decode: Use RefStruct API for hwaccel_picture_private Andreas Rheinhardt
2023-10-02 10:39 ` Anton Khirnov
@ 2023-10-02 12:30 ` Lynne
1 sibling, 0 replies; 106+ messages in thread
From: Lynne @ 2023-10-02 12:30 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Sep 19, 2023, 21:58 by andreas.rheinhardt@outlook.com:
> 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 <andreas.rheinhardt@outlook.com>
> ---
> 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(-)
>
Patchhset works and tests fine.
I've reviewed the code in this patch. Looks good,
and it reduces a constant per-frame free/alloc.
Thanks
_______________________________________________
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] 106+ messages in thread
* [FFmpeg-devel] [PATCH 13/42] avcodec/vulkan_decode: Use RefStruct API for shared_ref
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (11 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 12/42] avcodec/decode: Use RefStruct API for hwaccel_picture_private Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-10-02 12:31 ` Lynne
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 14/42] avcodec/hevcdec: Use RefStruct API for RefPicListTap buffer Andreas Rheinhardt
` (35 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
Avoids allocations, error checks and indirections.
Also increases type-safety.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
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(&dst_ctx->shared_ref, src_ctx->shared_ref);
- if (err < 0)
- return err;
+ ff_refstruct_replace(&dst_ctx->shared_ctx, src_ctx->shared_ctx);
if (src_ctx->session_params) {
err = av_buffer_replace(&dst_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 = &ctx->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 = &ctx->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 = &ctx->s.vkfn;
/* Output */
@@ -586,9 +585,9 @@ void ff_vk_decode_free_frame(AVHWDeviceContext *dev_ctx, FFVulkanDecodePicture *
av_frame_free(&vp->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 = &ctx->s;
FFVulkanFunctions *vk = &ctx->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,
+ free_common);
+ if (!dec->shared_ctx)
return AVERROR(ENOMEM);
- dec->shared_ref = av_buffer_create((uint8_t *)ctx, sizeof(*ctx),
- free_common, NULL, 0);
- if (!dec->shared_ref) {
- av_free(ctx);
- return AVERROR(ENOMEM);
- }
-
- ctx = (FFVulkanDecodeShared *)dec->shared_ref->data;
+ ctx = dec->shared_ctx;
ctx->s.extensions = ff_vk_extensions_to_mask(hwctx->enabled_dev_extensions,
hwctx->nb_enabled_dev_extensions);
@@ -648,13 +639,13 @@ static int vulkan_decode_bootstrap(AVCodecContext *avctx, AVBufferRef *frames_re
if (!(ctx->s.extensions & FF_VK_EXT_VIDEO_DECODE_QUEUE)) {
av_log(avctx, AV_LOG_ERROR, "Device does not support the %s extension!\n",
VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME);
- av_buffer_unref(&dec->shared_ref);
+ ff_refstruct_unref(&dec->shared_ctx);
return AVERROR(ENOSYS);
}
err = ff_vk_load_functions(device, &ctx->s.vkfn, ctx->s.extensions, 1, 1);
if (err < 0) {
- av_buffer_unref(&dec->shared_ref);
+ ff_refstruct_unref(&dec->shared_ctx);
return err;
}
@@ -751,7 +742,7 @@ static int vulkan_decode_get_profile(AVCodecContext *avctx, AVBufferRef *frames_
VkFormat best_vkfmt;
FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
- FFVulkanDecodeShared *ctx = (FFVulkanDecodeShared *)dec->shared_ref->data;
+ FFVulkanDecodeShared *ctx = dec->shared_ctx;
FFVulkanFunctions *vk = &ctx->s.vkfn;
VkVideoCapabilitiesKHR *caps = &ctx->caps;
@@ -1095,14 +1086,14 @@ int ff_vk_decode_create_params(AVBufferRef **par_ref, void *logctx, FFVulkanDeco
int ff_vk_decode_uninit(AVCodecContext *avctx)
{
FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
- FFVulkanDecodeShared *ctx = (FFVulkanDecodeShared *)dec->shared_ref->data;
+ FFVulkanDecodeShared *ctx = dec->shared_ctx;
/* Wait on and free execution pool */
ff_vk_exec_pool_free(&ctx->s, &dec->exec_pool);
av_freep(&dec->hevc_headers);
av_buffer_unref(&dec->session_params);
- av_buffer_unref(&dec->shared_ref);
+ ff_refstruct_unref(&dec->shared_ctx);
av_freep(&dec->slice_off);
return 0;
}
@@ -1148,7 +1139,7 @@ int ff_vk_decode_init(AVCodecContext *avctx)
return err;
/* Initialize contexts */
- ctx = (FFVulkanDecodeShared *)dec->shared_ref->data;
+ ctx = dec->shared_ctx;
s = &ctx->s;
vk = &ctx->s.vkfn;
diff --git a/libavcodec/vulkan_decode.h b/libavcodec/vulkan_decode.h
index c983b44029..b0b1ff5614 100644
--- a/libavcodec/vulkan_decode.h
+++ b/libavcodec/vulkan_decode.h
@@ -54,7 +54,7 @@ typedef struct FFVulkanDecodeShared {
} FFVulkanDecodeShared;
typedef struct FFVulkanDecodeContext {
- AVBufferRef *shared_ref;
+ FFVulkanDecodeShared *shared_ctx;
AVBufferRef *session_params;
FFVkExecPool exec_pool;
diff --git a/libavcodec/vulkan_h264.c b/libavcodec/vulkan_h264.c
index 2cb54bb1ff..172c6c4e8e 100644
--- a/libavcodec/vulkan_h264.c
+++ b/libavcodec/vulkan_h264.c
@@ -287,7 +287,7 @@ static int vk_h264_create_params(AVCodecContext *avctx, AVBufferRef **buf)
{
int err;
FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
- FFVulkanDecodeShared *ctx = (FFVulkanDecodeShared *)dec->shared_ref->data;
+ FFVulkanDecodeShared *ctx = dec->shared_ctx;
const H264Context *h = avctx->priv_data;
/* SPS */
diff --git a/libavcodec/vulkan_hevc.c b/libavcodec/vulkan_hevc.c
index d5116bb48c..0f301b42fe 100644
--- a/libavcodec/vulkan_hevc.c
+++ b/libavcodec/vulkan_hevc.c
@@ -636,7 +636,7 @@ static int vk_hevc_create_params(AVCodecContext *avctx, AVBufferRef **buf)
int err;
const HEVCContext *h = avctx->priv_data;
FFVulkanDecodeContext *dec = avctx->internal->hwaccel_priv_data;
- FFVulkanDecodeShared *ctx = (FFVulkanDecodeShared *)dec->shared_ref->data;
+ FFVulkanDecodeShared *ctx = dec->shared_ctx;
VkVideoDecodeH265SessionParametersAddInfoKHR h265_params_info = {
.sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR,
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 14/42] avcodec/hevcdec: Use RefStruct API for RefPicListTap buffer
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (12 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 13/42] avcodec/vulkan_decode: Use RefStruct API for shared_ref Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-10-02 10:47 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 15/42] avcodec/pthread_frame: Use RefStruct API for ThreadFrame.progress Andreas Rheinhardt
` (34 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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(&frame->tab_mvf_buf);
frame->tab_mvf = NULL;
- av_buffer_unref(&frame->rpl_buf);
+ ff_refstruct_unref(&frame->rpl);
+ frame->nb_rpl_elems = 0;
av_buffer_unref(&frame->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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 14/42] avcodec/hevcdec: Use RefStruct API for RefPicListTap buffer
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 14/42] avcodec/hevcdec: Use RefStruct API for RefPicListTap buffer Andreas Rheinhardt
@ 2023-10-02 10:47 ` Anton Khirnov
2023-10-02 11:07 ` Andreas Rheinhardt
0 siblings, 1 reply; 106+ messages in thread
From: Anton Khirnov @ 2023-10-02 10:47 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:06)
>avcodec/hevcdec: Use RefStruct API for RefPicListTap buffer
^
b
> 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,
Is there a reason you decided not to provide it, or there just wasn't
any code that would be improved by 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 <andreas.rheinhardt@outlook.com>
> ---
> libavcodec/hevc_refs.c | 14 ++++++++------
> libavcodec/hevcdec.c | 5 ++---
> libavcodec/hevcdec.h | 3 ++-
> 3 files changed, 12 insertions(+), 10 deletions(-)
The actual code looks good.
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 14/42] avcodec/hevcdec: Use RefStruct API for RefPicListTap buffer
2023-10-02 10:47 ` Anton Khirnov
@ 2023-10-02 11:07 ` Andreas Rheinhardt
2023-10-04 8:10 ` Anton Khirnov
0 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-10-02 11:07 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Anton Khirnov:
> Quoting Andreas Rheinhardt (2023-09-19 21:57:06)
>> avcodec/hevcdec: Use RefStruct API for RefPicListTap buffer
> ^
> b
>
>> 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,
>
> Is there a reason you decided not to provide it, or there just wasn't
> any code that would be improved by it?
>
In this example, there would be no improvement if RefStruct recorded the
size (in bytes) and provided a getter for it.
In general, the philosophy of the RefStruct API is that the user and not
the API knows what is in the user data. So the user has to keep track of
stuff like this in cases where the user doesn't know it.
The only scenario where keeping track of the size would be advantageous
would be for using arrays-of-whatever if the callbacks provided the size
as a parameter (to be ignored by most users), because one could then
derive the number of elements from it. I pondered this, but given that
the AVBuffer API doesn't do so either, I didn't do it. Shall I change this?
>> 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 <andreas.rheinhardt@outlook.com>
>> ---
>> libavcodec/hevc_refs.c | 14 ++++++++------
>> libavcodec/hevcdec.c | 5 ++---
>> libavcodec/hevcdec.h | 3 ++-
>> 3 files changed, 12 insertions(+), 10 deletions(-)
>
> The actual code looks good.
>
_______________________________________________
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] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 14/42] avcodec/hevcdec: Use RefStruct API for RefPicListTap buffer
2023-10-02 11:07 ` Andreas Rheinhardt
@ 2023-10-04 8:10 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-10-04 8:10 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Quoting Andreas Rheinhardt (2023-10-02 13:07:14)
> Anton Khirnov:
> > Quoting Andreas Rheinhardt (2023-09-19 21:57:06)
> >> avcodec/hevcdec: Use RefStruct API for RefPicListTap buffer
> > ^
> > b
> >
> >> 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,
> >
> > Is there a reason you decided not to provide it, or there just wasn't
> > any code that would be improved by it?
> >
>
> In this example, there would be no improvement if RefStruct recorded the
> size (in bytes) and provided a getter for it.
>
> In general, the philosophy of the RefStruct API is that the user and not
> the API knows what is in the user data. So the user has to keep track of
> stuff like this in cases where the user doesn't know it.
>
> The only scenario where keeping track of the size would be advantageous
> would be for using arrays-of-whatever if the callbacks provided the size
> as a parameter (to be ignored by most users), because one could then
> derive the number of elements from it. I pondered this, but given that
> the AVBuffer API doesn't do so either, I didn't do it. Shall I change this?
I'm leaning towards no, it's overly specific and the advantage probably
small.
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 15/42] avcodec/pthread_frame: Use RefStruct API for ThreadFrame.progress
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (13 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 14/42] avcodec/hevcdec: Use RefStruct API for RefPicListTap buffer Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-10-02 11:01 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 16/42] avcodec/nvdec: Use RefStruct API for decoder_ref Andreas Rheinhardt
` (33 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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 = &sl->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(&progress[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(&progress[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(&progress[0], -1);
- atomic_init(&progress[1], -1);
+ atomic_init(&f->progress->progress[0], -1);
+ atomic_init(&f->progress->progress[1], -1);
}
ret = ff_thread_get_buffer(avctx, f->f, flags);
if (ret)
- av_buffer_unref(&f->progress);
+ ff_refstruct_unref(&f->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(&f->progress);
+ ff_refstruct_unref(&f->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 ff_thread_ref_frame(ThreadFrame *dst, const ThreadFrame *src)
av_assert0(!dst->progress);
- if (src->progress &&
- !(dst->progress = av_buffer_ref(src->progress))) {
- ff_thread_release_ext_buffer(dst->owner[0], dst);
- return AVERROR(ENOMEM);
- }
+ if (src->progress)
+ dst->progress = ff_refstruct_ref(src->progress);
return 0;
}
@@ -899,11 +897,7 @@ int ff_thread_replace_frame(AVCodecContext *avctx, ThreadFrame *dst,
if (ret < 0)
return ret;
- ret = av_buffer_replace(&dst->progress, src->progress);
- if (ret < 0) {
- ff_thread_release_ext_buffer(dst->owner[0], dst);
- return ret;
- }
+ ff_refstruct_replace(&dst->progress, src->progress);
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 15/42] avcodec/pthread_frame: Use RefStruct API for ThreadFrame.progress
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 15/42] avcodec/pthread_frame: Use RefStruct API for ThreadFrame.progress Andreas Rheinhardt
@ 2023-10-02 11:01 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-10-02 11:01 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:07)
> Avoids allocations and error checks and allows to remove
> cleanup code for earlier allocations. Also avoids casts
> and indirections.
>
> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
> ---
> 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(-)
LGTM
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 16/42] avcodec/nvdec: Use RefStruct API for decoder_ref
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (14 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 15/42] avcodec/pthread_frame: Use RefStruct API for ThreadFrame.progress Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-10-02 10:58 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 17/42] avcodec/refstruct: Add RefStruct pool API Andreas Rheinhardt
` (32 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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(&decoder->hw_device_ref);
cuvid_free_functions(&decoder->cvdl);
-
- av_freep(&decoder);
}
-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(&decoder);
- 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(&decoder_ref);
+ ff_refstruct_unref(&decoder);
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(&ctx->decoder_ref);
+ ff_refstruct_unref(&ctx->decoder);
av_buffer_pool_uninit(&ctx->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(&ctx->decoder_ref, frames_ctx->device_ref, ¶ms, avctx);
+ ret = nvdec_decoder_create(&ctx->decoder, frames_ctx->device_ref, ¶ms, 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(&cf->idx_ref);
- av_buffer_unref(&cf->decoder_ref);
av_buffer_unref(&cf->ref_idx_ref);
+ ff_refstruct_unref(&cf->decoder);
av_freep(&priv);
}
@@ -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(&unmap_data->idx_ref);
- av_buffer_unref(&unmap_data->decoder_ref);
av_buffer_unref(&unmap_data->ref_idx_ref);
+ ff_refstruct_unref(&unmap_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 = (NVDECDecoder*)cf->decoder_ref->data;
+ NVDECDecoder *decoder = cf->decoder;
AVHWFramesContext *hwctx = (AVHWFramesContext *)frame->hw_frames_ctx->data;
@@ -534,11 +526,11 @@ 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)) ||
- !(unmap_data->decoder_ref = av_buffer_ref(cf->decoder_ref))) {
+ if (!(unmap_data->idx_ref = av_buffer_ref(cf->idx_ref))) {
ret = AVERROR(ENOMEM);
goto copy_fail;
}
+ unmap_data->decoder = ff_refstruct_ref(cf->decoder);
av_pix_fmt_get_chroma_sub_sample(hwctx->sw_format, &shift_h, &shift_v);
for (i = 0; frame->linesize[i]; i++) {
@@ -583,11 +575,7 @@ int ff_nvdec_start_frame(AVCodecContext *avctx, AVFrame *frame)
if (!cf)
return AVERROR(ENOMEM);
- cf->decoder_ref = av_buffer_ref(ctx->decoder_ref);
- if (!cf->decoder_ref) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
+ cf->decoder = ff_refstruct_ref(ctx->decoder);
cf->idx_ref = av_buffer_pool_get(ctx->decoder_pool);
if (!cf->idx_ref) {
@@ -645,7 +633,7 @@ fail:
int ff_nvdec_end_frame(AVCodecContext *avctx)
{
NVDECContext *ctx = avctx->internal->hwaccel_priv_data;
- NVDECDecoder *decoder = (NVDECDecoder*)ctx->decoder_ref->data;
+ NVDECDecoder *decoder = ctx->decoder;
void *logctx = avctx;
CUVIDPICPARAMS *pp = &ctx->pic_params;
diff --git a/libavcodec/nvdec.h b/libavcodec/nvdec.h
index 66f3ca59e7..efacb5b691 100644
--- a/libavcodec/nvdec.h
+++ b/libavcodec/nvdec.h
@@ -46,7 +46,7 @@ typedef struct NVDECFrame {
unsigned int ref_idx;
AVBufferRef *idx_ref;
AVBufferRef *ref_idx_ref;
- AVBufferRef *decoder_ref;
+ struct NVDECDecoder *decoder; ///< RefStruct reference
} NVDECFrame;
typedef struct NVDECContext {
@@ -54,7 +54,7 @@ typedef struct NVDECContext {
AVBufferPool *decoder_pool;
- AVBufferRef *decoder_ref;
+ struct NVDECDecoder *decoder; ///< RefStruct reference
uint8_t *bitstream;
int bitstream_len;
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 16/42] avcodec/nvdec: Use RefStruct API for decoder_ref
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 16/42] avcodec/nvdec: Use RefStruct API for decoder_ref Andreas Rheinhardt
@ 2023-10-02 10:58 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-10-02 10:58 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:08)
> 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 <andreas.rheinhardt@outlook.com>
> ---
> libavcodec/nvdec.c | 50 ++++++++++++++++++----------------------------
> libavcodec/nvdec.h | 4 ++--
> 2 files changed, 21 insertions(+), 33 deletions(-)
Looks ok.
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 17/42] avcodec/refstruct: Add RefStruct pool API
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (15 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 16/42] avcodec/nvdec: Use RefStruct API for decoder_ref Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-09-20 19:58 ` Michael Niedermayer
2023-10-04 8:39 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 18/42] avcodec/h264dec: Use RefStruct-pool API instead of AVBufferPool API Andreas Rheinhardt
` (31 subsequent siblings)
48 siblings, 2 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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(&ref->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(&ref->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*)&ref->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(&pool->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(&pool->mutex);
+ if (!pool->uninited) {
+ ref->opaque.nc = pool->available_entries;
+ pool->available_entries = ref;
+ ref = NULL;
+ }
+ pthread_mutex_unlock(&pool->mutex);
+
+ if (ref)
+ pool_free_entry(pool, ref);
+
+ if (atomic_fetch_sub_explicit(&pool->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(&pool->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(&ref->refcount, 1);
+ }
+ pthread_mutex_unlock(&pool->mutex);
+
+ if (!ret) {
+ RefCount *ref;
+ ret = ff_refstruct_alloc_ext(pool->size, pool->entry_flags, pool,
+ pool->reset_cb ? pool_reset_entry : NULL);
+ if (!ret)
+ return AVERROR(ENOMEM);
+ ref = get_refcount(ret);
+ ref->free = pool_return_entry;
+ if (pool->init_cb) {
+ int err = pool->init_cb(pool->opaque, ret);
+ if (err < 0) {
+ if (pool->pool_flags & FF_REFSTRUCT_POOL_FLAG_RESET_ON_INIT_ERROR)
+ pool->reset_cb(pool->opaque, ret);
+ if (pool->pool_flags & FF_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR)
+ pool->free_entry_cb(pool->opaque, ret);
+ av_free(ref);
+ return err;
+ }
+ }
+ }
+ atomic_fetch_add_explicit(&pool->refcount, 1, memory_order_relaxed);
+ memcpy(datap, &ret, sizeof(ret));
+
+ return 0;
+}
+
+void *ff_refstruct_pool_get(FFRefStructPool *pool)
+{
+ void *ret;
+ refstruct_pool_get_ext(&ret, pool);
+ return ret;
+}
+
+void ff_refstruct_pool_uninit(FFRefStructPool **poolp)
+{
+ FFRefStructPool *pool = *poolp;
+ RefCount *entry;
+
+ if (!pool)
+ return;
+
+ pthread_mutex_lock(&pool->mutex);
+ av_assert1(!pool->uninited);
+ pool->uninited = 1;
+ entry = pool->available_entries;
+ pool->available_entries = NULL;
+ pthread_mutex_unlock(&pool->mutex);
+
+ while (entry) {
+ void *next = entry->opaque.nc;
+ pool_free_entry(pool, entry);
+ entry = next;
+ }
+
+ if (atomic_fetch_sub_explicit(&pool->refcount, 1, memory_order_acq_rel) == 1)
+ pool_free(pool);
+
+ *poolp = NULL;
+}
+
+FFRefStructPool *ff_refstruct_pool_alloc(size_t size, unsigned flags)
+{
+ return ff_refstruct_pool_alloc_ext(size, flags, NULL, NULL, NULL, NULL, NULL);
+}
+
+FFRefStructPool *ff_refstruct_pool_alloc_ext_c(size_t size, unsigned flags,
+ 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))
+{
+ FFRefStructPool *pool = av_mallocz(sizeof(*pool));
+ int err;
+
+ if (!pool)
+ return NULL;
+
+ pool->size = size;
+ pool->opaque = opaque;
+ pool->init_cb = init_cb;
+ pool->reset_cb = reset_cb;
+ pool->free_entry_cb = free_entry_cb;
+ pool->free_cb = free_cb;
+#define COMMON_FLAGS FF_REFSTRUCT_POOL_FLAG_NO_ZEROING
+ pool->entry_flags = flags & COMMON_FLAGS;
+ // Filter out nonsense combinations to avoid checks later.
+ if (!pool->reset_cb)
+ flags &= ~FF_REFSTRUCT_POOL_FLAG_RESET_ON_INIT_ERROR;
+ if (!pool->free_entry_cb)
+ flags &= ~FF_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR;
+ pool->pool_flags = flags;
+
+ atomic_init(&pool->refcount, 1);
+
+ err = pthread_mutex_init(&pool->mutex, NULL);
+ if (err) {
+ av_free(pool);
+ return NULL;
+ }
+ return pool;
+}
diff --git a/libavcodec/refstruct.h b/libavcodec/refstruct.h
index ee6936d77a..e2fe45e77d 100644
--- a/libavcodec/refstruct.h
+++ b/libavcodec/refstruct.h
@@ -151,4 +151,132 @@ void ff_refstruct_replace(void *dstp, const void *src);
*/
int ff_refstruct_exclusive(const void *obj);
+/**
+ * FFRefStructPool is an API for a thread-safe pool of objects managed
+ * via the RefStruct API.
+ *
+ * Frequently allocating and freeing large or complicated objects may be slow
+ * and wasteful. This API is meant to solve this in cases when the caller
+ * needs a set of interchangable objects.
+ *
+ * At the beginning, the user must call allocate the pool via
+ * ff_refstruct_pool_alloc() or its analogue ff_refstruct_pool_alloc_ext().
+ * Then whenever an object is needed, call ff_refstruct_pool_get() to
+ * get a new or reused object from the pool. This new object works in all
+ * aspects the same way as the ones created by ff_refstruct_alloc_ext().
+ * However, when the last reference to this object is unreferenced, it is
+ * (optionally) reset and returned to the pool instead of being freed and
+ * will be reused for subsequent ff_refstruct_pool_get() calls.
+ *
+ * When the caller is done with the pool and no longer needs to create any new
+ * objects, ff_refstruct_pool_uninit() must be called to mark the pool as
+ * freeable. Then entries returned to the pool will then be freed.
+ * Once all the entries are freed, the pool will automatically be freed.
+ *
+ * Allocating and releasing objects with this API is thread-safe as long as
+ * the user-supplied callbacks (if provided) are thread-safe.
+ */
+
+/**
+ * The buffer pool. This structure is opaque and not meant to be accessed
+ * directly. It is allocated with the allocators below and freed with
+ * ff_refstruct_pool_uninit().
+ */
+typedef struct FFRefStructPool FFRefStructPool;
+
+/**
+ * If this flag is not set, every object in the pool will be zeroed before
+ * the init callback is called or before it is turned over to the user
+ * for the first time if no init callback has been provided.
+ */
+#define FF_REFSTRUCT_POOL_FLAG_NO_ZEROING FF_REFSTRUCT_FLAG_NO_ZEROING
+/**
+ * If this flag is set and both init_cb and reset_cb callbacks are provided,
+ * then reset_cb will be called if init_cb fails.
+ * The object passed to reset_cb will be in the state left by init_cb.
+ */
+#define FF_REFSTRUCT_POOL_FLAG_RESET_ON_INIT_ERROR (1 << 16)
+/**
+ * If this flag is set and both init_cb and free_entry_cb callbacks are
+ * provided, then free_cb will be called if init_cb fails.
+ *
+ * It will be called after reset_cb in case reset_cb and the
+ * FF_REFSTRUCT_POOL_FLAG_RESET_ON_INIT_ERROR flag are also set.
+ *
+ * The object passed to free_cb will be in the state left by
+ * the callbacks applied earlier (init_cb potentially followed by reset_cb).
+ */
+#define FF_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR (1 << 17)
+
+/**
+ * Equivalent to ff_refstruct_pool_alloc(size, flags, NULL, NULL, NULL, NULL, NULL)
+ */
+FFRefStructPool *ff_refstruct_pool_alloc(size_t size, unsigned flags);
+
+/**
+ * Allocate an FFRefStructPool, potentially using complex callbacks.
+ *
+ * @param size size of the entries of the pool
+ * @param flags a bitwise combination of FF_REFSTRUCT_POOL_FLAG_* flags
+ * @param opaque A pointer that will be passed to the callbacks below.
+ * @param init A callback that will be called directly after a new entry
+ * has been allocated. obj has already been zeroed unless
+ * the FF_REFSTRUCT_POOL_FLAG_NO_ZEROING flag is in use.
+ * @param reset A callback that will be called after an entry has been
+ * returned to the pool and before it is reused.
+ * @param free_entry A callback that will be called when an entry is freed
+ * after the pool has been marked as to be uninitialized.
+ * @param free A callback that will be called when the pool itself is
+ * freed (after the last entry has been returned and freed).
+ */
+FFRefStructPool *ff_refstruct_pool_alloc_ext_c(size_t size, unsigned flags,
+ 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));
+
+/**
+ * A wrapper around ff_refstruct_pool_alloc_ext_c() for the common case
+ * of a non-const qualified opaque.
+ *
+ * @see ff_refstruct_pool_alloc_ext_c()
+ */
+static inline
+FFRefStructPool *ff_refstruct_pool_alloc_ext(size_t size, unsigned flags,
+ void *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))
+{
+ return ff_refstruct_pool_alloc_ext_c(size, flags, (FFRefStructOpaque){.nc = opaque},
+ init_cb, reset_cb, free_entry_cb, free_cb);
+}
+
+/**
+ * Get an object from the pool, reusing an old one from the pool when
+ * available.
+ *
+ * Every call to this function must happen before ff_refstruct_pool_uninit().
+ * Otherwise undefined behaviour may occur.
+ *
+ * @param pool the pool from which to get the object
+ * @return a reference to the object on success, NULL on error.
+ */
+void *ff_refstruct_pool_get(FFRefStructPool *pool);
+
+/**
+ * Mark the pool as being available for freeing. It will actually be freed
+ * only once all the allocated buffers associated with the pool are released.
+ * Thus it is safe to call this function while some of the allocated buffers
+ * are still in use.
+ *
+ * It is illegal to try to get a new entry after this function has been called.
+ *
+ * @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);
+
#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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 17/42] avcodec/refstruct: Add RefStruct pool API
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 17/42] avcodec/refstruct: Add RefStruct pool API Andreas Rheinhardt
@ 2023-09-20 19:58 ` Michael Niedermayer
2023-09-21 0:28 ` Andreas Rheinhardt
2023-10-04 8:39 ` Anton Khirnov
1 sibling, 1 reply; 106+ messages in thread
From: Michael Niedermayer @ 2023-09-20 19:58 UTC (permalink / raw)
To: FFmpeg development discussions and patches
[-- Attachment #1.1: Type: text/plain, Size: 3200 bytes --]
On Tue, Sep 19, 2023 at 09:57:09PM +0200, Andreas Rheinhardt wrote:
> 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 <andreas.rheinhardt@outlook.com>
> ---
> libavcodec/refstruct.c | 194 ++++++++++++++++++++++++++++++++++++++++-
> libavcodec/refstruct.h | 128 +++++++++++++++++++++++++++
> 2 files changed, 321 insertions(+), 1 deletion(-)
seems to break building on ppc (--disable-pthreads)
CC libavcodec/refstruct.o
src/libavcodec/refstruct.c: In function ‘pool_free’:
src/libavcodec/refstruct.c:187:5: error: implicit declaration of function ‘pthread_mutex_destroy’; did you mean ‘ff_mutex_destroy’? [-Werror=implicit-function-declaration]
pthread_mutex_destroy(&pool->mutex);
^~~~~~~~~~~~~~~~~~~~~
ff_mutex_destroy
src/libavcodec/refstruct.c: In function ‘pool_return_entry’:
src/libavcodec/refstruct.c:205:5: error: implicit declaration of function ‘pthread_mutex_lock’; did you mean ‘ff_mutex_lock’? [-Werror=implicit-function-declaration]
pthread_mutex_lock(&pool->mutex);
^~~~~~~~~~~~~~~~~~
ff_mutex_lock
src/libavcodec/refstruct.c:211:5: error: implicit declaration of function ‘pthread_mutex_unlock’; did you mean ‘ff_mutex_unlock’? [-Werror=implicit-function-declaration]
pthread_mutex_unlock(&pool->mutex);
^~~~~~~~~~~~~~~~~~~~
ff_mutex_unlock
src/libavcodec/refstruct.c: In function ‘ff_refstruct_pool_alloc_ext_c’:
src/libavcodec/refstruct.c:339:11: error: implicit declaration of function ‘pthread_mutex_init’; did you mean ‘ff_mutex_init’? [-Werror=implicit-function-declaration]
err = pthread_mutex_init(&pool->mutex, NULL);
^~~~~~~~~~~~~~~~~~
ff_mutex_init
cc1: some warnings being treated as errors
/home/michael/ffmpeg-git/ffmpeg/ffbuild/common.mak:81: recipe for target 'libavcodec/refstruct.o' failed
make: *** [libavcodec/refstruct.o] Error 1
make: Target 'all' not remade because of errors.
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
During times of universal deceit, telling the truth becomes a
revolutionary act. -- George Orwell
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]
[-- Attachment #2: 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] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 17/42] avcodec/refstruct: Add RefStruct pool API
2023-09-20 19:58 ` Michael Niedermayer
@ 2023-09-21 0:28 ` Andreas Rheinhardt
0 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-21 0:28 UTC (permalink / raw)
To: ffmpeg-devel
Michael Niedermayer:
> On Tue, Sep 19, 2023 at 09:57:09PM +0200, Andreas Rheinhardt wrote:
>> 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 <andreas.rheinhardt@outlook.com>
>> ---
>> libavcodec/refstruct.c | 194 ++++++++++++++++++++++++++++++++++++++++-
>> libavcodec/refstruct.h | 128 +++++++++++++++++++++++++++
>> 2 files changed, 321 insertions(+), 1 deletion(-)
>
> seems to break building on ppc (--disable-pthreads)
>
> CC libavcodec/refstruct.o
> src/libavcodec/refstruct.c: In function ‘pool_free’:
> src/libavcodec/refstruct.c:187:5: error: implicit declaration of function ‘pthread_mutex_destroy’; did you mean ‘ff_mutex_destroy’? [-Werror=implicit-function-declaration]
> pthread_mutex_destroy(&pool->mutex);
> ^~~~~~~~~~~~~~~~~~~~~
> ff_mutex_destroy
> src/libavcodec/refstruct.c: In function ‘pool_return_entry’:
> src/libavcodec/refstruct.c:205:5: error: implicit declaration of function ‘pthread_mutex_lock’; did you mean ‘ff_mutex_lock’? [-Werror=implicit-function-declaration]
> pthread_mutex_lock(&pool->mutex);
> ^~~~~~~~~~~~~~~~~~
> ff_mutex_lock
> src/libavcodec/refstruct.c:211:5: error: implicit declaration of function ‘pthread_mutex_unlock’; did you mean ‘ff_mutex_unlock’? [-Werror=implicit-function-declaration]
> pthread_mutex_unlock(&pool->mutex);
> ^~~~~~~~~~~~~~~~~~~~
> ff_mutex_unlock
> src/libavcodec/refstruct.c: In function ‘ff_refstruct_pool_alloc_ext_c’:
> src/libavcodec/refstruct.c:339:11: error: implicit declaration of function ‘pthread_mutex_init’; did you mean ‘ff_mutex_init’? [-Werror=implicit-function-declaration]
> err = pthread_mutex_init(&pool->mutex, NULL);
> ^~~~~~~~~~~~~~~~~~
> ff_mutex_init
> cc1: some warnings being treated as errors
> /home/michael/ffmpeg-git/ffmpeg/ffbuild/common.mak:81: recipe for target 'libavcodec/refstruct.o' failed
> make: *** [libavcodec/refstruct.o] Error 1
> make: Target 'all' not remade because of errors.
Sorry for not having tested --disable-pthreads. Will switch to our
ff_mutex-wrappers.
- 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] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 17/42] avcodec/refstruct: Add RefStruct pool API
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 17/42] avcodec/refstruct: Add RefStruct pool API Andreas Rheinhardt
2023-09-20 19:58 ` Michael Niedermayer
@ 2023-10-04 8:39 ` Anton Khirnov
2023-10-04 11:09 ` Andreas Rheinhardt
1 sibling, 1 reply; 106+ messages in thread
From: Anton Khirnov @ 2023-10-04 8:39 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:09)
> 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().)
Considering that it's intended to be used from multiple threads, that
seems like the better option. Though I have not seen the following
patches yet, so maybe the advantage is not as big as I'd think.
> +/**
> + * If this flag is not set, every object in the pool will be zeroed before
> + * the init callback is called or before it is turned over to the user
> + * for the first time if no init callback has been provided.
> + */
> +#define FF_REFSTRUCT_POOL_FLAG_NO_ZEROING FF_REFSTRUCT_FLAG_NO_ZEROING
Do you think using the same namespace really improves things? It does
not seem so to me.
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 17/42] avcodec/refstruct: Add RefStruct pool API
2023-10-04 8:39 ` Anton Khirnov
@ 2023-10-04 11:09 ` Andreas Rheinhardt
0 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-10-04 11:09 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Anton Khirnov:
> Quoting Andreas Rheinhardt (2023-09-19 21:57:09)
>> 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().)
>
> Considering that it's intended to be used from multiple threads, that
> seems like the better option. Though I have not seen the following
> patches yet, so maybe the advantage is not as big as I'd think.
>
It is implemented in patch #24.
>> +/**
>> + * If this flag is not set, every object in the pool will be zeroed before
>> + * the init callback is called or before it is turned over to the user
>> + * for the first time if no init callback has been provided.
>> + */
>> +#define FF_REFSTRUCT_POOL_FLAG_NO_ZEROING FF_REFSTRUCT_FLAG_NO_ZEROING
>
> Do you think using the same namespace really improves things? It does
> not seem so to me.
>
Actually, the namespaces are separate. The pool API uses
FF_REFSTRUCT_POOL_FLAG_*, the ordinary RefStruct API uses
FF_REFSTRUCT_FLAG_*. That some pool flags are simply mapped to non-pool
flags is an implementation detail and does not join the namespaces.
- 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] 106+ messages in thread
* [FFmpeg-devel] [PATCH 18/42] avcodec/h264dec: Use RefStruct-pool API instead of AVBufferPool API
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (16 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 17/42] avcodec/refstruct: Add RefStruct pool API Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-10-04 14:07 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 19/42] avcodec/hevcdec: " Andreas Rheinhardt
` (30 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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(&pic->hwaccel_picture_private);
- av_buffer_unref(&pic->qscale_table_buf);
- av_buffer_unref(&pic->mb_type_buf);
+ ff_refstruct_unref(&pic->qscale_table_base);
+ ff_refstruct_unref(&pic->mb_type_base);
ff_refstruct_unref(&pic->pps);
for (i = 0; i < 2; i++) {
- av_buffer_unref(&pic->motion_val_buf[i]);
- av_buffer_unref(&pic->ref_index_buf[i]);
+ ff_refstruct_unref(&pic->motion_val_base[i]);
+ ff_refstruct_unref(&pic->ref_index[i]);
}
- av_buffer_unref(&pic->decode_error_flags);
+ ff_refstruct_unref(&pic->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(&dst->qscale_table_base, src->qscale_table_base);
+ ff_refstruct_replace(&dst->mb_type_base, src->mb_type_base);
ff_refstruct_replace(&dst->pps, src->pps);
+ for (int i = 0; i < 2; i++) {
+ ff_refstruct_replace(&dst->motion_val_base[i], src->motion_val_base[i]);
+ ff_refstruct_replace(&dst->ref_index[i], src->ref_index[i]);
+ }
+
+ ff_refstruct_replace(&dst->hwaccel_picture_private,
+ src->hwaccel_picture_private);
+
+ ff_refstruct_replace(&dst->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(&dst->hwaccel_picture_private,
- src->hwaccel_picture_private);
-
- ret = av_buffer_replace(&dst->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(&dst->qscale_table_buf, src->qscale_table_buf);
- ret |= av_buffer_replace(&dst->mb_type_buf, src->mb_type_buf);
- if (ret < 0)
- goto fail;
-
- for (i = 0; i < 2; i++) {
- ret = av_buffer_replace(&dst->motion_val_buf[i], src->motion_val_buf[i]);
- ret |= av_buffer_replace(&dst->ref_index_buf[i], src->ref_index_buf[i]);
- if (ret < 0)
- goto fail;
- }
-
- ff_refstruct_replace(&dst->hwaccel_picture_private,
- src->hwaccel_picture_private);
-
- ret = av_buffer_replace(&dst->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 6df80c9522..3e21caeda7 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -165,20 +165,19 @@ static int init_table_pools(H264Context *h)
const int b4_stride = h->mb_width * 4 + 1;
const int b4_array_size = b4_stride * h->mb_height * 4;
- h->qscale_table_pool = av_buffer_pool_init(big_mb_num + h->mb_stride,
- av_buffer_allocz);
- h->mb_type_pool = av_buffer_pool_init((big_mb_num + h->mb_stride) *
- sizeof(uint32_t), av_buffer_allocz);
- h->motion_val_pool = av_buffer_pool_init(2 * (b4_array_size + 4) *
- sizeof(int16_t), av_buffer_allocz);
- h->ref_index_pool = av_buffer_pool_init(4 * mb_array_size, av_buffer_allocz);
+ h->qscale_table_pool = ff_refstruct_pool_alloc(big_mb_num + h->mb_stride, 0);
+ h->mb_type_pool = ff_refstruct_pool_alloc((big_mb_num + h->mb_stride) *
+ sizeof(uint32_t), 0);
+ h->motion_val_pool = ff_refstruct_pool_alloc(2 * (b4_array_size + 4) *
+ sizeof(int16_t), 0);
+ h->ref_index_pool = ff_refstruct_pool_alloc(4 * mb_array_size, 0);
if (!h->qscale_table_pool || !h->mb_type_pool || !h->motion_val_pool ||
!h->ref_index_pool) {
- av_buffer_pool_uninit(&h->qscale_table_pool);
- av_buffer_pool_uninit(&h->mb_type_pool);
- av_buffer_pool_uninit(&h->motion_val_pool);
- av_buffer_pool_uninit(&h->ref_index_pool);
+ ff_refstruct_pool_uninit(&h->qscale_table_pool);
+ ff_refstruct_pool_uninit(&h->mb_type_pool);
+ ff_refstruct_pool_uninit(&h->motion_val_pool);
+ ff_refstruct_pool_uninit(&h->ref_index_pool);
return AVERROR(ENOMEM);
}
@@ -211,10 +210,10 @@ static int alloc_picture(H264Context *h, H264Picture *pic)
goto fail;
if (h->decode_error_flags_pool) {
- pic->decode_error_flags = av_buffer_pool_get(h->decode_error_flags_pool);
+ pic->decode_error_flags = ff_refstruct_pool_get(h->decode_error_flags_pool);
if (!pic->decode_error_flags)
goto fail;
- atomic_init((atomic_int*)pic->decode_error_flags->data, 0);
+ atomic_init(pic->decode_error_flags, 0);
}
if (CONFIG_GRAY && !h->avctx->hwaccel && h->flags & AV_CODEC_FLAG_GRAY && pic->f->data[2]) {
@@ -236,22 +235,21 @@ static int alloc_picture(H264Context *h, H264Picture *pic)
goto fail;
}
- pic->qscale_table_buf = av_buffer_pool_get(h->qscale_table_pool);
- pic->mb_type_buf = av_buffer_pool_get(h->mb_type_pool);
- if (!pic->qscale_table_buf || !pic->mb_type_buf)
+ pic->qscale_table_base = ff_refstruct_pool_get(h->qscale_table_pool);
+ pic->mb_type_base = ff_refstruct_pool_get(h->mb_type_pool);
+ if (!pic->qscale_table_base || !pic->mb_type_base)
goto fail;
- pic->mb_type = (uint32_t*)pic->mb_type_buf->data + 2 * h->mb_stride + 1;
- pic->qscale_table = pic->qscale_table_buf->data + 2 * h->mb_stride + 1;
+ pic->mb_type = pic->mb_type_base + 2 * h->mb_stride + 1;
+ pic->qscale_table = pic->qscale_table_base + 2 * h->mb_stride + 1;
for (i = 0; i < 2; i++) {
- pic->motion_val_buf[i] = av_buffer_pool_get(h->motion_val_pool);
- pic->ref_index_buf[i] = av_buffer_pool_get(h->ref_index_pool);
- if (!pic->motion_val_buf[i] || !pic->ref_index_buf[i])
+ pic->motion_val_base[i] = ff_refstruct_pool_get(h->motion_val_pool);
+ pic->ref_index[i] = ff_refstruct_pool_get(h->ref_index_pool);
+ if (!pic->motion_val_base[i] || !pic->ref_index[i])
goto fail;
- pic->motion_val[i] = (int16_t (*)[2])pic->motion_val_buf[i]->data + 4;
- pic->ref_index[i] = pic->ref_index_buf[i]->data;
+ pic->motion_val[i] = pic->motion_val_base[i] + 4;
}
pic->pps = ff_refstruct_ref_c(h->ps.pps);
diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c
index 796f80be8d..8578d3b346 100644
--- a/libavcodec/h264dec.c
+++ b/libavcodec/h264dec.c
@@ -51,6 +51,7 @@
#include "mpegutils.h"
#include "profiles.h"
#include "rectangle.h"
+#include "refstruct.h"
#include "thread.h"
#include "threadframe.h"
@@ -151,10 +152,10 @@ void ff_h264_free_tables(H264Context *h)
av_freep(&h->mb2b_xy);
av_freep(&h->mb2br_xy);
- av_buffer_pool_uninit(&h->qscale_table_pool);
- av_buffer_pool_uninit(&h->mb_type_pool);
- av_buffer_pool_uninit(&h->motion_val_pool);
- av_buffer_pool_uninit(&h->ref_index_pool);
+ ff_refstruct_pool_uninit(&h->qscale_table_pool);
+ ff_refstruct_pool_uninit(&h->mb_type_pool);
+ ff_refstruct_pool_uninit(&h->motion_val_pool);
+ ff_refstruct_pool_uninit(&h->ref_index_pool);
#if CONFIG_ERROR_RESILIENCE
av_freep(&h->er.mb_index2xy);
@@ -308,7 +309,7 @@ static int h264_init_context(AVCodecContext *avctx, H264Context *h)
ff_h264_sei_uninit(&h->sei);
if (avctx->active_thread_type & FF_THREAD_FRAME) {
- h->decode_error_flags_pool = av_buffer_pool_init(sizeof(atomic_int), NULL);
+ h->decode_error_flags_pool = ff_refstruct_pool_alloc(sizeof(atomic_int), 0);
if (!h->decode_error_flags_pool)
return AVERROR(ENOMEM);
}
@@ -359,7 +360,7 @@ static av_cold int h264_decode_end(AVCodecContext *avctx)
h->cur_pic_ptr = NULL;
- av_buffer_pool_uninit(&h->decode_error_flags_pool);
+ ff_refstruct_pool_uninit(&h->decode_error_flags_pool);
av_freep(&h->slice_ctx);
h->nb_slice_ctx = 0;
@@ -749,7 +750,7 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size)
if ((ret < 0 || h->er.error_occurred) && h->cur_pic_ptr) {
if (h->cur_pic_ptr->decode_error_flags) {
/* Frame-threading in use */
- atomic_int *decode_error = (atomic_int*)h->cur_pic_ptr->decode_error_flags->data;
+ atomic_int *decode_error = h->cur_pic_ptr->decode_error_flags;
/* Using atomics here is not supposed to provide syncronisation;
* they are merely used to allow to set decode_error from both
* decoding threads in case of coded slices. */
@@ -800,7 +801,7 @@ end:
ff_er_frame_end(&h->er, &decode_error_flags);
if (decode_error_flags) {
if (h->cur_pic_ptr->decode_error_flags) {
- atomic_int *decode_error = (atomic_int*)h->cur_pic_ptr->decode_error_flags->data;
+ atomic_int *decode_error = h->cur_pic_ptr->decode_error_flags;
atomic_fetch_or_explicit(decode_error, decode_error_flags,
memory_order_relaxed);
} else
@@ -878,7 +879,7 @@ static int output_frame(H264Context *h, AVFrame *dst, H264Picture *srcp)
return ret;
if (srcp->decode_error_flags) {
- atomic_int *decode_error = (atomic_int*)srcp->decode_error_flags->data;
+ atomic_int *decode_error = srcp->decode_error_flags;
/* The following is not supposed to provide synchronisation at all:
* given that srcp has already finished decoding, decode_error
* has already been set to its final value. */
diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h
index 7436e0a54f..a330e0a24f 100644
--- a/libavcodec/h264dec.h
+++ b/libavcodec/h264dec.h
@@ -108,19 +108,18 @@ typedef struct H264Picture {
AVFrame *f_grain;
- AVBufferRef *qscale_table_buf;
+ int8_t *qscale_table_base; ///< RefStruct reference
int8_t *qscale_table;
- AVBufferRef *motion_val_buf[2];
+ int16_t (*motion_val_base[2])[2]; ///< RefStruct reference
int16_t (*motion_val[2])[2];
- AVBufferRef *mb_type_buf;
+ uint32_t *mb_type_base; ///< RefStruct reference
uint32_t *mb_type;
void *hwaccel_picture_private; ///< hardware accelerator private data
- AVBufferRef *ref_index_buf[2];
- int8_t *ref_index[2];
+ int8_t *ref_index[2]; ///< RefStruct reference
int field_poc[2]; ///< top/bottom POC
int poc; ///< frame POC
@@ -151,8 +150,8 @@ typedef struct H264Picture {
int mb_width, mb_height;
int mb_stride;
- /* data points to an atomic_int */
- AVBufferRef *decode_error_flags;
+ /// RefStruct reference; its pointee is shared between decoding threads.
+ atomic_int *decode_error_flags;
} H264Picture;
typedef struct H264Ref {
@@ -546,11 +545,11 @@ typedef struct H264Context {
H264SEIContext sei;
- AVBufferPool *qscale_table_pool;
- AVBufferPool *mb_type_pool;
- AVBufferPool *motion_val_pool;
- AVBufferPool *ref_index_pool;
- AVBufferPool *decode_error_flags_pool;
+ struct FFRefStructPool *qscale_table_pool;
+ struct FFRefStructPool *mb_type_pool;
+ struct FFRefStructPool *motion_val_pool;
+ struct FFRefStructPool *ref_index_pool;
+ struct FFRefStructPool *decode_error_flags_pool;
int ref2frm[MAX_SLICES][2][64]; ///< reference to frame number lists, used in the loop filter, the first 2 are for -2,-1
} H264Context;
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 18/42] avcodec/h264dec: Use RefStruct-pool API instead of AVBufferPool API
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 18/42] avcodec/h264dec: Use RefStruct-pool API instead of AVBufferPool API Andreas Rheinhardt
@ 2023-10-04 14:07 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-10-04 14:07 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:10)
> 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 <andreas.rheinhardt@outlook.com>
> ---
> 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(-)
LGTM
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 19/42] avcodec/hevcdec: Use RefStruct-pool API instead of AVBufferPool API
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (17 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 18/42] avcodec/h264dec: Use RefStruct-pool API instead of AVBufferPool API Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-10-04 14:12 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 20/42] avcodec/nvdec: Use RefStruct-pool API for decoder pool Andreas Rheinhardt
` (29 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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(&frame->tab_mvf_buf);
- frame->tab_mvf = NULL;
+ ff_refstruct_unref(&frame->tab_mvf);
ff_refstruct_unref(&frame->rpl);
frame->nb_rpl_elems = 0;
- av_buffer_unref(&frame->rpl_tab_buf);
- frame->rpl_tab = NULL;
+ ff_refstruct_unref(&frame->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(&s->sh.size);
av_freep(&s->sh.offset);
- av_buffer_pool_uninit(&s->tab_mvf_pool);
- av_buffer_pool_uninit(&s->rpl_tab_pool);
+ ff_refstruct_pool_uninit(&s->tab_mvf_pool);
+ ff_refstruct_pool_uninit(&s->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 FFRefStructPool *tab_mvf_pool;
+ struct FFRefStructPool *rpl_tab_pool;
///< candidate references for the current frame
RefPicList rps[5];
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 19/42] avcodec/hevcdec: Use RefStruct-pool API instead of AVBufferPool API
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 19/42] avcodec/hevcdec: " Andreas Rheinhardt
@ 2023-10-04 14:12 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-10-04 14:12 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:11)
> 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 <andreas.rheinhardt@outlook.com>
> ---
> libavcodec/hevc_refs.c | 16 ++++++----------
> libavcodec/hevcdec.c | 25 ++++++-------------------
> libavcodec/hevcdec.h | 10 ++++------
> 3 files changed, 16 insertions(+), 35 deletions(-)
Looks ok
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 20/42] avcodec/nvdec: Use RefStruct-pool API for decoder pool
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (18 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 19/42] avcodec/hevcdec: " Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-10-04 14:28 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 21/42] avcodec/refstruct: Allow to always return zeroed pool entries Andreas Rheinhardt
` (28 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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(&ctx->decoder);
- av_buffer_pool_uninit(&ctx->decoder_pool);
+ ff_refstruct_pool_uninit(&ctx->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(&cf->idx_ref);
- av_buffer_unref(&cf->ref_idx_ref);
+ ff_refstruct_unref(&cf->idx_ref);
+ ff_refstruct_unref(&cf->ref_idx_ref);
ff_refstruct_unref(&cf->decoder);
av_freep(&priv);
@@ -469,8 +471,8 @@ static void nvdec_unmap_mapped_frame(void *opaque, uint8_t *data)
CHECK_CU(decoder->cudl->cuCtxPopCurrent(&dummy));
finish:
- av_buffer_unref(&unmap_data->idx_ref);
- av_buffer_unref(&unmap_data->ref_idx_ref);
+ ff_refstruct_unref(&unmap_data->idx_ref);
+ ff_refstruct_unref(&unmap_data->ref_idx_ref);
ff_refstruct_unref(&unmap_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, &shift_h, &shift_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;
}
}
- cf->ref_idx = *(unsigned int*)cf->ref_idx_ref->data;
+ cf->ref_idx = *cf->ref_idx_ref;
} else {
- av_buffer_unref(&cf->ref_idx_ref);
+ ff_refstruct_unref(&cf->ref_idx_ref);
cf->ref_idx = cf->idx;
}
diff --git a/libavcodec/nvdec.h b/libavcodec/nvdec.h
index efacb5b691..353e95bf42 100644
--- a/libavcodec/nvdec.h
+++ b/libavcodec/nvdec.h
@@ -44,15 +44,15 @@
typedef struct NVDECFrame {
unsigned int idx;
unsigned int ref_idx;
- AVBufferRef *idx_ref;
- AVBufferRef *ref_idx_ref;
+ unsigned int *idx_ref; ///< RefStruct reference
+ unsigned int *ref_idx_ref; ///< RefStruct reference
struct NVDECDecoder *decoder; ///< RefStruct reference
} NVDECFrame;
typedef struct NVDECContext {
CUVIDPICPARAMS pic_params;
- AVBufferPool *decoder_pool;
+ struct FFRefStructPool *decoder_pool;
struct NVDECDecoder *decoder; ///< 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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 20/42] avcodec/nvdec: Use RefStruct-pool API for decoder pool
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 20/42] avcodec/nvdec: Use RefStruct-pool API for decoder pool Andreas Rheinhardt
@ 2023-10-04 14:28 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-10-04 14:28 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:12)
> 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 <andreas.rheinhardt@outlook.com>
> ---
> 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.
AFAIK the API does not allow it, so there's nothing we can do about it.
Patch LGTM
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 21/42] avcodec/refstruct: Allow to always return zeroed pool entries
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (19 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 20/42] avcodec/nvdec: Use RefStruct-pool API for decoder pool Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-10-12 12:45 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 22/42] avcodec/vp9: Use RefStruct-pool API for extradata Andreas Rheinhardt
` (27 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
This is in preparation for the following commit.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
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(&pool->refcount, 1, memory_order_relaxed);
+
+ if (pool->pool_flags & FF_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME)
+ memset(ret, 0, pool->size);
+
memcpy(datap, &ret, 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(&pool->refcount, 1);
err = pthread_mutex_init(&pool->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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 21/42] avcodec/refstruct: Allow to always return zeroed pool entries
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 21/42] avcodec/refstruct: Allow to always return zeroed pool entries Andreas Rheinhardt
@ 2023-10-12 12:45 ` Anton Khirnov
2023-10-12 13:25 ` Andreas Rheinhardt
0 siblings, 1 reply; 106+ messages in thread
From: Anton Khirnov @ 2023-10-12 12:45 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:13)
> diff --git a/libavcodec/refstruct.h b/libavcodec/refstruct.h
> Furthermore, it also makes the pool behave as if the
> FF_REFSTRUCT_POOL_FLAG_NO_ZEROING flag had been provided.
What does this imply for the caller?
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 21/42] avcodec/refstruct: Allow to always return zeroed pool entries
2023-10-12 12:45 ` Anton Khirnov
@ 2023-10-12 13:25 ` Andreas Rheinhardt
2023-10-12 13:56 ` Anton Khirnov
0 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-10-12 13:25 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Anton Khirnov:
> Quoting Andreas Rheinhardt (2023-09-19 21:57:13)
>> diff --git a/libavcodec/refstruct.h b/libavcodec/refstruct.h
>> Furthermore, it also makes the pool behave as if the
>> FF_REFSTRUCT_POOL_FLAG_NO_ZEROING flag had been provided.
>
> What does this imply for the caller?
>
It means that if you have an init callback, that the object has not been
zeroed before it is given to you. So the init function would probably be
only useful for logging. If you don't have an init callback at all, you
won't notice the difference.
The rationale for this behaviour is that it makes no sense to zero
initially if it is zeroed generically before every use and I want to
spare the user to set the FF_REFSTRUCT_POOL_FLAG_NO_ZEROING flag (which
could be easily forgotten).
- 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] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 21/42] avcodec/refstruct: Allow to always return zeroed pool entries
2023-10-12 13:25 ` Andreas Rheinhardt
@ 2023-10-12 13:56 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-10-12 13:56 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Quoting Andreas Rheinhardt (2023-10-12 15:25:14)
> Anton Khirnov:
> > Quoting Andreas Rheinhardt (2023-09-19 21:57:13)
> >> diff --git a/libavcodec/refstruct.h b/libavcodec/refstruct.h
> >> Furthermore, it also makes the pool behave as if the
> >> FF_REFSTRUCT_POOL_FLAG_NO_ZEROING flag had been provided.
> >
> > What does this imply for the caller?
> >
>
> It means that if you have an init callback, that the object has not been
> zeroed before it is given to you. So the init function would probably be
> only useful for logging. If you don't have an init callback at all, you
> won't notice the difference.
> The rationale for this behaviour is that it makes no sense to zero
> initially if it is zeroed generically before every use and I want to
> spare the user to set the FF_REFSTRUCT_POOL_FLAG_NO_ZEROING flag (which
> could be easily forgotten).
Can you mention this in the docs then?
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 22/42] avcodec/vp9: Use RefStruct-pool API for extradata
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (20 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 21/42] avcodec/refstruct: Allow to always return zeroed pool entries Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 23/42] avcodec/vaapi_encode: Use RefStruct pool API, stop abusing AVBuffer API Andreas Rheinhardt
` (26 subsequent siblings)
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
It avoids allocations and corresponding error checks.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
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, &f->tf);
- av_buffer_unref(&f->extradata);
+ ff_refstruct_unref(&f->extradata);
ff_refstruct_unref(&f->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(&s->frame_extradata_pool);
- s->frame_extradata_pool = av_buffer_pool_init(sz * (1 + sizeof(VP9mvrefPair)), NULL);
+ ff_refstruct_pool_uninit(&s->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, &f->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->s.frames[i]);
av_frame_free(&s->s.frames[i].tf.f);
}
- av_buffer_pool_uninit(&s->frame_extradata_pool);
+ ff_refstruct_pool_uninit(&s->frame_extradata_pool);
for (i = 0; i < 8; i++) {
ff_thread_release_ext_buffer(avctx, &s->s.refs[i]);
av_frame_free(&s->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 <stdint.h>
#include <stdatomic.h>
-#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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 23/42] avcodec/vaapi_encode: Use RefStruct pool API, stop abusing AVBuffer API
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (21 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 22/42] avcodec/vp9: Use RefStruct-pool API for extradata Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 24/42] avcodec/refstruct: Allow to share pools Andreas Rheinhardt
` (25 subsequent siblings)
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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 <inttypes.h>
#include <string.h>
+#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(&pic->slices);
av_freep(&pic->roi);
av_frame_free(&pic->recon_image);
- av_buffer_unref(&pic->output_buffer_ref);
+ ff_refstruct_unref(&pic->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(&pic->output_buffer_ref);
+ ff_refstruct_unref(&pic->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(&pic->output_buffer_ref);
+ ff_refstruct_unref(&pic->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(&pic->output_buffer_ref);
+ ff_refstruct_unref(&pic->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, &buffer_id);
+ (1 << 16), 1, 0, buffer_id);
if (vas != VA_STATUS_SUCCESS) {
av_log(avctx, AV_LOG_ERROR, "Failed to create bitstream "
"output buffer: %d (%s).\n", vas, vaErrorStr(vas));
- return NULL;
+ return AVERROR(ENOMEM);
}
- av_log(avctx, AV_LOG_DEBUG, "Allocated output buffer %#x\n", buffer_id);
+ av_log(avctx, AV_LOG_DEBUG, "Allocated output buffer %#x\n", *buffer_id);
- ref = av_buffer_create((uint8_t*)(uintptr_t)buffer_id,
- sizeof(buffer_id),
- &vaapi_encode_free_output_buffer,
- avctx, AV_BUFFER_FLAG_READONLY);
- if (!ref) {
- vaDestroyBuffer(ctx->hwctx->display, buffer_id);
- return NULL;
- }
-
- return ref;
+ return 0;
}
static av_cold int vaapi_encode_create_recon_frames(AVCodecContext *avctx)
@@ -2677,8 +2666,9 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx)
}
ctx->output_buffer_pool =
- av_buffer_pool_init2(sizeof(VABufferID), avctx,
- &vaapi_encode_alloc_output_buffer, NULL);
+ ff_refstruct_pool_alloc_ext(sizeof(VABufferID), 0, avctx,
+ &vaapi_encode_alloc_output_buffer, NULL,
+ vaapi_encode_free_output_buffer, NULL);
if (!ctx->output_buffer_pool) {
err = AVERROR(ENOMEM);
goto fail;
@@ -2776,7 +2766,7 @@ av_cold int ff_vaapi_encode_close(AVCodecContext *avctx)
vaapi_encode_free(avctx, pic);
}
- av_buffer_pool_uninit(&ctx->output_buffer_pool);
+ ff_refstruct_pool_uninit(&ctx->output_buffer_pool);
if (ctx->va_context != VA_INVALID_ID) {
vaDestroyContext(ctx->hwctx->display, ctx->va_context);
diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h
index bd25cd5c95..741f6c6a77 100644
--- a/libavcodec/vaapi_encode.h
+++ b/libavcodec/vaapi_encode.h
@@ -102,7 +102,8 @@ typedef struct VAAPIEncodePicture {
int nb_param_buffers;
VABufferID *param_buffers;
- AVBufferRef *output_buffer_ref;
+ /* Refcounted via the refstruct-API */
+ VABufferID *output_buffer_ref;
VABufferID output_buffer;
void *priv_data;
@@ -262,7 +263,7 @@ typedef struct VAAPIEncodeContext {
AVHWFramesContext *recon_frames;
// Pool of (reusable) bitstream output buffers.
- AVBufferPool *output_buffer_pool;
+ struct FFRefStructPool *output_buffer_pool;
// Global parameters which will be applied at the start of the
// sequence (includes rate control parameters below).
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 24/42] avcodec/refstruct: Allow to share pools
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (22 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 23/42] avcodec/vaapi_encode: Use RefStruct pool API, stop abusing AVBuffer API Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-10-12 13:04 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 25/42] avcodec/vp9: Join extradata buffer pools Andreas Rheinhardt
` (24 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
To do this, make FFRefStructPool itself refcounted according
to the RefStruct API.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
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(&pool->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(&pool->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(&pool->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(&pool->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(&pool->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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 24/42] avcodec/refstruct: Allow to share pools
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 24/42] avcodec/refstruct: Allow to share pools Andreas Rheinhardt
@ 2023-10-12 13:04 ` Anton Khirnov
2023-10-12 13:51 ` Andreas Rheinhardt
0 siblings, 1 reply; 106+ messages in thread
From: Anton Khirnov @ 2023-10-12 13:04 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:16)
> To do this, make FFRefStructPool itself refcounted according
> to the RefStruct API.
>
> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
> ---
> 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(&pool->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(&pool->refcount, 1, memory_order_acq_rel) == 1)
Is there a reason you cannot fold pool->refcount into the pool's
containing RefStruct?
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 24/42] avcodec/refstruct: Allow to share pools
2023-10-12 13:04 ` Anton Khirnov
@ 2023-10-12 13:51 ` Andreas Rheinhardt
2023-10-12 14:04 ` Anton Khirnov
0 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-10-12 13:51 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Anton Khirnov:
> Quoting Andreas Rheinhardt (2023-09-19 21:57:16)
>> To do this, make FFRefStructPool itself refcounted according
>> to the RefStruct API.
>>
>> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
>> ---
>> 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(&pool->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(&pool->refcount, 1, memory_order_acq_rel) == 1)
>
> Is there a reason you cannot fold pool->refcount into the pool's
> containing RefStruct?
>
If I simply incremented the pool's refcount for every entry currently in
use by users, then the entries would only be freed when the last entry
has been returned and all the references to the pool unreferenced.
In fact, when I did this, I pondered two things: Shall I make
ff_refstruct_pool_uninit() free all the currently available buffers and
then unreference the caller's reference or shall I just make it a
wrapper to ff_refstruct_unref() to decrement the pool's refcount? The
latter is very simple and I did it; the former could be advantageous in
particular in case of frame-threading in case the dimensions change. (In
this scenario, no user will ever create new entries after the first user
unreferences a pool.)
- 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] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 24/42] avcodec/refstruct: Allow to share pools
2023-10-12 13:51 ` Andreas Rheinhardt
@ 2023-10-12 14:04 ` Anton Khirnov
2023-10-12 14:10 ` Andreas Rheinhardt
2023-10-12 17:09 ` Andreas Rheinhardt
0 siblings, 2 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-10-12 14:04 UTC (permalink / raw)
To: FFmpeg development discussions and patches
Quoting Andreas Rheinhardt (2023-10-12 15:51:18)
> Anton Khirnov:
> > Quoting Andreas Rheinhardt (2023-09-19 21:57:16)
> >> To do this, make FFRefStructPool itself refcounted according
> >> to the RefStruct API.
> >>
> >> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
> >> ---
> >> 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(&pool->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(&pool->refcount, 1, memory_order_acq_rel) == 1)
> >
> > Is there a reason you cannot fold pool->refcount into the pool's
> > containing RefStruct?
> >
>
> If I simply incremented the pool's refcount for every entry currently in
> use by users, then the entries would only be freed when the last entry
> has been returned and all the references to the pool unreferenced.
Ok, can you please mention this in a comment somewhere? It's quite
non-obvious why do both pool_unref() and refstruct_pool_uninit() exist.
> In fact, when I did this, I pondered two things: Shall I make
> ff_refstruct_pool_uninit() free all the currently available buffers and
> then unreference the caller's reference or shall I just make it a
> wrapper to ff_refstruct_unref() to decrement the pool's refcount? The
> latter is very simple and I did it; the former could be advantageous in
> particular in case of frame-threading in case the dimensions change. (In
> this scenario, no user will ever create new entries after the first user
> unreferences a pool.)
But in other scenarios you might want to get rid of some pool references
while still using the others, so maybe that should be a flag if
anything.
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 24/42] avcodec/refstruct: Allow to share pools
2023-10-12 14:04 ` Anton Khirnov
@ 2023-10-12 14:10 ` Andreas Rheinhardt
2023-10-12 17:09 ` Andreas Rheinhardt
1 sibling, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-10-12 14:10 UTC (permalink / raw)
To: ffmpeg-devel
Anton Khirnov:
> Quoting Andreas Rheinhardt (2023-10-12 15:51:18)
>> Anton Khirnov:
>>> Quoting Andreas Rheinhardt (2023-09-19 21:57:16)
>>>> To do this, make FFRefStructPool itself refcounted according
>>>> to the RefStruct API.
>>>>
>>>> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
>>>> ---
>>>> 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(&pool->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(&pool->refcount, 1, memory_order_acq_rel) == 1)
>>>
>>> Is there a reason you cannot fold pool->refcount into the pool's
>>> containing RefStruct?
>>>
>>
>> If I simply incremented the pool's refcount for every entry currently in
>> use by users, then the entries would only be freed when the last entry
>> has been returned and all the references to the pool unreferenced.
>
> Ok, can you please mention this in a comment somewhere? It's quite
> non-obvious why do both pool_unref() and refstruct_pool_uninit() exist.
>
>> In fact, when I did this, I pondered two things: Shall I make
>> ff_refstruct_pool_uninit() free all the currently available buffers and
>> then unreference the caller's reference or shall I just make it a
>> wrapper to ff_refstruct_unref() to decrement the pool's refcount? The
>> latter is very simple and I did it; the former could be advantageous in
>> particular in case of frame-threading in case the dimensions change. (In
>> this scenario, no user will ever create new entries after the first user
>> unreferences a pool.)
>
> But in other scenarios you might want to get rid of some pool references
> while still using the others, so maybe that should be a flag if
> anything.
>
If I added a non-inlined ff_refstruct_pool_uninit(), I could simply
still allow to call ff_refstruct_unref() on pool-references, so that one
can get both behaviours. (Notice that this allows a malicious owner of a
pool-reference to drain the pool ad libitum, but you can do way worse
stuff with a reference than 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] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 24/42] avcodec/refstruct: Allow to share pools
2023-10-12 14:04 ` Anton Khirnov
2023-10-12 14:10 ` Andreas Rheinhardt
@ 2023-10-12 17:09 ` Andreas Rheinhardt
1 sibling, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-10-12 17:09 UTC (permalink / raw)
To: ffmpeg-devel
Anton Khirnov:
> Quoting Andreas Rheinhardt (2023-10-12 15:51:18)
>> Anton Khirnov:
>>> Quoting Andreas Rheinhardt (2023-09-19 21:57:16)
>>>> To do this, make FFRefStructPool itself refcounted according
>>>> to the RefStruct API.
>>>>
>>>> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
>>>> ---
>>>> 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(&pool->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(&pool->refcount, 1, memory_order_acq_rel) == 1)
>>>
>>> Is there a reason you cannot fold pool->refcount into the pool's
>>> containing RefStruct?
>>>
>>
>> If I simply incremented the pool's refcount for every entry currently in
>> use by users, then the entries would only be freed when the last entry
>> has been returned and all the references to the pool unreferenced.
>
> Ok, can you please mention this in a comment somewhere? It's quite
> non-obvious why do both pool_unref() and refstruct_pool_uninit() exist.
>
Right now I could move everything from pool_unref() at the end of
refstruct_pool_uninit(), leaving pool_unref() empty, but existing. The
actual reason that pool_unref() and refstruct_pool_uninit() are
different are:
1. The pool must not be freed when its refcount goes to zero, hence I
need to override its free callback.
2. I pondered adding support for weak references in RefStruct (in this
case the unref callback would be called when there is no strong
reference and the free function when there is no reference at all any
more). In this case I could give every pool entry in use a weak
reference to the pool; FFRefStructPool.refcount would then be
unnecessary, as the pool's weak refcount would take over its function.
- 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] 106+ messages in thread
* [FFmpeg-devel] [PATCH 25/42] avcodec/vp9: Join extradata buffer pools
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (23 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 24/42] avcodec/refstruct: Allow to share pools Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 26/42] avcodec/refstruct: Allow to use a dynamic opaque Andreas Rheinhardt
` (23 subsequent siblings)
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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(&s->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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 26/42] avcodec/refstruct: Allow to use a dynamic opaque
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (24 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 25/42] avcodec/vp9: Join extradata buffer pools Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 27/42] avcodec/pthread_frame: Add new progress API Andreas Rheinhardt
` (22 subsequent siblings)
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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 <stdint.h>
#include <string.h>
+#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(&ref->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(&ref->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(&obj, 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(&ref->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);
+}
+
+static void pool_reset_entry_ext(FFRefStructOpaque opaque,
+ FFRefStructOpaque initial_opaque,
+ void *entry)
+{
+ FFRefStructPool *pool = initial_opaque.nc;
+
+ pool->reset_cb.unref_ext(opaque, pool->opaque, entry);
}
-static int refstruct_pool_get_ext(void *datap, FFRefStructPool *pool)
+static int refstruct_pool_get_ext(void *objp, FFRefStructPool *pool)
{
void *ret = NULL;
- memcpy(datap, &(void *){ NULL }, sizeof(void*));
+ memcpy(objp, &(void *){ NULL }, sizeof(void*));
pthread_mutex_lock(&pool->mutex);
av_assert1(!pool->uninited);
@@ -243,8 +282,13 @@ static int refstruct_pool_get_ext(void *datap, FFRefStructPool *pool)
if (!ret) {
RefCount *ref;
- ret = ff_refstruct_alloc_ext(pool->size, pool->entry_flags, pool,
- pool->reset_cb ? pool_reset_entry : NULL);
+#define CB_INIT(suffix) ((FFRefStructUnrefCB) { .unref ## suffix = pool->reset_cb.unref ## suffix ? \
+ pool_reset_entry ## suffix : NULL })
+ ret = ff_refstruct_alloc_ext_c(pool->size, pool->entry_flags,
+ (FFRefStructOpaque){ .nc = pool },
+ (pool->pool_flags & FF_REFSTRUCT_FLAG_DYNAMIC_OPAQUE) ?
+ CB_INIT(_ext) : CB_INIT());
+#undef CB_INIT
if (!ret)
return AVERROR(ENOMEM);
ref = get_refcount(ret);
@@ -253,7 +297,7 @@ static int refstruct_pool_get_ext(void *datap, FFRefStructPool *pool)
int err = pool->init_cb(pool->opaque, ret);
if (err < 0) {
if (pool->pool_flags & FF_REFSTRUCT_POOL_FLAG_RESET_ON_INIT_ERROR)
- pool->reset_cb(pool->opaque, ret);
+ pool->reset_cb.unref(pool->opaque, ret);
if (pool->pool_flags & FF_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR)
pool->free_entry_cb(pool->opaque, ret);
av_free(ref);
@@ -266,7 +310,7 @@ static int refstruct_pool_get_ext(void *datap, FFRefStructPool *pool)
if (pool->pool_flags & FF_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME)
memset(ret, 0, pool->size);
- memcpy(datap, &ret, sizeof(ret));
+ memcpy(objp, &ret, sizeof(ret));
return 0;
}
@@ -312,7 +356,7 @@ FFRefStructPool *ff_refstruct_pool_alloc(size_t size, unsigned flags)
FFRefStructPool *ff_refstruct_pool_alloc_ext_c(size_t size, unsigned flags,
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))
{
@@ -330,10 +374,15 @@ FFRefStructPool *ff_refstruct_pool_alloc_ext_c(size_t size, unsigned flags,
pool->reset_cb = reset_cb;
pool->free_entry_cb = free_entry_cb;
pool->free_cb = free_cb;
-#define COMMON_FLAGS FF_REFSTRUCT_POOL_FLAG_NO_ZEROING
+#define COMMON_FLAGS (FF_REFSTRUCT_POOL_FLAG_NO_ZEROING | FF_REFSTRUCT_POOL_FLAG_DYNAMIC_OPAQUE)
pool->entry_flags = flags & COMMON_FLAGS;
+ // Dynamic opaque and resetting-on-init-error are incompatible
+ // (there is no dynamic opaque available in ff_refstruct_pool_get()).
+ av_assert1(!(flags & FF_REFSTRUCT_POOL_FLAG_DYNAMIC_OPAQUE &&
+ flags & FF_REFSTRUCT_POOL_FLAG_RESET_ON_INIT_ERROR));
// Filter out nonsense combinations to avoid checks later.
- if (!pool->reset_cb)
+ if (flags & FF_REFSTRUCT_POOL_FLAG_RESET_ON_INIT_ERROR &&
+ !pool->reset_cb.unref)
flags &= ~FF_REFSTRUCT_POOL_FLAG_RESET_ON_INIT_ERROR;
if (!pool->free_entry_cb)
flags &= ~FF_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR;
diff --git a/libavcodec/refstruct.h b/libavcodec/refstruct.h
index d525be61e8..b0a750e2f7 100644
--- a/libavcodec/refstruct.h
+++ b/libavcodec/refstruct.h
@@ -53,18 +53,42 @@
*
* The functions provided by this API with an FFRefStructOpaque come in pairs
* named foo_c and foo. The foo function accepts void* as opaque and is just
- * a wrapper around the foo_c function; "_c" means "(potentially) const".
+ * a wrapper around the foo_c function for the common case of a non-const
+ * opaque ("_c" means "(potentially) const"). For the allocation functions
+ * the wrappers also accept the ordinary "unref" form of FFRefStructUnrefCB;
+ * only the "_c" versions accept the full union to set the unref_ext variant.
*/
typedef union {
void *nc;
const void *c;
} FFRefStructOpaque;
+typedef union FFRefStructUnrefCB {
+ void (*unref)(FFRefStructOpaque opaque, void *obj);
+ void (*unref_ext)(FFRefStructOpaque dynamic_opaque,
+ FFRefStructOpaque initial_opaque,
+ void *obj);
+} FFRefStructUnrefCB;
+
/**
* If this flag is set in ff_refstruct_alloc_ext_c(), the object will not
* be initially zeroed.
*/
#define FF_REFSTRUCT_FLAG_NO_ZEROING (1 << 0)
+/**
+ * This flag being set indicates that the free_cb union is in
+ * the unref_ext-state.
+ * In this case unreferencing the object has to be done
+ * via ff_refstruct_unref_ext() instead of ff_refstruct_unref().
+ * Using the latter is forbidden and leads to undefined behaviour.
+ *
+ * The free_ext-callback will be called when the refcount reaches zero
+ * with the opaque given to ff_refstruct_unref_ext() passed along as
+ * the callback's dynamic_opaque parameter; the argument corresponding
+ * to the initial_opaque parameter will be the opaque provided to
+ * ff_refstruct_alloc_ext_c() and obj is the object to be unreferenced.
+ */
+#define FF_REFSTRUCT_FLAG_DYNAMIC_OPAQUE (1 << 1)
/**
* Allocate a refcounted object of usable size `size` managed via
@@ -76,17 +100,19 @@ typedef union {
* @param size Desired usable size of the returned object.
* @param flags A bitwise combination of FF_REFSTRUCT_FLAG_* flags.
* @param opaque A pointer that will be passed to the free_cb callback.
- * @param free_cb A callback for freeing this object's content
+ * @param free_cb Contains the callback for freeing this object's content
* when its reference count reaches zero;
* it must not free the object itself.
+ * The state of free_cb is indicated by the
+ * FF_REFSTRUCT_FLAG_DYNAMIC_OPAQUE flag.
* @return A pointer to an object of the desired size or NULL on failure.
*/
void *ff_refstruct_alloc_ext_c(size_t size, unsigned flags, FFRefStructOpaque opaque,
- void (*free_cb)(FFRefStructOpaque opaque, void *obj));
+ FFRefStructUnrefCB free_cb);
/**
* A wrapper around ff_refstruct_alloc_ext_c() for the common case
- * of a non-const qualified opaque.
+ * of a non-const qualified and non-dynamic opaque.
*
* @see ff_refstruct_alloc_ext_c()
*/
@@ -95,7 +121,7 @@ void *ff_refstruct_alloc_ext(size_t size, unsigned flags, void *opaque,
void (*free_cb)(FFRefStructOpaque opaque, void *obj))
{
return ff_refstruct_alloc_ext_c(size, flags, (FFRefStructOpaque){.nc = opaque},
- free_cb);
+ (FFRefStructUnrefCB){ .unref = free_cb });
}
/**
@@ -107,6 +133,10 @@ void *ff_refstruct_allocz(size_t size);
* Decrement the reference count of the underlying object and automatically
* free the object if there are no more references to it.
*
+ * This function must not be used if the object has been created
+ * with the dynamic opaque flags (FF_REFSTRUCT_FLAG_DYNAMIC_OPAQUE
+ * or FF_REFSTRUCT_POOL_FLAG_DYNAMIC_OPAQUE for objects from pools).
+ *
* `*objp == NULL` is legal and a no-op.
*
* @param objp Pointer to a pointer that is either NULL or points to an object
@@ -114,6 +144,32 @@ void *ff_refstruct_allocz(size_t size);
*/
void ff_refstruct_unref(void *objp);
+/**
+ * Decrement the reference count of the underlying object and automatically
+ * free the object if there are no more references to it.
+ *
+ * This function may only be used of the object has been created
+ * with the dynamic opaque flags (FF_REFSTRUCT_FLAG_DYNAMIC_OPAQUE
+ * or FF_REFSTRUCT_POOL_FLAG_DYNAMIC_OPAQUE for objects from pools).
+ *
+ * `*objp == NULL` is legal and a no-op.
+ *
+ * @param objp Pointer to a pointer that is either NULL or points to an object
+ * managed via this API. `*objp` is set to NULL on return.
+ */
+void ff_refstruct_unref_ext_c(FFRefStructOpaque opaque, void *objp);
+/**
+ * A wrapper around ff_refstruct_unref_ext_c() for the common case
+ * of a non-const qualified dynamic opaque.
+ *
+ * @see ff_refstruct_alloc_ext_c()
+ */
+static inline
+void ff_refstruct_unref_ext(void *opaque, void *objp)
+{
+ ff_refstruct_unref_ext_c((FFRefStructOpaque){ .nc = opaque }, objp);
+}
+
/**
* Create a new reference to an object managed via this API,
* i.e. increment the reference count of the underlying object
@@ -215,6 +271,16 @@ typedef struct FFRefStructPool FFRefStructPool;
* flag had been provided.
*/
#define FF_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME (1 << 18)
+/**
+ * This flag being set indicates that the reset_cb union is in
+ * the unref_ext-state. The semantics of FF_REFSTRUCT_FLAG_DYNAMIC_OPAQUE
+ * apply with the opaque given to ff_refstruct_alloc_ext_c()
+ * corresponding to the opaque given to ff_refstruct_pool_alloc_ext_c().
+ *
+ * This flag is incompatible with FF_REFSTRUCT_POOL_FLAG_RESET_ON_INIT_ERROR.
+ * Giving both to a pool allocation function leads to undefined behaviour.
+ */
+#define FF_REFSTRUCT_POOL_FLAG_DYNAMIC_OPAQUE FF_REFSTRUCT_FLAG_DYNAMIC_OPAQUE
/**
* Equivalent to ff_refstruct_pool_alloc(size, flags, NULL, NULL, NULL, NULL, NULL)
@@ -240,13 +306,13 @@ FFRefStructPool *ff_refstruct_pool_alloc(size_t size, unsigned flags);
FFRefStructPool *ff_refstruct_pool_alloc_ext_c(size_t size, unsigned flags,
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));
/**
* A wrapper around ff_refstruct_pool_alloc_ext_c() for the common case
- * of a non-const qualified opaque.
+ * of a non-const qualified and non-dynamic opaque.
*
* @see ff_refstruct_pool_alloc_ext_c()
*/
@@ -259,7 +325,8 @@ FFRefStructPool *ff_refstruct_pool_alloc_ext(size_t size, unsigned flags,
void (*free_cb)(FFRefStructOpaque opaque))
{
return ff_refstruct_pool_alloc_ext_c(size, flags, (FFRefStructOpaque){.nc = opaque},
- init_cb, reset_cb, free_entry_cb, free_cb);
+ init_cb, (FFRefStructUnrefCB){ .unref = reset_cb },
+ free_entry_cb, free_cb);
}
/**
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 27/42] avcodec/pthread_frame: Add new progress API
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (25 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 26/42] avcodec/refstruct: Allow to use a dynamic opaque Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-10-21 10:34 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 28/42] avcodec/mimic: Switch to ProgressFrames Andreas Rheinhardt
` (21 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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
structure whereas ThreadFrames share it in every instance.
This makes it possible for different threads to have different
opinions about ownership of a given ThreadFrame (this really
happens when decoding field-based H.264), but this is not possible
with ProgressFrames. Also ProgressFrames currently does not
support separate ownership for the fields of an AVFrame.
This could be added if the need arises.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/avcodec.c | 1 +
libavcodec/codec_internal.h | 4 +
libavcodec/decode.c | 118 ++++++++++++++++++++++++
libavcodec/internal.h | 2 +
libavcodec/progressframe.h | 134 ++++++++++++++++++++++++++++
libavcodec/progressframe_internal.h | 32 +++++++
libavcodec/pthread_frame.c | 43 +++++++++
libavcodec/tests/avcodec.c | 3 +-
8 files changed, 336 insertions(+), 1 deletion(-)
create mode 100644 libavcodec/progressframe.h
create mode 100644 libavcodec/progressframe_internal.h
diff --git a/libavcodec/avcodec.c b/libavcodec/avcodec.c
index 6365ab87a6..a6ddc1c4e9 100644
--- a/libavcodec/avcodec.c
+++ b/libavcodec/avcodec.c
@@ -460,6 +460,7 @@ av_cold int avcodec_close(AVCodecContext *avctx)
av_frame_free(&avci->recon_frame);
ff_refstruct_unref(&avci->pool);
+ ff_refstruct_pool_uninit(&avci->progress_frame_pool);
ff_hwaccel_uninit(avctx);
diff --git a/libavcodec/codec_internal.h b/libavcodec/codec_internal.h
index 130a7dc3cd..c03b64ceba 100644
--- a/libavcodec/codec_internal.h
+++ b/libavcodec/codec_internal.h
@@ -62,6 +62,10 @@
* Codec initializes slice-based threading with a main function
*/
#define FF_CODEC_CAP_SLICE_THREAD_HAS_MF (1 << 5)
+/**
+ * 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().
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 7abfe7f0ce..3f98eb0df4 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -46,6 +46,8 @@
#include "hwconfig.h"
#include "internal.h"
#include "packet_internal.h"
+#include "progressframe.h"
+#include "progressframe_internal.h"
#include "refstruct.h"
#include "thread.h"
@@ -1691,6 +1693,111 @@ int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
return ret;
}
+static void check_progress_consistency(const ProgressFrame *f)
+{
+ av_assert1(!!f->f == !!f->progress);
+ av_assert1(!f->progress || f->progress->f == f->f);
+}
+
+static int thread_progress_get(AVCodecContext *avctx, ProgressFrame *f)
+{
+ FFRefStructPool *pool = avctx->internal->progress_frame_pool;
+
+ av_assert1(!f->f && !f->progress);
+
+ f->progress = ff_refstruct_pool_get(pool);
+ if (!f->progress)
+ return AVERROR(ENOMEM);
+
+ if (avctx->active_thread_type & FF_THREAD_FRAME) {
+ f->progress->owner = avctx->internal->thread_ctx;
+ atomic_init(&f->progress->progress, -1);
+ } else
+ f->progress->owner = NULL;
+ f->f = f->progress->f;
+ return 0;
+}
+
+int ff_thread_progress_get_buffer(AVCodecContext *avctx, ProgressFrame *f, int flags)
+{
+ int ret;
+
+ ret = thread_progress_get(avctx, f);
+ if (ret < 0)
+ return ret;
+
+ ret = ff_thread_get_buffer(avctx, f->progress->f, flags);
+ if (ret < 0) {
+ f->f = NULL;
+ ff_refstruct_unref_ext(avctx, &f->progress);
+ return ret;
+ }
+ return 0;
+}
+
+void ff_thread_progress_ref(ProgressFrame *dst, const ProgressFrame *src)
+{
+ av_assert1(src->progress && src->f && src->f == src->progress->f);
+ av_assert1(!dst->f && !dst->progress);
+ dst->f = src->f;
+ dst->progress = ff_refstruct_ref(src->progress);
+}
+
+void ff_thread_progress_unref(AVCodecContext *avctx, ProgressFrame *f)
+{
+ check_progress_consistency(f);
+ f->f = NULL;
+ ff_refstruct_unref_ext(avctx, &f->progress);
+}
+
+void ff_thread_progress_replace(AVCodecContext *avctx,
+ ProgressFrame *dst, const ProgressFrame *src)
+{
+ if (dst == src)
+ return;
+ ff_thread_progress_unref(avctx, dst);
+ check_progress_consistency(src);
+ if (src->f)
+ ff_thread_progress_ref(dst, src);
+}
+
+#if !HAVE_THREADS
+void ff_thread_progress_report(ProgressFrame *f, int n)
+{
+}
+
+void ff_thread_progress_await(const ProgressFrame *f, int n)
+{
+}
+#endif /* !HAVE_THREADS */
+
+static int progress_frame_pool_init_cb(FFRefStructOpaque unused, void *obj)
+{
+ ProgressInternal *progress = obj;
+
+ progress->f = av_frame_alloc();
+ if (!progress->f)
+ return AVERROR(ENOMEM);
+ return 0;
+}
+
+static void progress_frame_pool_reset_cb(FFRefStructOpaque dynamic_opaque,
+ FFRefStructOpaque unused,
+ void *obj)
+{
+ AVCodecContext *avctx = dynamic_opaque.nc;
+ ProgressInternal *progress = obj;
+
+ ff_thread_release_buffer(avctx, progress->f);
+}
+
+static void progress_frame_pool_free_entry_cb(FFRefStructOpaque opaque, void *obj)
+{
+ ProgressInternal *progress = obj;
+
+ av_frame_free(&progress->f);
+}
+
int ff_decode_preinit(AVCodecContext *avctx)
{
AVCodecInternal *avci = avctx->internal;
@@ -1759,6 +1866,17 @@ int ff_decode_preinit(AVCodecContext *avctx)
if (!avci->in_pkt || !avci->last_pkt_props)
return AVERROR(ENOMEM);
+ if (ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_USES_PROGRESSFRAMES) {
+ avci->progress_frame_pool =
+ ff_refstruct_pool_alloc_ext_c(sizeof(ProgressInternal),
+ FF_REFSTRUCT_POOL_FLAG_DYNAMIC_OPAQUE,
+ (FFRefStructOpaque){ NULL },
+ progress_frame_pool_init_cb,
+ (FFRefStructUnrefCB){ .unref_ext = progress_frame_pool_reset_cb },
+ progress_frame_pool_free_entry_cb, NULL);
+ if (!avci->progress_frame_pool)
+ return AVERROR(ENOMEM);
+ }
ret = decode_bsfs_init(avctx);
if (ret < 0)
return ret;
diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index eb9e0d707c..04d5bbb6fc 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -64,6 +64,8 @@ typedef struct AVCodecInternal {
struct FramePool *pool;
+ struct FFRefStructPool *progress_frame_pool;
+
void *thread_ctx;
/**
diff --git a/libavcodec/progressframe.h b/libavcodec/progressframe.h
new file mode 100644
index 0000000000..bc1d8462fa
--- /dev/null
+++ b/libavcodec/progressframe.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2022 Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
+ *
+ * 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_PROGRESSFRAME_H
+#define AVCODEC_PROGRESSFRAME_H
+
+/**
+ * ProgressFrame is an API to easily share frames without an underlying
+ * av_frame_ref(). Its main usecase is in frame-threading scenarios,
+ * yet it could also be used for purely single-threaded decoders that
+ * want to keep multiple references to the same frame.
+ *
+ * The underlying principle behind the API is that all that is needed
+ * to share a frame is a reference count and a contract between all parties.
+ * The ProgressFrame provides the reference count and the frame is unreferenced
+ * via ff_thread_release_buffer() when the reference count reaches zero.
+ *
+ * In order to make this API also usable for frame-threaded decoders it also
+ * provides a way of exchanging simple information about the state of
+ * decoding the frame via ff_thread_progress_report() and
+ * ff_thread_progress_await().
+ *
+ * The typical contract for frame-threaded decoders is as follows:
+ * Thread A initializes a ProgressFrame via ff_thread_progress_get_buffer()
+ * (which already allocates the AVFrame's data buffers), calls
+ * ff_thread_finish_setup() and starts decoding the frame. Later threads
+ * receive a reference to this frame, which means they get a pointer
+ * to the AVFrame and the internal reference count gets incremented.
+ * Later threads whose frames use A's frame as reference as well as
+ * the thread that will eventually output A's frame will wait for
+ * progress on said frame reported by A. As soon as A has reported
+ * that it has finished decoding its frame, it must no longer modify it
+ * (neither its data nor its properties).
+ *
+ * Because creating a reference with this API does not involve reads
+ * from the actual AVFrame, the decoding thread may modify the properties
+ * (i.e. non-data fields) until it has indicated to be done with this
+ * frame. This is important for e.g. propagating decode_error_flags;
+ * it also allows to add side-data late.
+ */
+
+struct AVCodecContext;
+
+typedef struct ProgressFrame {
+ struct AVFrame *f;
+ struct ProgressInternal *progress;
+} ProgressFrame;
+
+/**
+ * Notify later decoding threads when part of their reference picture is ready.
+ * Call this when some part of the picture is finished decoding.
+ * Later calls with lower values of progress have no effect.
+ *
+ * @param f The picture being decoded.
+ * @param progress Value, in arbitrary units, of how much of the picture has decoded.
+ *
+ * @warning Calling this on a blank ProgressFrame causes undefined behaviour
+ */
+void ff_thread_progress_report(ProgressFrame *f, int progress);
+
+/**
+ * Wait for earlier decoding threads to finish reference pictures.
+ * Call this before accessing some part of a picture, with a given
+ * value for progress, and it will return after the responsible decoding
+ * thread calls ff_thread_progress_report() with the same or
+ * higher value for progress.
+ *
+ * @param f The picture being referenced.
+ * @param progress Value, in arbitrary units, to wait for.
+ *
+ * @warning Calling this on a blank ProgressFrame causes undefined behaviour
+ */
+void ff_thread_progress_await(const ProgressFrame *f, int progress);
+
+/**
+ * This function sets up the ProgressFrame, i.e. gets ProgressFrame.f
+ * and also calls ff_thread_get_buffer() on the frame.
+ *
+ * @note: This must only be called by codecs with the
+ * FF_CODEC_CAP_USES_PROGRESSFRAMES internal cap.
+ */
+int ff_thread_progress_get_buffer(struct AVCodecContext *avctx,
+ ProgressFrame *f, int flags);
+
+/**
+ * Give up a reference to the underlying frame contained in a ProgressFrame
+ * and reset the ProgressFrame, setting all pointers to NULL.
+ *
+ * @note: This implies that when using this API the check for whether
+ * a frame exists is by checking ProgressFrame.f and not
+ * ProgressFrame.f->data[0] or ProgressFrame.f->buf[0].
+ */
+void ff_thread_progress_unref(struct AVCodecContext *avctx, ProgressFrame *f);
+
+/**
+ * Set dst.f to src.f and make dst a co-owner of src.f.
+ * dst can then be used to wait on progress of the underlying frame.
+ *
+ * @note: There is no underlying av_frame_ref() here. dst.f and src.f
+ * really point to the same AVFrame. Typically this means that
+ * the decoding thread is allowed to set all the properties of
+ * the AVFrame until it has indicated to have finished decoding.
+ * Afterwards later threads may read all of these fields.
+ * Access to the frame's data is governed by
+ * ff_thread_progress_report/await().
+ */
+void ff_thread_progress_ref(ProgressFrame *dst, const ProgressFrame *src);
+
+/**
+ * Do nothing if dst and src already refer to the same AVFrame;
+ * otherwise unreference dst and if src is not blank, put a reference
+ * to src's AVFrame in its place (in case src is not blank).
+ */
+void ff_thread_progress_replace(struct AVCodecContext *avctx,
+ ProgressFrame *dst, const ProgressFrame *src);
+
+#endif /* AVCODEC_PROGRESSFRAME_H */
diff --git a/libavcodec/progressframe_internal.h b/libavcodec/progressframe_internal.h
new file mode 100644
index 0000000000..1101207106
--- /dev/null
+++ b/libavcodec/progressframe_internal.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2022 Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
+ *
+ * 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_PROGRESSFRAME_INTERNAL_H
+#define AVCODEC_PROGRESSFRAME_INTERNAL_H
+
+#include <stdatomic.h>
+
+typedef struct ProgressInternal {
+ atomic_int progress;
+ struct PerThreadContext *owner; ///< != NULL iff frame-threading is in use
+ struct AVFrame *f;
+} ProgressInternal;
+
+#endif /* AVCODEC_PROGRESSFRAME_INTERNAL_H */
diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index 282f3fad58..9e827f0606 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -34,6 +34,8 @@
#include "hwaccel_internal.h"
#include "hwconfig.h"
#include "internal.h"
+#include "progressframe.h"
+#include "progressframe_internal.h"
#include "pthread_internal.h"
#include "refstruct.h"
#include "thread.h"
@@ -795,6 +797,7 @@ static av_cold int init_thread(PerThreadContext *p, int *threads_to_free,
if (!copy->internal)
return AVERROR(ENOMEM);
copy->internal->thread_ctx = p;
+ copy->internal->progress_frame_pool = avctx->internal->progress_frame_pool;
copy->delay = avctx->delay;
@@ -1026,3 +1029,43 @@ void ff_thread_release_ext_buffer(AVCodecContext *avctx, ThreadFrame *f)
f->owner[0] = f->owner[1] = NULL;
ff_thread_release_buffer(avctx, f->f);
}
+
+void ff_thread_progress_report(ProgressFrame *f, int n)
+{
+ ProgressInternal *pro = f->progress;
+ PerThreadContext *p = pro->owner;
+
+ if (!p ||
+ atomic_load_explicit(&pro->progress, memory_order_relaxed) >= n)
+ return;
+
+ if (atomic_load_explicit(&p->debug_threads, memory_order_relaxed))
+ av_log(p->avctx, AV_LOG_DEBUG,
+ "%p finished %d\n", (void*)pro, n);
+
+ pthread_mutex_lock(&p->progress_mutex);
+
+ atomic_store_explicit(&pro->progress, n, memory_order_release);
+
+ pthread_cond_broadcast(&p->progress_cond);
+ pthread_mutex_unlock(&p->progress_mutex);
+}
+
+void ff_thread_progress_await(const ProgressFrame *f, int n)
+{
+ ProgressInternal *pro = f->progress;
+ PerThreadContext *p = pro->owner;
+
+ if (!p ||
+ atomic_load_explicit(&pro->progress, memory_order_acquire) >= n)
+ return;
+
+ if (atomic_load_explicit(&p->debug_threads, memory_order_relaxed))
+ av_log(p->avctx, AV_LOG_DEBUG,
+ "thread awaiting %d from %p\n", n, (void*)pro);
+
+ pthread_mutex_lock(&p->progress_mutex);
+ while (atomic_load_explicit(&pro->progress, memory_order_relaxed) < n)
+ pthread_cond_wait(&p->progress_cond, &p->progress_mutex);
+ pthread_mutex_unlock(&p->progress_mutex);
+}
diff --git a/libavcodec/tests/avcodec.c b/libavcodec/tests/avcodec.c
index 08ca507bf0..f6e394c78d 100644
--- a/libavcodec/tests/avcodec.c
+++ b/libavcodec/tests/avcodec.c
@@ -145,7 +145,8 @@ int main(void){
FF_CODEC_CAP_SETS_PKT_DTS |
FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM |
FF_CODEC_CAP_EXPORTS_CROPPING |
- FF_CODEC_CAP_SETS_FRAME_PROPS) ||
+ FF_CODEC_CAP_SETS_FRAME_PROPS |
+ FF_CODEC_CAP_USES_PROGRESSFRAMES) ||
codec->capabilities & (AV_CODEC_CAP_AVOID_PROBING |
AV_CODEC_CAP_CHANNEL_CONF |
AV_CODEC_CAP_DRAW_HORIZ_BAND))
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 27/42] avcodec/pthread_frame: Add new progress API
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 27/42] avcodec/pthread_frame: Add new progress API Andreas Rheinhardt
@ 2023-10-21 10:34 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-10-21 10:34 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:19)
> 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.
Do we really need an owner? I never liked this notion for ThreadFrames.
Might as well make the mutex and the cond per-ProgressFrame and drop the
debug logs - I never found them useful. Then this API could be entirely
independent of the frame threading implementation and could potentially
be used elsewhere.
> +#ifndef AVCODEC_PROGRESSFRAME_H
> +#define AVCODEC_PROGRESSFRAME_H
> +
> +/**
> + * ProgressFrame is an API to easily share frames without an underlying
> + * av_frame_ref(). Its main usecase is in frame-threading scenarios,
> + * yet it could also be used for purely single-threaded decoders that
> + * want to keep multiple references to the same frame.
nit: the name is not ideal for these other use cases. You could call it
something like SharedFrame instead.
> +typedef struct ProgressFrame {
> + struct AVFrame *f;
> + struct ProgressInternal *progress;
> +} ProgressFrame;
> +
> +/**
> + * Notify later decoding threads when part of their reference picture is ready.
s/picture/frame/ everywhere
"picture" has a special meaning for interlaced video and might confuse
readers.
> diff --git a/libavcodec/progressframe_internal.h b/libavcodec/progressframe_internal.h
> new file mode 100644
> index 0000000000..1101207106
> --- /dev/null
> +++ b/libavcodec/progressframe_internal.h
> @@ -0,0 +1,32 @@
> +/*
> + * Copyright (c) 2022 Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
> + *
> + * 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_PROGRESSFRAME_INTERNAL_H
> +#define AVCODEC_PROGRESSFRAME_INTERNAL_H
Mention who this header is for, so clue-free decoder writers don't
start including it.
> diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
> index 282f3fad58..9e827f0606 100644
> --- a/libavcodec/pthread_frame.c
> +++ b/libavcodec/pthread_frame.c
> @@ -34,6 +34,8 @@
> #include "hwaccel_internal.h"
> #include "hwconfig.h"
> #include "internal.h"
> +#include "progressframe.h"
> +#include "progressframe_internal.h"
> #include "pthread_internal.h"
> #include "refstruct.h"
> #include "thread.h"
> @@ -795,6 +797,7 @@ static av_cold int init_thread(PerThreadContext *p, int *threads_to_free,
> if (!copy->internal)
> return AVERROR(ENOMEM);
> copy->internal->thread_ctx = p;
> + copy->internal->progress_frame_pool = avctx->internal->progress_frame_pool;
It feels cleaner to me to make each of those a separate reference,
especially since it's pretty much free.
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 28/42] avcodec/mimic: Switch to ProgressFrames
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (26 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 27/42] avcodec/pthread_frame: Add new progress API Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-10-21 10:38 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 29/42] avcodec/vp3: " Andreas Rheinhardt
` (20 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
Avoids implicit av_frame_ref() and therefore allocations
and error checks.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
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(&ctx->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, &ctx->frames[i]);
- av_frame_free(&ctx->frames[i].f);
- }
+ for (int i = 0; i < FF_ARRAY_ELEMS(ctx->frames); i++)
+ ff_thread_progress_unref(avctx, &ctx->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(&ctx->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(&init_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, &dst->frames[i]);
- if (i != src->next_cur_index && src->frames[i].f->data[0]) {
- ret = ff_thread_ref_frame(&dst->frames[i], &src->frames[i]);
- if (ret < 0)
- return ret;
- }
+ for (int i = 0; i < FF_ARRAY_ELEMS(dst->frames); i++) {
+ ff_thread_progress_unref(avctx, &dst->frames[i]);
+ if (i != src->next_cur_index && src->frames[i].f)
+ ff_thread_progress_ref(&dst->frames[i], &src->frames[i]);
}
return 0;
@@ -291,11 +276,10 @@ static int decode(MimicContext *ctx, int quality, int num_coeffs,
} else {
unsigned int backref = get_bits(&ctx->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(&ctx->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(&ctx->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(&ctx->frames[ctx->prev_index],
- cur_row, 0);
+ ff_thread_progress_await(&ctx->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(&ctx->frames[ctx->cur_index],
- cur_row++, 0);
+ ff_thread_progress_report(&ctx->frames[ctx->cur_index], cur_row++);
}
}
@@ -390,17 +372,17 @@ static int mimic_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
return AVERROR_PATCHWELCOME;
}
- if (is_pframe && !ctx->frames[ctx->prev_index].f->data[0]) {
+ if (is_pframe && !ctx->frames[ctx->prev_index].f) {
av_log(avctx, AV_LOG_ERROR, "decoding must start with keyframe\n");
return AVERROR_INVALIDDATA;
}
- ff_thread_release_ext_buffer(avctx, &ctx->frames[ctx->cur_index]);
+ ff_thread_progress_unref(avctx, &ctx->frames[ctx->cur_index]);
+ if ((res = ff_thread_progress_get_buffer(avctx, &ctx->frames[ctx->cur_index],
+ AV_GET_BUFFER_FLAG_REF)) < 0)
+ return res;
ctx->frames[ctx->cur_index].f->pict_type = is_pframe ? AV_PICTURE_TYPE_P :
AV_PICTURE_TYPE_I;
- if ((res = ff_thread_get_ext_buffer(avctx, &ctx->frames[ctx->cur_index],
- AV_GET_BUFFER_FLAG_REF)) < 0)
- return res;
ctx->next_prev_index = ctx->cur_index;
ctx->next_cur_index = (ctx->cur_index - 1) & 15;
@@ -417,10 +399,10 @@ static int mimic_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
init_get_bits(&ctx->gb, ctx->swap_buf, swap_buf_size << 3);
res = decode(ctx, quality, num_coeffs, !is_pframe);
- ff_thread_report_progress(&ctx->frames[ctx->cur_index], INT_MAX, 0);
+ ff_thread_progress_report(&ctx->frames[ctx->cur_index], INT_MAX);
if (res < 0) {
if (!(avctx->active_thread_type & FF_THREAD_FRAME))
- ff_thread_release_ext_buffer(avctx, &ctx->frames[ctx->cur_index]);
+ ff_thread_progress_unref(avctx, &ctx->frames[ctx->cur_index]);
return res;
}
@@ -447,6 +429,6 @@ const FFCodec ff_mimic_decoder = {
FF_CODEC_DECODE_CB(mimic_decode_frame),
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
UPDATE_THREAD_CONTEXT(mimic_decode_update_thread_context),
- .caps_internal = FF_CODEC_CAP_ALLOCATE_PROGRESS |
+ .caps_internal = FF_CODEC_CAP_USES_PROGRESSFRAMES |
FF_CODEC_CAP_INIT_CLEANUP,
};
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 29/42] avcodec/vp3: Switch to ProgressFrames
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (27 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 28/42] avcodec/mimic: Switch to ProgressFrames Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-10-21 10:48 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 30/42] avcodec/vp9: " Andreas Rheinhardt
` (19 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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, &s->golden_frame);
- if (s->last_frame.f)
- ff_thread_release_ext_buffer(avctx, &s->last_frame);
- if (s->current_frame.f)
- ff_thread_release_ext_buffer(avctx, &s->current_frame);
+ ff_thread_progress_unref(avctx, &s->golden_frame);
+ ff_thread_progress_unref(avctx, &s->last_frame);
+ ff_thread_progress_unref(avctx, &s->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(&s->current_frame.f);
- av_frame_free(&s->last_frame.f);
- av_frame_free(&s->golden_frame.f);
for (int i = 0; i < FF_ARRAY_ELEMS(s->coeff_vlc); i++)
ff_vlc_free(&s->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(&s->current_frame,
+ ff_thread_progress_report(&s->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 AVERROR(ENOMEM);
-
- return 0;
-}
-
static av_cold int vp3_decode_init(AVCodecContext *avctx)
{
Vp3DecodeContext *s = avctx->priv_data;
@@ -2322,10 +2303,6 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx)
int c_height;
int y_fragment_count, c_fragment_count;
- ret = init_frames(s);
- if (ret < 0)
- return ret;
-
if (avctx->codec_tag == MKTAG('V', 'P', '4', '0')) {
s->version = 3;
#if !CONFIG_VP4_DECODER
@@ -2493,59 +2470,43 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx)
}
/// Release and shuffle frames after decode finishes
-static int update_frames(AVCodecContext *avctx)
+static void update_frames(AVCodecContext *avctx)
{
Vp3DecodeContext *s = avctx->priv_data;
- int ret = 0;
- if (s->keyframe) {
- ff_thread_release_ext_buffer(avctx, &s->golden_frame);
- ret = ff_thread_ref_frame(&s->golden_frame, &s->current_frame);
- }
- /* shuffle frames */
- ff_thread_release_ext_buffer(avctx, &s->last_frame);
- FFSWAP(ThreadFrame, s->last_frame, s->current_frame);
+ if (s->keyframe)
+ ff_thread_progress_replace(avctx, &s->golden_frame, &s->current_frame);
- return ret;
+ /* shuffle frames */
+ ff_thread_progress_unref(avctx, &s->last_frame);
+ FFSWAP(ProgressFrame, s->last_frame, s->current_frame);
}
#if HAVE_THREADS
-static int ref_frame(Vp3DecodeContext *s, ThreadFrame *dst, const ThreadFrame *src)
-{
- ff_thread_release_ext_buffer(s->avctx, dst);
- if (src->f->data[0])
- return ff_thread_ref_frame(dst, src);
- return 0;
-}
-
-static int ref_frames(Vp3DecodeContext *dst, const Vp3DecodeContext *src)
+static void ref_frames(AVCodecContext *avctx,
+ Vp3DecodeContext *dst, const Vp3DecodeContext *src)
{
- int ret;
- if ((ret = ref_frame(dst, &dst->current_frame, &src->current_frame)) < 0 ||
- (ret = ref_frame(dst, &dst->golden_frame, &src->golden_frame)) < 0 ||
- (ret = ref_frame(dst, &dst->last_frame, &src->last_frame)) < 0)
- return ret;
- return 0;
+ ff_thread_progress_replace(avctx, &dst->current_frame, &src->current_frame);
+ ff_thread_progress_replace(avctx, &dst->golden_frame, &src->golden_frame);
+ ff_thread_progress_replace(avctx, &dst->last_frame, &src->last_frame);
}
static int vp3_update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
{
Vp3DecodeContext *s = dst->priv_data;
const Vp3DecodeContext *s1 = src->priv_data;
- int qps_changed = 0, err;
+ int qps_changed = 0;
- if (!s1->current_frame.f->data[0] ||
+ if (s != s1) {
+ // copy previous frame data
+ ref_frames(dst, s, s1);
+ }
+ if (!s1->current_frame.f ||
s->width != s1->width || s->height != s1->height) {
- if (s != s1)
- ref_frames(s, s1);
return -1;
}
if (s != s1) {
- // copy previous frame data
- if ((err = ref_frames(s, s1)) < 0)
- return err;
-
s->keyframe = s1->keyframe;
// copy qscale data if necessary
@@ -2567,7 +2528,8 @@ static int vp3_update_thread_context(AVCodecContext *dst, const AVCodecContext *
}
}
- return update_frames(dst);
+ update_frames(dst);
+ return 0;
}
#endif
@@ -2658,15 +2620,18 @@ static int vp3_decode_frame(AVCodecContext *avctx, AVFrame *frame,
if (avctx->skip_frame >= AVDISCARD_NONKEY && !s->keyframe)
return buf_size;
+ if ((ret = ff_thread_progress_get_buffer(avctx, &s->current_frame,
+ AV_GET_BUFFER_FLAG_REF)) < 0) {
+ // Don't goto error here, as one can't report progress on or
+ // unref a non-existent frame.
+ return ret;
+ }
s->current_frame.f->pict_type = s->keyframe ? AV_PICTURE_TYPE_I
: AV_PICTURE_TYPE_P;
if (s->keyframe)
s->current_frame.f->flags |= AV_FRAME_FLAG_KEY;
else
s->current_frame.f->flags &= ~AV_FRAME_FLAG_KEY;
- if ((ret = ff_thread_get_ext_buffer(avctx, &s->current_frame,
- AV_GET_BUFFER_FLAG_REF)) < 0)
- goto error;
if (!s->edge_emu_buffer) {
s->edge_emu_buffer = av_malloc(9 * FFABS(s->current_frame.f->linesize[0]));
@@ -2724,19 +2689,16 @@ static int vp3_decode_frame(AVCodecContext *avctx, AVFrame *frame,
#endif
}
} else {
- if (!s->golden_frame.f->data[0]) {
+ if (!s->golden_frame.f) {
av_log(s->avctx, AV_LOG_WARNING,
"vp3: first frame not a keyframe\n");
- s->golden_frame.f->pict_type = AV_PICTURE_TYPE_I;
- if ((ret = ff_thread_get_ext_buffer(avctx, &s->golden_frame,
- AV_GET_BUFFER_FLAG_REF)) < 0)
+ if ((ret = ff_thread_progress_get_buffer(avctx, &s->golden_frame,
+ AV_GET_BUFFER_FLAG_REF)) < 0)
goto error;
- ff_thread_release_ext_buffer(avctx, &s->last_frame);
- if ((ret = ff_thread_ref_frame(&s->last_frame,
- &s->golden_frame)) < 0)
- goto error;
- ff_thread_report_progress(&s->last_frame, INT_MAX, 0);
+ s->golden_frame.f->pict_type = AV_PICTURE_TYPE_I;
+ ff_thread_progress_replace(avctx, &s->last_frame, &s->golden_frame);
+ ff_thread_progress_report(&s->golden_frame, INT_MAX);
}
}
ff_thread_finish_setup(avctx);
@@ -2814,16 +2776,13 @@ static int vp3_decode_frame(AVCodecContext *avctx, AVFrame *frame,
*got_frame = 1;
- if (!HAVE_THREADS || !(s->avctx->active_thread_type & FF_THREAD_FRAME)) {
- ret = update_frames(avctx);
- if (ret < 0)
- return ret;
- }
+ if (!HAVE_THREADS || !(s->avctx->active_thread_type & FF_THREAD_FRAME))
+ update_frames(avctx);
return buf_size;
error:
- ff_thread_report_progress(&s->current_frame, INT_MAX, 0);
+ ff_thread_progress_report(&s->current_frame, INT_MAX);
if (!HAVE_THREADS || !(s->avctx->active_thread_type & FF_THREAD_FRAME))
av_frame_unref(s->current_frame.f);
@@ -3173,7 +3132,8 @@ const FFCodec ff_theora_decoder = {
.flush = vp3_decode_flush,
UPDATE_THREAD_CONTEXT(vp3_update_thread_context),
.caps_internal = FF_CODEC_CAP_INIT_CLEANUP |
- FF_CODEC_CAP_EXPORTS_CROPPING | FF_CODEC_CAP_ALLOCATE_PROGRESS,
+ FF_CODEC_CAP_EXPORTS_CROPPING |
+ FF_CODEC_CAP_USES_PROGRESSFRAMES,
};
#endif
@@ -3191,7 +3151,7 @@ const FFCodec ff_vp3_decoder = {
.flush = vp3_decode_flush,
UPDATE_THREAD_CONTEXT(vp3_update_thread_context),
.caps_internal = FF_CODEC_CAP_INIT_CLEANUP |
- FF_CODEC_CAP_ALLOCATE_PROGRESS,
+ FF_CODEC_CAP_USES_PROGRESSFRAMES,
};
#if CONFIG_VP4_DECODER
@@ -3209,6 +3169,6 @@ const FFCodec ff_vp4_decoder = {
.flush = vp3_decode_flush,
UPDATE_THREAD_CONTEXT(vp3_update_thread_context),
.caps_internal = FF_CODEC_CAP_INIT_CLEANUP |
- FF_CODEC_CAP_ALLOCATE_PROGRESS,
+ FF_CODEC_CAP_USES_PROGRESSFRAMES,
};
#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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 29/42] avcodec/vp3: Switch to ProgressFrames
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 29/42] avcodec/vp3: " Andreas Rheinhardt
@ 2023-10-21 10:48 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-10-21 10:48 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:21)
> 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 <andreas.rheinhardt@outlook.com>
> ---
> libavcodec/vp3.c | 148 +++++++++++++++++------------------------------
> 1 file changed, 54 insertions(+), 94 deletions(-)
Looks ok.
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 30/42] avcodec/vp9: Switch to ProgressFrames
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (28 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 29/42] avcodec/vp3: " Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-10-21 11:04 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 31/42] avcodec/vp9: Fix race when attaching side-data for show-existing frame Andreas Rheinhardt
` (18 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
Compare this with Anton's earlier patch [1]
https://patchwork.ffmpeg.org/project/ffmpeg/patch/20220315104932.25496-2-anton@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(&pp->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(&pp->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, &f->tf);
+ ff_thread_progress_unref(avctx, &f->tf);
ff_refstruct_unref(&f->extradata);
ff_refstruct_unref(&f->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, &f->tf, AV_GET_BUFFER_FLAG_REF);
+ ret = ff_thread_progress_get_buffer(avctx, &f->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(&dst->tf, &src->tf);
- if (ret < 0)
- return ret;
+ ff_thread_progress_ref(&dst->tf, &src->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(&dst->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(&s->gb) && !s->s.h.errorres;
s->s.h.refidx[2] = get_bits(&s->gb, 3);
s->s.h.signbias[2] = get_bits1(&s->gb) && !s->s.h.errorres;
- if (!s->s.refs[s->s.h.refidx[0]].f->buf[0] ||
- !s->s.refs[s->s.h.refidx[1]].f->buf[0] ||
- !s->s.refs[s->s.h.refidx[2]].f->buf[0]) {
+ if (!s->s.refs[s->s.h.refidx[0]].f ||
+ !s->s.refs[s->s.h.refidx[1]].f ||
+ !s->s.refs[s->s.h.refidx[2]].f) {
av_log(avctx, AV_LOG_ERROR, "Not all references are available\n");
return AVERROR_INVALIDDATA;
}
@@ -606,7 +607,8 @@ static int decode_frame_header(AVCodecContext *avctx,
// Note that in this code, "CUR_FRAME" is actually before we
// have formally allocated a frame, and thus actually represents
// the _last_ frame
- s->s.h.use_last_frame_mvs &= s->s.frames[CUR_FRAME].tf.f->width == w &&
+ s->s.h.use_last_frame_mvs &= s->s.frames[CUR_FRAME].tf.f &&
+ s->s.frames[CUR_FRAME].tf.f->width == w &&
s->s.frames[CUR_FRAME].tf.f->height == h;
if (get_bits1(&s->gb)) // display size
skip_bits(&s->gb, 32);
@@ -1235,16 +1237,12 @@ static av_cold int vp9_decode_free(AVCodecContext *avctx)
VP9Context *s = avctx->priv_data;
int i;
- for (i = 0; i < 3; i++) {
+ for (int i = 0; i < 3; i++)
vp9_frame_unref(avctx, &s->s.frames[i]);
- av_frame_free(&s->s.frames[i].tf.f);
- }
ff_refstruct_pool_uninit(&s->frame_extradata_pool);
for (i = 0; i < 8; i++) {
- ff_thread_release_ext_buffer(avctx, &s->s.refs[i]);
- av_frame_free(&s->s.refs[i].f);
- ff_thread_release_ext_buffer(avctx, &s->next_refs[i]);
- av_frame_free(&s->next_refs[i].f);
+ ff_thread_progress_unref(avctx, &s->s.refs[i]);
+ ff_thread_progress_unref(avctx, &s->next_refs[i]);
}
free_buffers(s);
@@ -1379,7 +1377,7 @@ static int decode_tiles(AVCodecContext *avctx,
// FIXME maybe we can make this more finegrained by running the
// loopfilter per-block instead of after each sbrow
// In fact that would also make intra pred left preparation easier?
- ff_thread_report_progress(&s->s.frames[CUR_FRAME].tf, row >> 3, 0);
+ ff_thread_progress_report(&s->s.frames[CUR_FRAME].tf, row >> 3);
}
}
return 0;
@@ -1556,12 +1554,13 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame,
int ret, i, j, ref;
int retain_segmap_ref = s->s.frames[REF_FRAME_SEGMAP].segmentation_map &&
(!s->s.h.segmentation.enabled || !s->s.h.segmentation.update_map);
+ const VP9Frame *src;
AVFrame *f;
if ((ret = decode_frame_header(avctx, data, size, &ref)) < 0) {
return ret;
} else if (ret == 0) {
- if (!s->s.refs[ref].f->buf[0]) {
+ if (!s->s.refs[ref].f) {
av_log(avctx, AV_LOG_ERROR, "Requested reference %d not available\n", ref);
return AVERROR_INVALIDDATA;
}
@@ -1569,33 +1568,19 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame,
return ret;
frame->pts = pkt->pts;
frame->pkt_dts = pkt->dts;
- for (i = 0; i < 8; i++) {
- if (s->next_refs[i].f->buf[0])
- ff_thread_release_ext_buffer(avctx, &s->next_refs[i]);
- if (s->s.refs[i].f->buf[0] &&
- (ret = ff_thread_ref_frame(&s->next_refs[i], &s->s.refs[i])) < 0)
- return ret;
- }
+ for (int i = 0; i < 8; i++)
+ ff_thread_progress_replace(avctx, &s->next_refs[i], &s->s.refs[i]);
*got_frame = 1;
return pkt->size;
}
data += ret;
size -= ret;
- if (!retain_segmap_ref || s->s.h.keyframe || s->s.h.intraonly) {
- if (s->s.frames[REF_FRAME_SEGMAP].tf.f->buf[0])
- vp9_frame_unref(avctx, &s->s.frames[REF_FRAME_SEGMAP]);
- if (!s->s.h.keyframe && !s->s.h.intraonly && !s->s.h.errorres && s->s.frames[CUR_FRAME].tf.f->buf[0] &&
- (ret = vp9_frame_ref(avctx, &s->s.frames[REF_FRAME_SEGMAP], &s->s.frames[CUR_FRAME])) < 0)
- return ret;
- }
- if (s->s.frames[REF_FRAME_MVPAIR].tf.f->buf[0])
- vp9_frame_unref(avctx, &s->s.frames[REF_FRAME_MVPAIR]);
- if (!s->s.h.intraonly && !s->s.h.keyframe && !s->s.h.errorres && s->s.frames[CUR_FRAME].tf.f->buf[0] &&
- (ret = vp9_frame_ref(avctx, &s->s.frames[REF_FRAME_MVPAIR], &s->s.frames[CUR_FRAME])) < 0)
- return ret;
- if (s->s.frames[CUR_FRAME].tf.f->buf[0])
- vp9_frame_unref(avctx, &s->s.frames[CUR_FRAME]);
+ src = !s->s.h.keyframe && !s->s.h.intraonly && !s->s.h.errorres ? &s->s.frames[CUR_FRAME] : NULL;
+ if (!retain_segmap_ref || s->s.h.keyframe || s->s.h.intraonly)
+ vp9_frame_replace(avctx, &s->s.frames[REF_FRAME_SEGMAP], src);
+ vp9_frame_replace(avctx, &s->s.frames[REF_FRAME_MVPAIR], src);
+ vp9_frame_unref(avctx, &s->s.frames[CUR_FRAME]);
if ((ret = vp9_frame_alloc(avctx, &s->s.frames[CUR_FRAME])) < 0)
return ret;
f = s->s.frames[CUR_FRAME].tf.f;
@@ -1605,7 +1590,8 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame,
f->flags &= ~AV_FRAME_FLAG_KEY;
f->pict_type = (s->s.h.keyframe || s->s.h.intraonly) ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
- if (s->s.frames[REF_FRAME_SEGMAP].tf.f->buf[0] &&
+ // Inexistent frames have the implicit dimension 0x0 != CUR_FRAME
+ if (!s->s.frames[REF_FRAME_MVPAIR].tf.f ||
(s->s.frames[REF_FRAME_MVPAIR].tf.f->width != s->s.frames[CUR_FRAME].tf.f->width ||
s->s.frames[REF_FRAME_MVPAIR].tf.f->height != s->s.frames[CUR_FRAME].tf.f->height)) {
vp9_frame_unref(avctx, &s->s.frames[REF_FRAME_SEGMAP]);
@@ -1613,15 +1599,9 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame,
// ref frame setup
for (i = 0; i < 8; i++) {
- if (s->next_refs[i].f->buf[0])
- ff_thread_release_ext_buffer(avctx, &s->next_refs[i]);
- if (s->s.h.refreshrefmask & (1 << i)) {
- ret = ff_thread_ref_frame(&s->next_refs[i], &s->s.frames[CUR_FRAME].tf);
- } else if (s->s.refs[i].f->buf[0]) {
- ret = ff_thread_ref_frame(&s->next_refs[i], &s->s.refs[i]);
- }
- if (ret < 0)
- return ret;
+ ff_thread_progress_replace(avctx, &s->next_refs[i],
+ s->s.h.refreshrefmask & (1 << i) ?
+ &s->s.frames[CUR_FRAME].tf : &s->s.refs[i]);
}
if (avctx->hwaccel) {
@@ -1731,7 +1711,7 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame,
{
ret = decode_tiles(avctx, data, size);
if (ret < 0) {
- ff_thread_report_progress(&s->s.frames[CUR_FRAME].tf, INT_MAX, 0);
+ ff_thread_progress_report(&s->s.frames[CUR_FRAME].tf, INT_MAX);
return ret;
}
}
@@ -1747,7 +1727,7 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame,
ff_thread_finish_setup(avctx);
}
} while (s->pass++ == 1);
- ff_thread_report_progress(&s->s.frames[CUR_FRAME].tf, INT_MAX, 0);
+ ff_thread_progress_report(&s->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");
@@ -1762,13 +1742,8 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame,
finish:
// ref frame setup
- for (i = 0; i < 8; i++) {
- if (s->s.refs[i].f->buf[0])
- ff_thread_release_ext_buffer(avctx, &s->s.refs[i]);
- if (s->next_refs[i].f->buf[0] &&
- (ret = ff_thread_ref_frame(&s->s.refs[i], &s->next_refs[i])) < 0)
- return ret;
- }
+ for (int i = 0; i < 8; i++)
+ ff_thread_progress_replace(avctx, &s->s.refs[i], &s->next_refs[i]);
if (!s->s.h.invisible) {
if ((ret = av_frame_ref(frame, s->s.frames[CUR_FRAME].tf.f)) < 0)
@@ -1787,7 +1762,7 @@ static void vp9_decode_flush(AVCodecContext *avctx)
for (i = 0; i < 3; i++)
vp9_frame_unref(avctx, &s->s.frames[i]);
for (i = 0; i < 8; i++)
- ff_thread_release_ext_buffer(avctx, &s->s.refs[i]);
+ ff_thread_progress_unref(avctx, &s->s.refs[i]);
if (FF_HW_HAS_CB(avctx, flush))
FF_HW_SIMPLE_CALL(avctx, flush);
@@ -1809,42 +1784,18 @@ static av_cold int vp9_decode_init(AVCodecContext *avctx)
}
#endif
- for (int i = 0; i < 3; i++) {
- s->s.frames[i].tf.f = av_frame_alloc();
- if (!s->s.frames[i].tf.f)
- return AVERROR(ENOMEM);
- }
- for (int i = 0; i < 8; i++) {
- s->s.refs[i].f = av_frame_alloc();
- s->next_refs[i].f = av_frame_alloc();
- if (!s->s.refs[i].f || !s->next_refs[i].f)
- return AVERROR(ENOMEM);
- }
return 0;
}
#if HAVE_THREADS
static int vp9_decode_update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
{
- int i, ret;
VP9Context *s = dst->priv_data, *ssrc = src->priv_data;
- for (i = 0; i < 3; i++) {
- if (s->s.frames[i].tf.f->buf[0])
- vp9_frame_unref(dst, &s->s.frames[i]);
- if (ssrc->s.frames[i].tf.f->buf[0]) {
- if ((ret = vp9_frame_ref(dst, &s->s.frames[i], &ssrc->s.frames[i])) < 0)
- return ret;
- }
- }
- for (i = 0; i < 8; i++) {
- if (s->s.refs[i].f->buf[0])
- ff_thread_release_ext_buffer(dst, &s->s.refs[i]);
- if (ssrc->next_refs[i].f->buf[0]) {
- if ((ret = ff_thread_ref_frame(&s->s.refs[i], &ssrc->next_refs[i])) < 0)
- return ret;
- }
- }
+ for (int i = 0; i < 3; i++)
+ vp9_frame_replace(dst, &s->s.frames[i], &ssrc->s.frames[i]);
+ for (int i = 0; i < 8; i++)
+ ff_thread_progress_replace(dst, &s->s.refs[i], &ssrc->next_refs[i]);
ff_refstruct_replace(&s->frame_extradata_pool, ssrc->frame_extradata_pool);
s->frame_extradata_pool_size = ssrc->frame_extradata_pool_size;
@@ -1884,7 +1835,7 @@ const FFCodec ff_vp9_decoder = {
.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_SLICE_THREAD_HAS_MF |
- FF_CODEC_CAP_ALLOCATE_PROGRESS,
+ FF_CODEC_CAP_USES_PROGRESSFRAMES,
.flush = vp9_decode_flush,
UPDATE_THREAD_CONTEXT(vp9_decode_update_thread_context),
.p.profiles = NULL_IF_CONFIG_SMALL(ff_vp9_profiles),
diff --git a/libavcodec/vp9_mc_template.c b/libavcodec/vp9_mc_template.c
index e654c0e5ed..81e4ed59c7 100644
--- a/libavcodec/vp9_mc_template.c
+++ b/libavcodec/vp9_mc_template.c
@@ -36,7 +36,7 @@ static void FN(inter_pred)(VP9TileData *td)
const VP9Context *s = td->s;
VP9Block *b = td->b;
int row = td->row, col = td->col;
- const ThreadFrame *tref1 = &s->s.refs[s->s.h.refidx[b->ref[0]]], *tref2;
+ const ProgressFrame *tref1 = &s->s.refs[s->s.h.refidx[b->ref[0]]], *tref2;
const AVFrame *ref1 = tref1->f, *ref2;
int w1 = ref1->width, h1 = ref1->height, w2, h2;
ptrdiff_t ls_y = td->y_stride, ls_uv = td->uv_stride;
diff --git a/libavcodec/vp9block.c b/libavcodec/vp9block.c
index 5743f048cc..554b4caebb 100644
--- a/libavcodec/vp9block.c
+++ b/libavcodec/vp9block.c
@@ -22,8 +22,9 @@
*/
#include "libavutil/avassert.h"
+#include "libavutil/frame.h"
-#include "threadframe.h"
+#include "progressframe.h"
#include "vp89_rac.h"
#include "vp9.h"
#include "vp9data.h"
@@ -113,7 +114,7 @@ static void decode_mode(VP9TileData *td)
uint8_t *refsegmap = s->s.frames[REF_FRAME_SEGMAP].segmentation_map;
if (!s->s.frames[REF_FRAME_SEGMAP].uses_2pass)
- ff_thread_await_progress(&s->s.frames[REF_FRAME_SEGMAP].tf, row >> 3, 0);
+ ff_thread_progress_await(&s->s.frames[REF_FRAME_SEGMAP].tf, row >> 3);
for (y = 0; y < h4; y++) {
int idx_base = (y + row) * 8 * s->sb_cols + col;
for (x = 0; x < w4; x++)
diff --git a/libavcodec/vp9dec.h b/libavcodec/vp9dec.h
index 013aac49eb..cbeb0b1bea 100644
--- a/libavcodec/vp9dec.h
+++ b/libavcodec/vp9dec.h
@@ -120,7 +120,7 @@ typedef struct VP9Context {
int w, h;
enum AVPixelFormat pix_fmt, last_fmt, gf_fmt;
unsigned sb_cols, sb_rows, rows, cols;
- ThreadFrame next_refs[8];
+ ProgressFrame next_refs[8];
struct {
uint8_t lim_lut[64];
@@ -245,7 +245,7 @@ void ff_vp9_decode_block(VP9TileData *td, int row, int col,
VP9Filter *lflvl, ptrdiff_t yoff, ptrdiff_t uvoff,
enum BlockLevel bl, enum BlockPartition bp);
-void ff_vp9_loopfilter_sb(AVCodecContext *avctx, VP9Filter *lflvl,
+void ff_vp9_loopfilter_sb(struct AVCodecContext *avctx, VP9Filter *lflvl,
int row, int col, ptrdiff_t yoff, ptrdiff_t uvoff);
void ff_vp9_intra_recon_8bpp(VP9TileData *td,
diff --git a/libavcodec/vp9lpf.c b/libavcodec/vp9lpf.c
index 414cede852..afeebebf59 100644
--- a/libavcodec/vp9lpf.c
+++ b/libavcodec/vp9lpf.c
@@ -21,6 +21,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "avcodec.h"
#include "vp9dec.h"
static av_always_inline void filter_plane_cols(VP9Context *s, int col, int ss_h, int ss_v,
diff --git a/libavcodec/vp9mvs.c b/libavcodec/vp9mvs.c
index b93d878d6f..d0016d85ca 100644
--- a/libavcodec/vp9mvs.c
+++ b/libavcodec/vp9mvs.c
@@ -21,7 +21,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "threadframe.h"
+#include "progressframe.h"
#include "vp89_rac.h"
#include "vp9data.h"
#include "vp9dec.h"
@@ -175,7 +175,7 @@ static void find_ref_mvs(VP9TileData *td,
VP9mvrefPair *mv = &s->s.frames[REF_FRAME_MVPAIR].mv[row * s->sb_cols * 8 + col];
if (!s->s.frames[REF_FRAME_MVPAIR].uses_2pass)
- ff_thread_await_progress(&s->s.frames[REF_FRAME_MVPAIR].tf, row >> 3, 0);
+ ff_thread_progress_await(&s->s.frames[REF_FRAME_MVPAIR].tf, row >> 3);
if (mv->ref[0] == ref)
RETURN_MV(mv->mv[0]);
else if (mv->ref[1] == ref)
diff --git a/libavcodec/vp9recon.c b/libavcodec/vp9recon.c
index 073c04b47d..4af693608e 100644
--- a/libavcodec/vp9recon.c
+++ b/libavcodec/vp9recon.c
@@ -22,9 +22,10 @@
*/
#include "libavutil/avassert.h"
+#include "libavutil/frame.h"
#include "libavutil/mem_internal.h"
-#include "threadframe.h"
+#include "progressframe.h"
#include "videodsp.h"
#include "vp9data.h"
#include "vp9dec.h"
@@ -298,7 +299,7 @@ void ff_vp9_intra_recon_16bpp(VP9TileData *td, ptrdiff_t y_off, ptrdiff_t uv_off
static av_always_inline void mc_luma_unscaled(VP9TileData *td, const vp9_mc_func (*mc)[2],
uint8_t *dst, ptrdiff_t dst_stride,
const uint8_t *ref, ptrdiff_t ref_stride,
- const ThreadFrame *ref_frame,
+ const ProgressFrame *ref_frame,
ptrdiff_t y, ptrdiff_t x, const VP9mv *mv,
int bw, int bh, int w, int h, int bytesperpixel)
{
@@ -314,7 +315,7 @@ static av_always_inline void mc_luma_unscaled(VP9TileData *td, const vp9_mc_func
// we use +7 because the last 7 pixels of each sbrow can be changed in
// the longest loopfilter of the next sbrow
th = (y + bh + 4 * !!my + 7) >> 6;
- ff_thread_await_progress(ref_frame, FFMAX(th, 0), 0);
+ ff_thread_progress_await(ref_frame, FFMAX(th, 0));
// The arm/aarch64 _hv filters read one more row than what actually is
// needed, so switch to emulated edge one pixel sooner vertically
// (!!my * 5) than horizontally (!!mx * 4).
@@ -336,7 +337,7 @@ static av_always_inline void mc_chroma_unscaled(VP9TileData *td, const vp9_mc_fu
ptrdiff_t dst_stride,
const uint8_t *ref_u, ptrdiff_t src_stride_u,
const uint8_t *ref_v, ptrdiff_t src_stride_v,
- const ThreadFrame *ref_frame,
+ const ProgressFrame *ref_frame,
ptrdiff_t y, ptrdiff_t x, const VP9mv *mv,
int bw, int bh, int w, int h, int bytesperpixel)
{
@@ -353,7 +354,7 @@ static av_always_inline void mc_chroma_unscaled(VP9TileData *td, const vp9_mc_fu
// we use +7 because the last 7 pixels of each sbrow can be changed in
// the longest loopfilter of the next sbrow
th = (y + bh + 4 * !!my + 7) >> (6 - s->ss_v);
- ff_thread_await_progress(ref_frame, FFMAX(th, 0), 0);
+ ff_thread_progress_await(ref_frame, FFMAX(th, 0));
// The arm/aarch64 _hv filters read one more row than what actually is
// needed, so switch to emulated edge one pixel sooner vertically
// (!!my * 5) than horizontally (!!mx * 4).
@@ -407,7 +408,7 @@ static av_always_inline void mc_luma_scaled(VP9TileData *td, vp9_scaled_mc_func
const vp9_mc_func (*mc)[2],
uint8_t *dst, ptrdiff_t dst_stride,
const uint8_t *ref, ptrdiff_t ref_stride,
- const ThreadFrame *ref_frame,
+ const ProgressFrame *ref_frame,
ptrdiff_t y, ptrdiff_t x, const VP9mv *in_mv,
int px, int py, int pw, int ph,
int bw, int bh, int w, int h, int bytesperpixel,
@@ -444,7 +445,7 @@ static av_always_inline void mc_luma_scaled(VP9TileData *td, vp9_scaled_mc_func
// we use +7 because the last 7 pixels of each sbrow can be changed in
// the longest loopfilter of the next sbrow
th = (y + refbh_m1 + 4 + 7) >> 6;
- ff_thread_await_progress(ref_frame, FFMAX(th, 0), 0);
+ ff_thread_progress_await(ref_frame, FFMAX(th, 0));
// The arm/aarch64 _hv filters read one more row than what actually is
// needed, so switch to emulated edge one pixel sooner vertically
// (y + 5 >= h - refbh_m1) than horizontally (x + 4 >= w - refbw_m1).
@@ -467,7 +468,7 @@ static av_always_inline void mc_chroma_scaled(VP9TileData *td, vp9_scaled_mc_fun
ptrdiff_t dst_stride,
const uint8_t *ref_u, ptrdiff_t src_stride_u,
const uint8_t *ref_v, ptrdiff_t src_stride_v,
- const ThreadFrame *ref_frame,
+ const ProgressFrame *ref_frame,
ptrdiff_t y, ptrdiff_t x, const VP9mv *in_mv,
int px, int py, int pw, int ph,
int bw, int bh, int w, int h, int bytesperpixel,
@@ -514,7 +515,7 @@ static av_always_inline void mc_chroma_scaled(VP9TileData *td, vp9_scaled_mc_fun
// we use +7 because the last 7 pixels of each sbrow can be changed in
// the longest loopfilter of the next sbrow
th = (y + refbh_m1 + 4 + 7) >> (6 - s->ss_v);
- ff_thread_await_progress(ref_frame, FFMAX(th, 0), 0);
+ ff_thread_progress_await(ref_frame, FFMAX(th, 0));
// The arm/aarch64 _hv filters read one more row than what actually is
// needed, so switch to emulated edge one pixel sooner vertically
// (y + 5 >= h - refbh_m1) than horizontally (x + 4 >= w - refbw_m1).
diff --git a/libavcodec/vp9shared.h b/libavcodec/vp9shared.h
index b445a2a746..805668416f 100644
--- a/libavcodec/vp9shared.h
+++ b/libavcodec/vp9shared.h
@@ -29,8 +29,8 @@
#include "libavutil/mem_internal.h"
+#include "progressframe.h"
#include "vp9.h"
-#include "threadframe.h"
enum BlockPartition {
PARTITION_NONE, // [ ] <-.
@@ -63,7 +63,7 @@ typedef struct VP9mvrefPair {
} VP9mvrefPair;
typedef struct VP9Frame {
- ThreadFrame tf;
+ ProgressFrame tf;
void *extradata; ///< RefStruct reference
uint8_t *segmentation_map;
VP9mvrefPair *mv;
@@ -164,7 +164,7 @@ typedef struct VP9BitstreamHeader {
typedef struct VP9SharedContext {
VP9BitstreamHeader h;
- ThreadFrame refs[8];
+ ProgressFrame refs[8];
#define CUR_FRAME 0
#define REF_FRAME_MVPAIR 1
#define REF_FRAME_SEGMAP 2
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 30/42] avcodec/vp9: Switch to ProgressFrames
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 30/42] avcodec/vp9: " Andreas Rheinhardt
@ 2023-10-21 11:04 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-10-21 11:04 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:22)
> @@ -1605,7 +1590,8 @@ static int vp9_decode_frame(AVCodecContext *avctx, AVFrame *frame,
> f->flags &= ~AV_FRAME_FLAG_KEY;
> f->pict_type = (s->s.h.keyframe || s->s.h.intraonly) ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
>
> - if (s->s.frames[REF_FRAME_SEGMAP].tf.f->buf[0] &&
> + // Inexistent frames have the implicit dimension 0x0 != CUR_FRAME
Is this a word? I think one would normally say "non-existent".
Otherwise looks ok.
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 31/42] avcodec/vp9: Fix race when attaching side-data for show-existing frame
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (29 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 30/42] avcodec/vp9: " Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 32/42] avcodec/vp9: Reduce wait times Andreas Rheinhardt
` (17 subsequent siblings)
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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->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->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->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->s.frames[CUR_FRAME]);
if (ret < 0)
- return ret;
+ goto fail;
}
+ ff_thread_progress_report(&s->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->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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 32/42] avcodec/vp9: Reduce wait times
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (30 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 31/42] avcodec/vp9: Fix race when attaching side-data for show-existing frame Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 33/42] avcodec/vp9: Simplify replacing VP9Frame Andreas Rheinhardt
` (16 subsequent siblings)
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
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, &s->next_refs[i], &s->s.refs[i]);
+ ff_thread_finish_setup(avctx);
ff_thread_progress_await(&s->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, &s->next_refs[i], &s->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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 33/42] avcodec/vp9: Simplify replacing VP9Frame
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (31 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 32/42] avcodec/vp9: Reduce wait times Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 34/42] avcodec/vp9: Replace atomic_store() by atomic_init() Andreas Rheinhardt
` (15 subsequent siblings)
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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(&dst->tf, &src->tf);
+ ff_thread_progress_replace(avctx, &dst->tf, &src->tf);
- dst->extradata = ff_refstruct_ref(src->extradata);
+ ff_refstruct_replace(&dst->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->s.frames[CUR_FRAME] : NULL;
+ src = !s->s.h.keyframe && !s->s.h.intraonly && !s->s.h.errorres ?
+ &s->s.frames[CUR_FRAME] : &s->s.frames[BLANK_FRAME];
if (!retain_segmap_ref || s->s.h.keyframe || s->s.h.intraonly)
vp9_frame_replace(avctx, &s->s.frames[REF_FRAME_SEGMAP], src);
vp9_frame_replace(avctx, &s->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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 34/42] avcodec/vp9: Replace atomic_store() by atomic_init()
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (32 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 33/42] avcodec/vp9: Simplify replacing VP9Frame Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 35/42] avcodec/threadprogress: Add new API for frame-threaded progress Andreas Rheinhardt
` (14 subsequent siblings)
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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(&s->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(&s->entries[i], 0);
+ atomic_init(&s->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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 35/42] avcodec/threadprogress: Add new API for frame-threaded progress
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (33 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 34/42] avcodec/vp9: Replace atomic_store() by atomic_init() Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-09-20 19:44 ` Michael Niedermayer
2023-10-25 13:25 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 36/42] avcodec/wavpack: Use ThreadProgress API Andreas Rheinhardt
` (13 subsequent siblings)
48 siblings, 2 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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(&p->progress_cond, &p->progress_mutex);
pthread_mutex_unlock(&p->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(&pro->progress, -1);
+ if (atomic_load_explicit(&p->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(&pro->progress, memory_order_relaxed) >= n)
+ return;
+
+ if (atomic_load_explicit(&p->debug_threads, memory_order_relaxed))
+ av_log(p->avctx, AV_LOG_DEBUG,
+ "%p finished %d\n", (void*)pro, n);
+
+ pthread_mutex_lock(&p->progress_mutex);
+
+ atomic_store_explicit(&pro->progress, n, memory_order_release);
+
+ pthread_cond_broadcast(&p->progress_cond);
+ pthread_mutex_unlock(&p->progress_mutex);
+}
+
+void ff_thread_progress_await2(const ThreadProgress *pro, int n)
+{
+ PerThreadContext *p = pro->owner;
+
+ if (!p ||
+ atomic_load_explicit(&pro->progress, memory_order_acquire) >= n)
+ return;
+
+ if (atomic_load_explicit(&p->debug_threads, memory_order_relaxed))
+ av_log(p->avctx, AV_LOG_DEBUG,
+ "thread awaiting %d from %p\n", n, (void*)pro);
+
+ pthread_mutex_lock(&p->progress_mutex);
+ while (atomic_load_explicit(&pro->progress, memory_order_relaxed) < n)
+ pthread_cond_wait(&p->progress_cond, &p->progress_mutex);
+ pthread_mutex_unlock(&p->progress_mutex);
+}
diff --git a/libavcodec/threadprogress.h b/libavcodec/threadprogress.h
new file mode 100644
index 0000000000..4f65e7da4d
--- /dev/null
+++ b/libavcodec/threadprogress.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2022 Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
+ *
+ * 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 <stdatomic.h>
+
+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 */
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 35/42] avcodec/threadprogress: Add new API for frame-threaded progress
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 35/42] avcodec/threadprogress: Add new API for frame-threaded progress Andreas Rheinhardt
@ 2023-09-20 19:44 ` Michael Niedermayer
2023-09-21 0:28 ` Andreas Rheinhardt
2023-10-25 13:25 ` Anton Khirnov
1 sibling, 1 reply; 106+ messages in thread
From: Michael Niedermayer @ 2023-09-20 19:44 UTC (permalink / raw)
To: FFmpeg development discussions and patches
[-- Attachment #1.1: Type: text/plain, Size: 3112 bytes --]
On Tue, Sep 19, 2023 at 09:57:27PM +0200, Andreas Rheinhardt wrote:
> 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 <andreas.rheinhardt@outlook.com>
> ---
> libavcodec/pthread_frame.c | 50 +++++++++++++++++++++++++++++++++++++
> libavcodec/threadprogress.h | 37 +++++++++++++++++++++++++++
> 2 files changed, 87 insertions(+)
> create mode 100644 libavcodec/threadprogress.h
Seems to break build here with shared libs / clang
CC libavcodec/pthread_frame.o
src/libavcodec/pthread_frame.c:1108:9: error: address argument to atomic operation must be a pointer to non-const _Atomic type ('const atomic_int *' (aka 'const _Atomic(int) *') invalid)
atomic_load_explicit(&pro->progress, memory_order_acquire) >= n)
^ ~~~~~~~~~~~~~~
/usr/lib/llvm-6.0/lib/clang/6.0.0/include/stdatomic.h:135:30: note: expanded from macro 'atomic_load_explicit'
#define atomic_load_explicit __c11_atomic_load
^
src/libavcodec/pthread_frame.c:1116:12: error: address argument to atomic operation must be a pointer to non-const _Atomic type ('const atomic_int *' (aka 'const _Atomic(int) *') invalid)
while (atomic_load_explicit(&pro->progress, memory_order_relaxed) < n)
^ ~~~~~~~~~~~~~~
/usr/lib/llvm-6.0/lib/clang/6.0.0/include/stdatomic.h:135:30: note: expanded from macro 'atomic_load_explicit'
#define atomic_load_explicit __c11_atomic_load
^
2 errors generated.
src/ffbuild/common.mak:81: recipe for target 'libavcodec/pthread_frame.o' failed
make: *** [libavcodec/pthread_frame.o] Error 1
make: Target 'all' not remade because of errors.
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
Old school: Use the lowest level language in which you can solve the problem
conveniently.
New school: Use the highest level language in which the latest supercomputer
can solve the problem without the user falling asleep waiting.
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]
[-- Attachment #2: 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] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 35/42] avcodec/threadprogress: Add new API for frame-threaded progress
2023-09-20 19:44 ` Michael Niedermayer
@ 2023-09-21 0:28 ` Andreas Rheinhardt
0 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-21 0:28 UTC (permalink / raw)
To: ffmpeg-devel
Michael Niedermayer:
> On Tue, Sep 19, 2023 at 09:57:27PM +0200, Andreas Rheinhardt wrote:
>> 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 <andreas.rheinhardt@outlook.com>
>> ---
>> libavcodec/pthread_frame.c | 50 +++++++++++++++++++++++++++++++++++++
>> libavcodec/threadprogress.h | 37 +++++++++++++++++++++++++++
>> 2 files changed, 87 insertions(+)
>> create mode 100644 libavcodec/threadprogress.h
>
> Seems to break build here with shared libs / clang
>
> CC libavcodec/pthread_frame.o
> src/libavcodec/pthread_frame.c:1108:9: error: address argument to atomic operation must be a pointer to non-const _Atomic type ('const atomic_int *' (aka 'const _Atomic(int) *') invalid)
> atomic_load_explicit(&pro->progress, memory_order_acquire) >= n)
> ^ ~~~~~~~~~~~~~~
> /usr/lib/llvm-6.0/lib/clang/6.0.0/include/stdatomic.h:135:30: note: expanded from macro 'atomic_load_explicit'
> #define atomic_load_explicit __c11_atomic_load
> ^
> src/libavcodec/pthread_frame.c:1116:12: error: address argument to atomic operation must be a pointer to non-const _Atomic type ('const atomic_int *' (aka 'const _Atomic(int) *') invalid)
> while (atomic_load_explicit(&pro->progress, memory_order_relaxed) < n)
> ^ ~~~~~~~~~~~~~~
> /usr/lib/llvm-6.0/lib/clang/6.0.0/include/stdatomic.h:135:30: note: expanded from macro 'atomic_load_explicit'
> #define atomic_load_explicit __c11_atomic_load
> ^
> 2 errors generated.
> src/ffbuild/common.mak:81: recipe for target 'libavcodec/pthread_frame.o' failed
> make: *** [libavcodec/pthread_frame.o] Error 1
> make: Target 'all' not remade because of errors.
>
The original version of C11 did not allow to use atomic_load() on
const-qualified atomic objects (presumably because on systems that don't
have native support for atomic operations this might involve locking a
mutex or so and this would involve writes); this has since been changed
(see defect report N1807), yet your (presumably) ancient toolchain does
not reflect that.
I'll cast const away here and add a comment.
- 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] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 35/42] avcodec/threadprogress: Add new API for frame-threaded progress
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 35/42] avcodec/threadprogress: Add new API for frame-threaded progress Andreas Rheinhardt
2023-09-20 19:44 ` Michael Niedermayer
@ 2023-10-25 13:25 ` Anton Khirnov
1 sibling, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-10-25 13:25 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:27)
> 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 <andreas.rheinhardt@outlook.com>
> ---
> libavcodec/pthread_frame.c | 50 +++++++++++++++++++++++++++++++++++++
> libavcodec/threadprogress.h | 37 +++++++++++++++++++++++++++
> 2 files changed, 87 insertions(+)
> create mode 100644 libavcodec/threadprogress.h
Again, I'd prefer to do without owner.
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 36/42] avcodec/wavpack: Use ThreadProgress API
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (34 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 35/42] avcodec/threadprogress: Add new API for frame-threaded progress Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 37/42] avcodec/vp8: Convert to ProgressFrame API Andreas Rheinhardt
` (12 subsequent siblings)
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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(&s->dsdctx);
+ ff_refstruct_unref(&s->curr_progress);
+ ff_refstruct_unref(&s->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, &fdst->curr_frame);
- if (fsrc->curr_frame.f->data[0]) {
- if ((ret = ff_thread_ref_frame(&fdst->curr_frame, &fsrc->curr_frame)) < 0)
- return ret;
- }
+ ff_refstruct_replace(&fdst->progress_pool, fsrc->progress_pool);
+ ff_refstruct_replace(&fdst->curr_progress, fsrc->curr_progress);
ff_refstruct_replace(&fdst->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(&s->fdec);
s->fdec_num = 0;
- ff_thread_release_ext_buffer(avctx, &s->curr_frame);
- av_frame_free(&s->curr_frame.f);
-
- ff_thread_release_ext_buffer(avctx, &s->prev_frame);
- av_frame_free(&s->prev_frame.f);
-
ff_refstruct_unref(&s->dsdctx);
+ ff_refstruct_unref(&s->curr_progress);
+ ff_refstruct_unref(&s->prev_progress);
+ ff_refstruct_pool_uninit(&s->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, &wc->curr_frame);
}
av_channel_layout_copy(&avctx->ch_layout, &new_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, &wc->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, &wc->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(&wc->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 ((avctx->err_recognition & AV_EF_EXPLODE) || !wc->ch_offset) ? AVERROR_INVALIDDATA : 0;
}
- samples_l = wc->frame->extended_data[wc->ch_offset];
+ samples_l = frame->extended_data[wc->ch_offset];
if (s->stereo)
- samples_r = wc->frame->extended_data[wc->ch_offset + 1];
+ samples_r = frame->extended_data[wc->ch_offset + 1];
wc->ch_offset += 1 + s->stereo;
@@ -1606,14 +1600,14 @@ static int dsd_channel(AVCodecContext *avctx, void *frmptr, int jobnr, int threa
const WavpackContext *s = avctx->priv_data;
AVFrame *frame = frmptr;
- ff_dsd2pcm_translate (&s->dsdctx [jobnr], s->samples, 0,
+ ff_dsd2pcm_translate(&s->dsdctx[jobnr], s->samples, 0,
(uint8_t *)frame->extended_data[jobnr], 4,
(float *)frame->extended_data[jobnr], 1);
return 0;
}
-static int wavpack_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
+static int wavpack_decode_frame(AVCodecContext *avctx, AVFrame *frame,
int *got_frame_ptr, AVPacket *avpkt)
{
WavpackContext *s = avctx->priv_data;
@@ -1624,7 +1618,6 @@ static int wavpack_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
if (avpkt->size <= WV_HEADER_SIZE)
return AVERROR_INVALIDDATA;
- s->frame = NULL;
s->block = 0;
s->ch_offset = 0;
@@ -1650,7 +1643,8 @@ static int wavpack_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
ret = AVERROR_INVALIDDATA;
goto error;
}
- if ((ret = wavpack_decode_block(avctx, s->block, buf, frame_size)) < 0)
+ ret = wavpack_decode_block(avctx, frame, s->block, buf, frame_size);
+ if (ret < 0)
goto error;
s->block++;
buf += frame_size;
@@ -1663,26 +1657,22 @@ static int wavpack_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
goto error;
}
- ff_thread_await_progress(&s->prev_frame, INT_MAX, 0);
- ff_thread_release_ext_buffer(avctx, &s->prev_frame);
-
- if (s->modulation == MODULATION_DSD)
- avctx->execute2(avctx, dsd_channel, s->frame, NULL, avctx->ch_layout.nb_channels);
-
- ff_thread_report_progress(&s->curr_frame, INT_MAX, 0);
-
- if ((ret = av_frame_ref(rframe, s->frame)) < 0)
- return ret;
+ if (s->dsdctx) {
+ if (s->prev_progress)
+ ff_thread_progress_await2(s->prev_progress, INT_MAX);
+ avctx->execute2(avctx, dsd_channel, frame, NULL, avctx->ch_layout.nb_channels);
+ ff_thread_progress_report2(s->curr_progress, INT_MAX);
+ }
*got_frame_ptr = 1;
return avpkt->size;
error:
- if (s->frame) {
- ff_thread_await_progress(&s->prev_frame, INT_MAX, 0);
- ff_thread_release_ext_buffer(avctx, &s->prev_frame);
- ff_thread_report_progress(&s->curr_frame, INT_MAX, 0);
+ if (s->curr_progress) {
+ if (s->prev_progress)
+ ff_thread_progress_await2(s->prev_progress, INT_MAX);
+ ff_thread_progress_report2(s->curr_progress, INT_MAX);
}
return ret;
@@ -1701,6 +1691,4 @@ const FFCodec ff_wavpack_decoder = {
UPDATE_THREAD_CONTEXT(update_thread_context),
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS |
AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_CHANNEL_CONF,
- .caps_internal = FF_CODEC_CAP_INIT_CLEANUP |
- FF_CODEC_CAP_ALLOCATE_PROGRESS,
};
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 37/42] avcodec/vp8: Convert to ProgressFrame API
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (35 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 36/42] avcodec/wavpack: Use ThreadProgress API Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-10-25 13:35 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 38/42] avcodec/codec_internal: Remove FF_CODEC_CAP_ALLOCATE_PROGRESS Andreas Rheinhardt
` (11 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
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, &f->tf,
- ref ? AV_GET_BUFFER_FLAG_REF : 0)) < 0)
+ int ret = ff_thread_progress_get_buffer(s->avctx, &f->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(&f->seg_map);
- ff_thread_release_ext_buffer(s->avctx, &f->tf);
+ ff_thread_progress_unref(s->avctx, &f->tf);
return ret;
}
@@ -124,23 +124,16 @@ static void vp8_release_frame(VP8Context *s, VP8Frame *f)
{
ff_refstruct_unref(&f->seg_map);
ff_refstruct_unref(&f->hwaccel_picture_private);
- ff_thread_release_ext_buffer(s->avctx, &f->tf);
+ ff_thread_progress_unref(s->avctx, &f->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(&dst->tf, &src->tf)) < 0)
- return ret;
+ ff_thread_progress_replace(s->avctx, &dst->tf, &src->tf);
ff_refstruct_replace(&dst->seg_map, src->seg_map);
ff_refstruct_replace(&dst->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 || y_off >= height - block_h - subpel_idx[2][my]) {
s->vdsp.emulated_edge_mc(td->edge_emu_buffer,
@@ -1929,7 +1922,7 @@ void vp8_mc_chroma(VP8Context *s, VP8ThreadData *td, uint8_t *dst1,
mc_func[my_idx][mx_idx](dst2, linesize, src2, linesize, block_h, mx, my);
}
} else {
- ff_thread_await_progress(ref, (3 + y_off + block_h) >> 3, 0);
+ ff_thread_progress_await(ref, (3 + y_off + block_h) >> 3);
mc_func[0][0](dst1, linesize, src1 + y_off * linesize + x_off, linesize, block_h, 0, 0);
mc_func[0][0](dst2, linesize, src2 + y_off * linesize + x_off, linesize, block_h, 0, 0);
}
@@ -1937,7 +1930,7 @@ void vp8_mc_chroma(VP8Context *s, VP8ThreadData *td, uint8_t *dst1,
static av_always_inline
void vp8_mc_part(VP8Context *s, VP8ThreadData *td, uint8_t *const dst[3],
- const ThreadFrame *ref_frame, int x_off, int y_off,
+ const ProgressFrame *ref_frame, int x_off, int y_off,
int bx_off, int by_off, int block_w, int block_h,
int width, int height, const VP8mv *mv)
{
@@ -2002,7 +1995,7 @@ void inter_predict(VP8Context *s, VP8ThreadData *td, uint8_t *const dst[3],
{
int x_off = mb_x << 4, y_off = mb_y << 4;
int width = 16 * s->mb_width, height = 16 * s->mb_height;
- const ThreadFrame *ref = &s->framep[mb->ref_frame]->tf;
+ const ProgressFrame *ref = &s->framep[mb->ref_frame]->tf;
const VP8mv *bmv = mb->bmv;
switch (mb->partitioning) {
@@ -2422,7 +2415,7 @@ static av_always_inline int decode_mb_row_no_filter(AVCodecContext *avctx, void
// if we re-use the same map.
if (prev_frame && s->segmentation.enabled &&
!s->segmentation.update_map)
- ff_thread_await_progress(&prev_frame->tf, mb_y, 0);
+ ff_thread_progress_await(&prev_frame->tf, mb_y);
mb = s->macroblocks + (s->mb_height - mb_y - 1) * 2;
memset(mb - 1, 0, sizeof(*mb)); // zero left macroblock
AV_WN32A(s->intra4x4_pred_mode_left, DC_PRED * 0x01010101);
@@ -2630,7 +2623,7 @@ int vp78_decode_mb_row_sliced(AVCodecContext *avctx, void *tdata, int jobnr,
td->mv_bounds.mv_max.y -= 64 * num_jobs;
if (avctx->active_thread_type == FF_THREAD_FRAME)
- ff_thread_report_progress(&curframe->tf, mb_y, 0);
+ ff_thread_progress_report(&curframe->tf, mb_y);
}
return 0;
@@ -2694,7 +2687,7 @@ int vp78_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame,
// release no longer referenced frames
for (i = 0; i < 5; i++)
- if (s->frames[i].tf.f->buf[0] &&
+ if (s->frames[i].tf.f &&
&s->frames[i] != prev_frame &&
&s->frames[i] != s->framep[VP8_FRAME_PREVIOUS] &&
&s->frames[i] != s->framep[VP8_FRAME_GOLDEN] &&
@@ -2723,14 +2716,14 @@ int vp78_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame,
goto err;
}
+ if ((ret = vp8_alloc_frame(s, curframe, referenced)) < 0)
+ goto err;
if (s->keyframe)
curframe->tf.f->flags |= AV_FRAME_FLAG_KEY;
else
curframe->tf.f->flags &= ~AV_FRAME_FLAG_KEY;
curframe->tf.f->pict_type = s->keyframe ? AV_PICTURE_TYPE_I
: AV_PICTURE_TYPE_P;
- if ((ret = vp8_alloc_frame(s, curframe, referenced)) < 0)
- goto err;
// check if golden and altref are swapped
if (s->update_altref != VP8_FRAME_NONE)
@@ -2787,7 +2780,7 @@ int vp78_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame,
// if we re-use the same map.
if (prev_frame && s->segmentation.enabled &&
!s->segmentation.update_map)
- ff_thread_await_progress(&prev_frame->tf, 1, 0);
+ ff_thread_progress_await(&prev_frame->tf, 1);
if (is_vp7)
ret = vp7_decode_mv_mb_modes(avctx, curframe, prev_frame);
else
@@ -2818,7 +2811,7 @@ int vp78_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame,
num_jobs);
}
- ff_thread_report_progress(&curframe->tf, INT_MAX, 0);
+ ff_thread_progress_report(&curframe->tf, INT_MAX);
memcpy(&s->framep[0], &s->next_framep[0], sizeof(s->framep[0]) * 4);
skip_decode:
@@ -2855,32 +2848,15 @@ static int vp7_decode_frame(AVCodecContext *avctx, AVFrame *frame,
av_cold int ff_vp8_decode_free(AVCodecContext *avctx)
{
- VP8Context *s = avctx->priv_data;
- int i;
-
vp8_decode_flush_impl(avctx, 1);
- for (i = 0; i < FF_ARRAY_ELEMS(s->frames); i++)
- av_frame_free(&s->frames[i].tf.f);
return 0;
}
-static av_cold int vp8_init_frames(VP8Context *s)
-{
- int i;
- for (i = 0; i < FF_ARRAY_ELEMS(s->frames); i++) {
- s->frames[i].tf.f = av_frame_alloc();
- if (!s->frames[i].tf.f)
- return AVERROR(ENOMEM);
- }
- return 0;
-}
-
static av_always_inline
int vp78_decode_init(AVCodecContext *avctx, int is_vp7)
{
VP8Context *s = avctx->priv_data;
- int ret;
s->avctx = avctx;
s->vp7 = avctx->codec->id == AV_CODEC_ID_VP7;
@@ -2905,11 +2881,6 @@ int vp78_decode_init(AVCodecContext *avctx, int is_vp7)
/* does not change for VP8 */
memcpy(s->prob[0].scan, ff_zigzag_scan, sizeof(s->prob[0].scan));
- if ((ret = vp8_init_frames(s)) < 0) {
- ff_vp8_decode_free(avctx);
- return ret;
- }
-
return 0;
}
@@ -2933,7 +2904,6 @@ static int vp8_decode_update_thread_context(AVCodecContext *dst,
const AVCodecContext *src)
{
VP8Context *s = dst->priv_data, *s_src = src->priv_data;
- int i;
if (s->macroblocks_base &&
(s_src->mb_width != s->mb_width || s_src->mb_height != s->mb_height)) {
@@ -2948,13 +2918,8 @@ static int vp8_decode_update_thread_context(AVCodecContext *dst,
s->lf_delta = s_src->lf_delta;
memcpy(s->sign_bias, s_src->sign_bias, sizeof(s->sign_bias));
- for (i = 0; i < FF_ARRAY_ELEMS(s_src->frames); i++) {
- if (s_src->frames[i].tf.f->buf[0]) {
- int ret = vp8_ref_frame(s, &s->frames[i], &s_src->frames[i]);
- if (ret < 0)
- return ret;
- }
- }
+ for (int i = 0; i < FF_ARRAY_ELEMS(s_src->frames); i++)
+ vp8_replace_frame(s, &s->frames[i], &s_src->frames[i]);
s->framep[0] = REBASE(s_src->next_framep[0]);
s->framep[1] = REBASE(s_src->next_framep[1]);
@@ -2978,6 +2943,7 @@ const FFCodec ff_vp7_decoder = {
FF_CODEC_DECODE_CB(vp7_decode_frame),
.p.capabilities = AV_CODEC_CAP_DR1,
.flush = vp8_decode_flush,
+ .caps_internal = FF_CODEC_CAP_USES_PROGRESSFRAMES,
};
#endif /* CONFIG_VP7_DECODER */
@@ -2993,7 +2959,7 @@ const FFCodec ff_vp8_decoder = {
FF_CODEC_DECODE_CB(ff_vp8_decode_frame),
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS |
AV_CODEC_CAP_SLICE_THREADS,
- .caps_internal = FF_CODEC_CAP_ALLOCATE_PROGRESS,
+ .caps_internal = FF_CODEC_CAP_USES_PROGRESSFRAMES,
.flush = vp8_decode_flush,
UPDATE_THREAD_CONTEXT(vp8_decode_update_thread_context),
.hw_configs = (const AVCodecHWConfigInternal *const []) {
diff --git a/libavcodec/vp8.h b/libavcodec/vp8.h
index eb9fa2f166..e38b92f0fe 100644
--- a/libavcodec/vp8.h
+++ b/libavcodec/vp8.h
@@ -31,8 +31,9 @@
#include "libavutil/mem_internal.h"
#include "libavutil/thread.h"
+#include "avcodec.h"
#include "h264pred.h"
-#include "threadframe.h"
+#include "progressframe.h"
#include "videodsp.h"
#include "vp8dsp.h"
#include "vpx_rac.h"
@@ -150,7 +151,7 @@ typedef struct VP8ThreadData {
} VP8ThreadData;
typedef struct VP8Frame {
- ThreadFrame tf;
+ ProgressFrame tf;
uint8_t *seg_map; ///< RefStruct reference
void *hwaccel_picture_private; ///< RefStruct reference
diff --git a/libavcodec/webp.c b/libavcodec/webp.c
index 54b3fde6dc..85cb884153 100644
--- a/libavcodec/webp.c
+++ b/libavcodec/webp.c
@@ -1565,5 +1565,6 @@ const FFCodec ff_webp_decoder = {
FF_CODEC_DECODE_CB(webp_decode_frame),
.close = webp_decode_close,
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
- .caps_internal = FF_CODEC_CAP_ICC_PROFILES,
+ .caps_internal = FF_CODEC_CAP_ICC_PROFILES |
+ FF_CODEC_CAP_USES_PROGRESSFRAMES,
};
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 38/42] avcodec/codec_internal: Remove FF_CODEC_CAP_ALLOCATE_PROGRESS
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (36 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 37/42] avcodec/vp8: Convert to ProgressFrame API Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-10-25 13:38 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 39/42] avcodec/hevcdec: Move collocated_ref to HEVCContext Andreas Rheinhardt
` (10 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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
+++ b/libavcodec/hevcdec.c
@@ -3671,7 +3671,7 @@ const FFCodec ff_hevc_decoder = {
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS,
.caps_internal = FF_CODEC_CAP_EXPORTS_CROPPING |
- FF_CODEC_CAP_ALLOCATE_PROGRESS | FF_CODEC_CAP_INIT_CLEANUP,
+ FF_CODEC_CAP_INIT_CLEANUP,
.p.profiles = NULL_IF_CONFIG_SMALL(ff_hevc_profiles),
.hw_configs = (const AVCodecHWConfigInternal *const []) {
#if CONFIG_HEVC_DXVA2_HWACCEL
diff --git a/libavcodec/mpeg4videodec.c b/libavcodec/mpeg4videodec.c
index a8dd57bf6b..e0b0e1e08c 100644
--- a/libavcodec/mpeg4videodec.c
+++ b/libavcodec/mpeg4videodec.c
@@ -3860,8 +3860,7 @@ const FFCodec ff_mpeg4_decoder = {
FF_CODEC_DECODE_CB(ff_h263_decode_frame),
.p.capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1 |
AV_CODEC_CAP_DELAY | AV_CODEC_CAP_FRAME_THREADS,
- .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM |
- FF_CODEC_CAP_ALLOCATE_PROGRESS,
+ .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
.flush = ff_mpeg_flush,
.p.max_lowres = 3,
.p.pix_fmts = ff_h263_hwaccel_pixfmt_list_420,
diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c
index 0369d1c449..c011ca386e 100644
--- a/libavcodec/pngdec.c
+++ b/libavcodec/pngdec.c
@@ -1862,7 +1862,6 @@ const FFCodec ff_apng_decoder = {
UPDATE_THREAD_CONTEXT(update_thread_context),
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
.caps_internal = FF_CODEC_CAP_INIT_CLEANUP |
- FF_CODEC_CAP_ALLOCATE_PROGRESS |
FF_CODEC_CAP_ICC_PROFILES,
};
#endif
@@ -1880,7 +1879,7 @@ const FFCodec ff_png_decoder = {
UPDATE_THREAD_CONTEXT(update_thread_context),
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
.caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM |
- FF_CODEC_CAP_ALLOCATE_PROGRESS | FF_CODEC_CAP_INIT_CLEANUP |
+ FF_CODEC_CAP_INIT_CLEANUP |
FF_CODEC_CAP_ICC_PROFILES,
};
#endif
diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index 219ab16ccd..28b727dec9 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -998,14 +998,12 @@ int ff_thread_get_ext_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags)
if (!(avctx->active_thread_type & FF_THREAD_FRAME))
return ff_get_buffer(avctx, f->f, flags);
- if (ffcodec(avctx->codec)->caps_internal & FF_CODEC_CAP_ALLOCATE_PROGRESS) {
- f->progress = ff_refstruct_allocz(sizeof(*f->progress));
- if (!f->progress)
- return AVERROR(ENOMEM);
+ f->progress = ff_refstruct_allocz(sizeof(*f->progress));
+ if (!f->progress)
+ return AVERROR(ENOMEM);
- atomic_init(&f->progress->progress[0], -1);
- atomic_init(&f->progress->progress[1], -1);
- }
+ atomic_init(&f->progress->progress[0], -1);
+ atomic_init(&f->progress->progress[1], -1);
ret = ff_thread_get_buffer(avctx, f->f, flags);
if (ret)
diff --git a/libavcodec/rv30.c b/libavcodec/rv30.c
index be62577f99..d0e10722cd 100644
--- a/libavcodec/rv30.c
+++ b/libavcodec/rv30.c
@@ -308,5 +308,4 @@ const FFCodec ff_rv30_decoder = {
AV_PIX_FMT_NONE
},
UPDATE_THREAD_CONTEXT(ff_rv34_decode_update_thread_context),
- .caps_internal = FF_CODEC_CAP_ALLOCATE_PROGRESS,
};
diff --git a/libavcodec/rv40.c b/libavcodec/rv40.c
index d2f8ef9f5a..689432b4bb 100644
--- a/libavcodec/rv40.c
+++ b/libavcodec/rv40.c
@@ -591,5 +591,4 @@ const FFCodec ff_rv40_decoder = {
AV_PIX_FMT_NONE
},
UPDATE_THREAD_CONTEXT(ff_rv34_decode_update_thread_context),
- .caps_internal = FF_CODEC_CAP_ALLOCATE_PROGRESS,
};
diff --git a/libavcodec/tests/avcodec.c b/libavcodec/tests/avcodec.c
index f6e394c78d..d65f682c76 100644
--- a/libavcodec/tests/avcodec.c
+++ b/libavcodec/tests/avcodec.c
@@ -141,8 +141,7 @@ int main(void){
ret = 1;
}
}
- if (codec2->caps_internal & (FF_CODEC_CAP_ALLOCATE_PROGRESS |
- FF_CODEC_CAP_SETS_PKT_DTS |
+ if (codec2->caps_internal & (FF_CODEC_CAP_SETS_PKT_DTS |
FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM |
FF_CODEC_CAP_EXPORTS_CROPPING |
FF_CODEC_CAP_SETS_FRAME_PROPS |
@@ -172,10 +171,6 @@ int main(void){
AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE |
AV_CODEC_CAP_ENCODER_FLUSH))
ERR("Decoder %s has encoder-only capabilities\n");
- if (codec2->caps_internal & FF_CODEC_CAP_ALLOCATE_PROGRESS &&
- !(codec->capabilities & AV_CODEC_CAP_FRAME_THREADS))
- ERR("Decoder %s wants allocated progress without supporting"
- "frame threads\n");
if (codec2->cb_type != FF_CODEC_CB_TYPE_DECODE &&
codec2->caps_internal & FF_CODEC_CAP_SETS_PKT_DTS)
ERR("Decoder %s is marked as setting pkt_dts when it doesn't have"
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 38/42] avcodec/codec_internal: Remove FF_CODEC_CAP_ALLOCATE_PROGRESS
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 38/42] avcodec/codec_internal: Remove FF_CODEC_CAP_ALLOCATE_PROGRESS Andreas Rheinhardt
@ 2023-10-25 13:38 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-10-25 13:38 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:30)
> 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 <andreas.rheinhardt@outlook.com>
> ---
> 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(-)
LGTM
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 39/42] avcodec/hevcdec: Move collocated_ref to HEVCContext
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (37 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 38/42] avcodec/codec_internal: Remove FF_CODEC_CAP_ALLOCATE_PROGRESS Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-10-25 13:42 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 40/42] avcodec/hevcdec: Switch to ProgressFrames Andreas Rheinhardt
` (9 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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(&frame->rpl_tab);
frame->refPicList = NULL;
- frame->collocated_ref = NULL;
-
ff_refstruct_unref(&frame->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(&s->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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 39/42] avcodec/hevcdec: Move collocated_ref to HEVCContext
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 39/42] avcodec/hevcdec: Move collocated_ref to HEVCContext Andreas Rheinhardt
@ 2023-10-25 13:42 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-10-25 13:42 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:31)
> 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 <andreas.rheinhardt@outlook.com>
> ---
> 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(-)
Ok
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 40/42] avcodec/hevcdec: Switch to ProgressFrames
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (38 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 39/42] avcodec/hevcdec: Move collocated_ref to HEVCContext Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-11-09 9:50 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 41/42] avcodec/pngdec: " Andreas Rheinhardt
` (8 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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(&s->ref->tf, y, 0);
+ ff_thread_progress_report(&s->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(&s->ref->tf, y + ctb_size, 0);
+ ff_thread_progress_report(&s->ref->tf, y + ctb_size);
}
} else if (s->threads_type & FF_THREAD_FRAME && x_end)
- ff_thread_report_progress(&s->ref->tf, y + ctb_size - 4, 0);
+ ff_thread_progress_report(&s->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(&ref->tf, y, 0);
+ ff_thread_progress_await(&ref->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(&ref->tf, y, 0);
+ ff_thread_progress_await(&ref->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, &frame->tf);
+ ff_thread_progress_unref(s->avctx, &frame->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 = &s->DPB[i];
- if (frame->frame->buf[0])
+ if (frame->frame)
continue;
- ret = ff_thread_get_ext_buffer(s->avctx, &frame->tf,
- AV_GET_BUFFER_FLAG_REF);
+ ret = ff_thread_progress_get_buffer(s->avctx, &frame->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 = &s->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",
poc);
@@ -395,7 +393,7 @@ static HEVCFrame *find_ref_idx(HEVCContext *s, int poc, uint8_t use_msb)
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
HEVCFrame *ref = &s->DPB[i];
- if (ref->frame->buf[0] && ref->sequence == s->seq_decode) {
+ if (ref->frame && ref->sequence == s->seq_decode) {
if ((ref->poc & mask) == poc && (use_msb || ref->poc != s->poc))
return ref;
}
@@ -442,7 +440,7 @@ static HEVCFrame *generate_missing_ref(HEVCContext *s, int poc)
frame->flags = 0;
if (s->threads_type == FF_THREAD_FRAME)
- ff_thread_report_progress(&frame->tf, INT_MAX, 0);
+ ff_thread_progress_report(&frame->tf, INT_MAX);
return frame;
}
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index a476a7c7ce..355604a46f 100644
--- a/libavcodec/hevcdec.c
+++ b/libavcodec/hevcdec.c
@@ -47,9 +47,9 @@
#include "hwconfig.h"
#include "internal.h"
#include "profiles.h"
+#include "progressframe.h"
#include "refstruct.h"
#include "thread.h"
-#include "threadframe.h"
static const uint8_t hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12] = 4, [16] = 5, [24] = 6, [32] = 7, [48] = 8, [64] = 9 };
@@ -1857,7 +1857,7 @@ static void hevc_await_progress(const HEVCContext *s, const HEVCFrame *ref,
if (s->threads_type == FF_THREAD_FRAME ) {
int y = FFMAX(0, (mv->y >> 2) + y0 + height + 9);
- ff_thread_await_progress(&ref->tf, y, 0);
+ ff_thread_progress_await(&ref->tf, y);
}
}
@@ -3210,7 +3210,7 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length)
fail:
if (s->ref && s->threads_type == FF_THREAD_FRAME)
- ff_thread_report_progress(&s->ref->tf, INT_MAX, 0);
+ ff_thread_progress_report(&s->ref->tf, INT_MAX);
return ret;
}
@@ -3381,14 +3381,15 @@ static int hevc_ref_frame(HEVCContext *s, HEVCFrame *dst, HEVCFrame *src)
{
int ret;
- ret = ff_thread_ref_frame(&dst->tf, &src->tf);
- if (ret < 0)
- return ret;
+ ff_thread_progress_ref(&dst->tf, &src->tf);
+ dst->frame = dst->tf.f;
if (src->needs_fg) {
ret = av_frame_ref(dst->frame_grain, src->frame_grain);
- if (ret < 0)
+ if (ret < 0) {
+ ff_hevc_unref_frame(s, dst, ~0);
return ret;
+ }
dst->needs_fg = 1;
}
@@ -3428,7 +3429,6 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
ff_hevc_unref_frame(s, &s->DPB[i], ~0);
- av_frame_free(&s->DPB[i].frame);
av_frame_free(&s->DPB[i].frame_grain);
}
@@ -3474,11 +3474,6 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
return AVERROR(ENOMEM);
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
- s->DPB[i].frame = av_frame_alloc();
- if (!s->DPB[i].frame)
- return AVERROR(ENOMEM);
- s->DPB[i].tf.f = s->DPB[i].frame;
-
s->DPB[i].frame_grain = av_frame_alloc();
if (!s->DPB[i].frame_grain)
return AVERROR(ENOMEM);
@@ -3510,7 +3505,7 @@ static int hevc_update_thread_context(AVCodecContext *dst,
for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) {
ff_hevc_unref_frame(s, &s->DPB[i], ~0);
- if (s0->DPB[i].frame->buf[0]) {
+ if (s0->DPB[i].frame) {
ret = hevc_ref_frame(s, &s->DPB[i], &s0->DPB[i]);
if (ret < 0)
return ret;
@@ -3671,6 +3666,7 @@ const FFCodec ff_hevc_decoder = {
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS,
.caps_internal = FF_CODEC_CAP_EXPORTS_CROPPING |
+ FF_CODEC_CAP_USES_PROGRESSFRAMES |
FF_CODEC_CAP_INIT_CLEANUP,
.p.profiles = NULL_IF_CONFIG_SMALL(ff_hevc_profiles),
.hw_configs = (const AVCodecHWConfigInternal *const []) {
diff --git a/libavcodec/hevcdec.h b/libavcodec/hevcdec.h
index bed8716f99..827a26c536 100644
--- a/libavcodec/hevcdec.h
+++ b/libavcodec/hevcdec.h
@@ -40,7 +40,7 @@
#include "hevc_sei.h"
#include "hevcdsp.h"
#include "h274.h"
-#include "threadframe.h"
+#include "progressframe.h"
#include "videodsp.h"
#define SHIFT_CTB_WPP 2
@@ -406,7 +406,7 @@ typedef struct DBParams {
typedef struct HEVCFrame {
AVFrame *frame;
AVFrame *frame_grain;
- ThreadFrame tf;
+ ProgressFrame tf;
int needs_fg; /* 1 if grain needs to be applied by the decoder */
MvField *tab_mvf; ///< RefStruct reference
RefPicList *refPicList;
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 40/42] avcodec/hevcdec: Switch to ProgressFrames
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 40/42] avcodec/hevcdec: Switch to ProgressFrames Andreas Rheinhardt
@ 2023-11-09 9:50 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-11-09 9:50 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:32)
> 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 <andreas.rheinhardt@outlook.com>
> ---
> 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(-)
Looks ok
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 41/42] avcodec/pngdec: Switch to ProgressFrames
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (39 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 40/42] avcodec/hevcdec: Switch to ProgressFrames Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-11-09 9:52 ` Anton Khirnov
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 42/42] avcodec/ffv1dec: " Andreas Rheinhardt
` (7 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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 <zlib.h>
@@ -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, &s->picture);
+ ff_thread_progress_unref(avctx, &s->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, &s->picture,
- AV_GET_BUFFER_FLAG_REF);
+ ret = ff_thread_progress_get_buffer(avctx, &s->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, &s->picture,
- AV_GET_BUFFER_FLAG_REF)) < 0)
+ ret = ff_thread_progress_get_buffer(avctx, &s->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(&s->last_picture, INT_MAX, 0);
+ ff_thread_progress_await(&s->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(&s->last_picture, INT_MAX, 0);
+ ff_thread_progress_await(&s->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(&s->picture, INT_MAX, 0);
-
- return 0;
-
+ ret = 0;
fail:
- ff_thread_report_progress(&s->picture, INT_MAX, 0);
+ if (s->picture.f)
+ ff_thread_progress_report(&s->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, &s->last_picture);
- FFSWAP(ThreadFrame, s->picture, s->last_picture);
+ ff_thread_progress_unref(avctx, &s->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, &s->picture);
+ ff_thread_progress_unref(avctx, &s->picture);
} else {
- ff_thread_release_ext_buffer(avctx, &s->last_picture);
- FFSWAP(ThreadFrame, s->picture, s->last_picture);
+ ff_thread_progress_unref(avctx, &s->last_picture);
+ FFSWAP(ProgressFrame, s->picture, s->last_picture);
}
}
@@ -1773,8 +1773,7 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
{
PNGDecContext *psrc = src->priv_data;
PNGDecContext *pdst = dst->priv_data;
- ThreadFrame *src_frame = NULL;
- int ret;
+ const ProgressFrame *src_frame;
if (dst == src)
return 0;
@@ -1799,12 +1798,7 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
src_frame = psrc->dispose_op == APNG_DISPOSE_OP_PREVIOUS ?
&psrc->last_picture : &psrc->picture;
- ff_thread_release_ext_buffer(dst, &pdst->last_picture);
- if (src_frame && src_frame->f->data[0]) {
- ret = ff_thread_ref_frame(&pdst->last_picture, src_frame);
- if (ret < 0)
- return ret;
- }
+ ff_thread_progress_replace(dst, &pdst->last_picture, src_frame);
return 0;
}
@@ -1817,10 +1811,6 @@ static av_cold int png_dec_init(AVCodecContext *avctx)
avctx->color_range = AVCOL_RANGE_JPEG;
s->avctx = avctx;
- s->last_picture.f = av_frame_alloc();
- s->picture.f = av_frame_alloc();
- if (!s->last_picture.f || !s->picture.f)
- return AVERROR(ENOMEM);
ff_pngdsp_init(&s->dsp);
@@ -1831,10 +1821,8 @@ static av_cold int png_dec_end(AVCodecContext *avctx)
{
PNGDecContext *s = avctx->priv_data;
- ff_thread_release_ext_buffer(avctx, &s->last_picture);
- av_frame_free(&s->last_picture.f);
- ff_thread_release_ext_buffer(avctx, &s->picture);
- av_frame_free(&s->picture.f);
+ ff_thread_progress_unref(avctx, &s->last_picture);
+ ff_thread_progress_unref(avctx, &s->picture);
av_freep(&s->buffer);
s->buffer_size = 0;
av_freep(&s->last_row);
@@ -1862,6 +1850,7 @@ const FFCodec ff_apng_decoder = {
UPDATE_THREAD_CONTEXT(update_thread_context),
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
.caps_internal = FF_CODEC_CAP_INIT_CLEANUP |
+ FF_CODEC_CAP_USES_PROGRESSFRAMES |
FF_CODEC_CAP_ICC_PROFILES,
};
#endif
@@ -1880,6 +1869,7 @@ const FFCodec ff_png_decoder = {
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
.caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM |
FF_CODEC_CAP_INIT_CLEANUP |
+ FF_CODEC_CAP_USES_PROGRESSFRAMES |
FF_CODEC_CAP_ICC_PROFILES,
};
#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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 41/42] avcodec/pngdec: Switch to ProgressFrames
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 41/42] avcodec/pngdec: " Andreas Rheinhardt
@ 2023-11-09 9:52 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-11-09 9:52 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:33)
> 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 <andreas.rheinhardt@outlook.com>
> ---
> libavcodec/pngdec.c | 64 +++++++++++++++++++--------------------------
> 1 file changed, 27 insertions(+), 37 deletions(-)
Looks ok
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 42/42] avcodec/ffv1dec: Switch to ProgressFrames
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (40 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 41/42] avcodec/pngdec: " Andreas Rheinhardt
@ 2023-09-19 19:57 ` Andreas Rheinhardt
2023-11-09 9:56 ` Anton Khirnov
2023-10-02 18:13 ` [FFmpeg-devel] [PATCH 43/49] avcodec/qsv: Use RefStruct API for memory id (mids) array Andreas Rheinhardt
` (6 subsequent siblings)
48 siblings, 1 reply; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-09-19 19:57 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: 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 <andreas.rheinhardt@outlook.com>
---
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(&f->last_picture, si, 0);
+ if (f->fsrc && !(p->flags & AV_FRAME_FLAG_KEY) && f->last_picture.f)
+ ff_thread_progress_await(&f->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(&f->picture, si, 0);
+ ff_thread_progress_report(&f->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 = &f->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, &f->last_picture);
- FFSWAP(ThreadFrame, f->picture, f->last_picture);
-
- f->cur = p = f->picture.f;
+ ff_thread_progress_unref(avctx, &f->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, &keystate)) {
- 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, &f->picture, AV_GET_BUFFER_FLAG_REF);
+ ret = ff_thread_progress_get_buffer(avctx, &f->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 vs. P
+ p->flags = (p->flags & ~AV_FRAME_FLAG_KEY) | key_frame;
+
+ 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;
+ }
+
if (avctx->debug & FF_DEBUG_PICT_INFO)
av_log(avctx, AV_LOG_DEBUG, "ver:%d keyframe:%d coder:%d ec:%d slices:%d bps:%d\n",
f->version, !!(p->flags & AV_FRAME_FLAG_KEY), f->ac, f->ec, f->slice_count, f->avctx->bits_per_raw_sample);
@@ -943,7 +941,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe,
} else v = buf_p - c->bytestream_start;
if (buf_p - c->bytestream_start < v) {
av_log(avctx, AV_LOG_ERROR, "Slice pointer chain broken\n");
- ff_thread_report_progress(&f->picture, INT_MAX, 0);
+ ff_thread_progress_report(&f->picture, INT_MAX);
return AVERROR_INVALIDDATA;
}
buf_p -= v;
@@ -985,11 +983,11 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe,
for (i = f->slice_count - 1; i >= 0; i--) {
FFV1Context *fs = f->slice_context[i];
int j;
- if (fs->slice_damaged && f->last_picture.f->data[0]) {
+ if (fs->slice_damaged && f->last_picture.f) {
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
const uint8_t *src[4];
uint8_t *dst[4];
- ff_thread_await_progress(&f->last_picture, INT_MAX, 0);
+ ff_thread_progress_await(&f->last_picture, INT_MAX);
for (j = 0; j < desc->nb_components; j++) {
int pixshift = desc->comp[j].depth > 8;
int sh = (j == 1 || j == 2) ? f->chroma_h_shift : 0;
@@ -1011,10 +1009,9 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *rframe,
fs->slice_height);
}
}
- ff_thread_report_progress(&f->picture, INT_MAX, 0);
+ ff_thread_progress_report(&f->picture, INT_MAX);
- if (f->last_picture.f)
- ff_thread_release_ext_buffer(avctx, &f->last_picture);
+ ff_thread_progress_unref(avctx, &f->last_picture);
if ((ret = av_frame_ref(rframe, f->picture.f)) < 0)
return ret;
@@ -1056,13 +1053,13 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
{
FFV1Context *fsrc = src->priv_data;
FFV1Context *fdst = dst->priv_data;
- int i, ret;
+ int i;
if (dst == src)
return 0;
{
- ThreadFrame picture = fdst->picture, last_picture = fdst->last_picture;
+ ProgressFrame picture = fdst->picture, last_picture = fdst->last_picture;
uint8_t (*initial_states[MAX_QUANT_TABLES])[32];
struct FFV1Context *slice_context[MAX_SLICES];
memcpy(initial_states, fdst->initial_states, sizeof(fdst->initial_states));
@@ -1084,12 +1081,7 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
av_assert1(fdst->max_slice_count == fsrc->max_slice_count);
-
- ff_thread_release_ext_buffer(dst, &fdst->picture);
- if (fsrc->picture.f->data[0]) {
- if ((ret = ff_thread_ref_frame(&fdst->picture, &fsrc->picture)) < 0)
- return ret;
- }
+ ff_thread_progress_replace(dst, &fdst->picture, &fsrc->picture);
fdst->fsrc = fsrc;
@@ -1101,15 +1093,9 @@ static av_cold int ffv1_decode_close(AVCodecContext *avctx)
{
FFV1Context *const s = avctx->priv_data;
- if (s->picture.f) {
- ff_thread_release_ext_buffer(avctx, &s->picture);
- av_frame_free(&s->picture.f);
- }
+ ff_thread_progress_unref(avctx, &s->picture);
+ ff_thread_progress_unref(avctx, &s->last_picture);
- if (s->last_picture.f) {
- ff_thread_release_ext_buffer(avctx, &s->last_picture);
- av_frame_free(&s->last_picture.f);
- }
return ff_ffv1_close(avctx);
}
@@ -1125,5 +1111,6 @@ 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,
+ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP |
+ FF_CODEC_CAP_USES_PROGRESSFRAMES,
};
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* Re: [FFmpeg-devel] [PATCH 42/42] avcodec/ffv1dec: Switch to ProgressFrames
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 42/42] avcodec/ffv1dec: " Andreas Rheinhardt
@ 2023-11-09 9:56 ` Anton Khirnov
0 siblings, 0 replies; 106+ messages in thread
From: Anton Khirnov @ 2023-11-09 9:56 UTC (permalink / raw)
To: FFmpeg development discussions and patches; +Cc: Andreas Rheinhardt
Quoting Andreas Rheinhardt (2023-09-19 21:57:34)
> 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 <andreas.rheinhardt@outlook.com>
> ---
> libavcodec/ffv1.c | 1 -
> libavcodec/ffv1.h | 4 +--
> libavcodec/ffv1dec.c | 83 +++++++++++++++++++-------------------------
> 3 files changed, 37 insertions(+), 51 deletions(-)
Looks ok
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 43/49] avcodec/qsv: Use RefStruct API for memory id (mids) array
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (41 preceding siblings ...)
2023-09-19 19:57 ` [FFmpeg-devel] [PATCH 42/42] avcodec/ffv1dec: " Andreas Rheinhardt
@ 2023-10-02 18:13 ` Andreas Rheinhardt
2023-10-02 18:13 ` [FFmpeg-devel] [PATCH 44/49] avcodec/rkmppdec: Fix double-free on error Andreas Rheinhardt
` (5 subsequent siblings)
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-10-02 18:13 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
Avoids allocations and therefore error checks and cleanup code;
also avoids indirections.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
Would be nice if someone could test these additional patches;
I only ensured that they compile properly.
Here is current branch (there will be merge conflicts with
vaapi_encode.c and ffv1dec.c when using the patches sent to the ML):
https://github.com/mkver/FFmpeg/commits/refstruct9
libavcodec/qsv.c | 55 +++++++++++++++------------------------
libavcodec/qsv_internal.h | 11 ++++----
libavcodec/qsvdec.c | 3 ++-
libavcodec/qsvenc.c | 3 ++-
4 files changed, 31 insertions(+), 41 deletions(-)
diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
index 7563625627..4f639e33f5 100644
--- a/libavcodec/qsv.c
+++ b/libavcodec/qsv.c
@@ -34,6 +34,7 @@
#include "avcodec.h"
#include "qsv_internal.h"
+#include "refstruct.h"
#define MFX_IMPL_VIA_MASK(impl) (0x0f00 & (impl))
#define QSV_HAVE_USER_PLUGIN !QSV_ONEVPL
@@ -741,20 +742,19 @@ int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs,
return 0;
}
-static void mids_buf_free(void *opaque, uint8_t *data)
+static void mids_buf_free(FFRefStructOpaque opaque, void *obj)
{
- AVBufferRef *hw_frames_ref = opaque;
+ AVBufferRef *hw_frames_ref = opaque.nc;
av_buffer_unref(&hw_frames_ref);
- av_freep(&data);
}
-static AVBufferRef *qsv_create_mids(AVBufferRef *hw_frames_ref)
+static QSVMid *qsv_create_mids(AVBufferRef *hw_frames_ref)
{
AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ref->data;
AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
int nb_surfaces = frames_hwctx->nb_surfaces;
- AVBufferRef *mids_buf, *hw_frames_ref1;
+ AVBufferRef *hw_frames_ref1;
QSVMid *mids;
int i;
@@ -762,35 +762,27 @@ static AVBufferRef *qsv_create_mids(AVBufferRef *hw_frames_ref)
if (!hw_frames_ref1)
return NULL;
- mids = av_calloc(nb_surfaces, sizeof(*mids));
+ mids = ff_refstruct_alloc_ext(nb_surfaces * sizeof(*mids), 0,
+ hw_frames_ref1, mids_buf_free);
if (!mids) {
av_buffer_unref(&hw_frames_ref1);
return NULL;
}
- mids_buf = av_buffer_create((uint8_t*)mids, nb_surfaces * sizeof(*mids),
- mids_buf_free, hw_frames_ref1, 0);
- if (!mids_buf) {
- av_buffer_unref(&hw_frames_ref1);
- av_freep(&mids);
- return NULL;
- }
-
for (i = 0; i < nb_surfaces; i++) {
QSVMid *mid = &mids[i];
mid->handle_pair = (mfxHDLPair*)frames_hwctx->surfaces[i].Data.MemId;
mid->hw_frames_ref = hw_frames_ref1;
}
- return mids_buf;
+ return mids;
}
static int qsv_setup_mids(mfxFrameAllocResponse *resp, AVBufferRef *hw_frames_ref,
- AVBufferRef *mids_buf)
+ QSVMid *mids)
{
AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ref->data;
AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
- QSVMid *mids = (QSVMid*)mids_buf->data;
int nb_surfaces = frames_hwctx->nb_surfaces;
int i;
@@ -811,12 +803,7 @@ static int qsv_setup_mids(mfxFrameAllocResponse *resp, AVBufferRef *hw_frames_re
return AVERROR(ENOMEM);
}
- resp->mids[resp->NumFrameActual + 1] = av_buffer_ref(mids_buf);
- if (!resp->mids[resp->NumFrameActual + 1]) {
- av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual]);
- av_freep(&resp->mids);
- return AVERROR(ENOMEM);
- }
+ resp->mids[resp->NumFrameActual + 1] = ff_refstruct_ref(mids);
return 0;
}
@@ -850,7 +837,7 @@ static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req,
return MFX_ERR_UNSUPPORTED;
}
- ret = qsv_setup_mids(resp, ctx->hw_frames_ctx, ctx->mids_buf);
+ ret = qsv_setup_mids(resp, ctx->hw_frames_ctx, ctx->mids);
if (ret < 0) {
av_log(ctx->logctx, AV_LOG_ERROR,
"Error filling an external frame allocation request\n");
@@ -861,7 +848,8 @@ static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req,
AVHWFramesContext *ext_frames_ctx = (AVHWFramesContext*)ctx->hw_frames_ctx->data;
mfxFrameInfo *i = &req->Info;
- AVBufferRef *frames_ref, *mids_buf;
+ AVBufferRef *frames_ref;
+ QSVMid *mids;
AVHWFramesContext *frames_ctx;
AVQSVFramesContext *frames_hwctx;
@@ -889,14 +877,14 @@ static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req,
return MFX_ERR_MEMORY_ALLOC;
}
- mids_buf = qsv_create_mids(frames_ref);
- if (!mids_buf) {
+ mids = qsv_create_mids(frames_ref);
+ if (!mids) {
av_buffer_unref(&frames_ref);
return MFX_ERR_MEMORY_ALLOC;
}
- ret = qsv_setup_mids(resp, frames_ref, mids_buf);
- av_buffer_unref(&mids_buf);
+ ret = qsv_setup_mids(resp, frames_ref, mids);
+ ff_refstruct_unref(&mids);
av_buffer_unref(&frames_ref);
if (ret < 0) {
av_log(ctx->logctx, AV_LOG_ERROR,
@@ -913,7 +901,7 @@ static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req,
static mfxStatus qsv_frame_free(mfxHDL pthis, mfxFrameAllocResponse *resp)
{
av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual]);
- av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual + 1]);
+ ff_refstruct_unref(&resp->mids[resp->NumFrameActual + 1]);
av_freep(&resp->mids);
return MFX_ERR_NONE;
}
@@ -1105,11 +1093,10 @@ int ff_qsv_init_session_frames(AVCodecContext *avctx, mfxSession *psession,
qsv_frames_ctx->logctx = avctx;
/* allocate the memory ids for the external frames */
- av_buffer_unref(&qsv_frames_ctx->mids_buf);
- qsv_frames_ctx->mids_buf = qsv_create_mids(qsv_frames_ctx->hw_frames_ctx);
- if (!qsv_frames_ctx->mids_buf)
+ ff_refstruct_unref(&qsv_frames_ctx->mids);
+ qsv_frames_ctx->mids = qsv_create_mids(qsv_frames_ctx->hw_frames_ctx);
+ if (!qsv_frames_ctx->mids)
return AVERROR(ENOMEM);
- qsv_frames_ctx->mids = (QSVMid*)qsv_frames_ctx->mids_buf->data;
qsv_frames_ctx->nb_mids = frames_hwctx->nb_surfaces;
err = MFXVideoCORE_SetFrameAllocator(session, &frame_allocator);
diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h
index c2d301b4a2..d970cd20f0 100644
--- a/libavcodec/qsv_internal.h
+++ b/libavcodec/qsv_internal.h
@@ -115,11 +115,12 @@ typedef struct QSVFramesContext {
AVBufferRef *hw_frames_ctx;
void *logctx;
- /* The memory ids for the external frames.
- * Refcounted, since we need one reference owned by the QSVFramesContext
- * (i.e. by the encoder/decoder) and another one given to the MFX session
- * from the frame allocator. */
- AVBufferRef *mids_buf;
+ /**
+ * The memory ids for the external frames.
+ * Refcounted (via the RefStruct API), since we need one reference
+ * owned by the QSVFramesContext (i.e. by the encoder/decoder) and
+ * another one given to the MFX session from the frame allocator.
+ */
QSVMid *mids;
int nb_mids;
} QSVFramesContext;
diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
index da700f25e9..e53d320d0d 100644
--- a/libavcodec/qsvdec.c
+++ b/libavcodec/qsvdec.c
@@ -50,6 +50,7 @@
#include "hwconfig.h"
#include "qsv.h"
#include "qsv_internal.h"
+#include "refstruct.h"
#if QSV_ONEVPL
#include <mfxdispatcher.h>
@@ -875,7 +876,7 @@ static void qsv_decode_close_qsvcontext(QSVContext *q)
ff_qsv_close_internal_session(&q->internal_qs);
av_buffer_unref(&q->frames_ctx.hw_frames_ctx);
- av_buffer_unref(&q->frames_ctx.mids_buf);
+ ff_refstruct_unref(&q->frames_ctx.mids);
av_buffer_pool_uninit(&q->pool);
}
diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c
index a0144b0760..8a607ee5e7 100644
--- a/libavcodec/qsvenc.c
+++ b/libavcodec/qsvenc.c
@@ -41,6 +41,7 @@
#include "qsv.h"
#include "qsv_internal.h"
#include "qsvenc.h"
+#include "refstruct.h"
struct profile_names {
mfxU16 profile;
@@ -2622,7 +2623,7 @@ int ff_qsv_enc_close(AVCodecContext *avctx, QSVEncContext *q)
ff_qsv_close_internal_session(&q->internal_qs);
av_buffer_unref(&q->frames_ctx.hw_frames_ctx);
- av_buffer_unref(&q->frames_ctx.mids_buf);
+ ff_refstruct_unref(&q->frames_ctx.mids);
cur = q->work_frames;
while (cur) {
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 44/49] avcodec/rkmppdec: Fix double-free on error
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (42 preceding siblings ...)
2023-10-02 18:13 ` [FFmpeg-devel] [PATCH 43/49] avcodec/qsv: Use RefStruct API for memory id (mids) array Andreas Rheinhardt
@ 2023-10-02 18:13 ` Andreas Rheinhardt
2023-10-02 18:13 ` [FFmpeg-devel] [PATCH 45/49] avcodec/rkmppdec: Check av_buffer_ref() Andreas Rheinhardt
` (4 subsequent siblings)
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-10-02 18:13 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
After having created the AVBuffer that is put into frame->buf[0],
ownership of several objects (namely an AVDRMFrameDescriptor,
an MppFrame and some AVBufferRefs framecontextref and decoder_ref)
has passed to the AVBuffer and therefore to the frame.
Yet it has nevertheless been freed manually on error
afterwards, which would lead to a double-free as soon
as the AVFrame is unreferenced.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
I hope we have a maintainer (or anyone else) for this who can test
these patches.
libavcodec/rkmppdec.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
index 5768568b00..2ca368e0a9 100644
--- a/libavcodec/rkmppdec.c
+++ b/libavcodec/rkmppdec.c
@@ -462,8 +462,8 @@ static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame)
frame->hw_frames_ctx = av_buffer_ref(decoder->frames_ref);
if (!frame->hw_frames_ctx) {
- ret = AVERROR(ENOMEM);
- goto fail;
+ av_frame_unref(frame);
+ return AVERROR(ENOMEM);
}
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 45/49] avcodec/rkmppdec: Check av_buffer_ref()
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (43 preceding siblings ...)
2023-10-02 18:13 ` [FFmpeg-devel] [PATCH 44/49] avcodec/rkmppdec: Fix double-free on error Andreas Rheinhardt
@ 2023-10-02 18:13 ` Andreas Rheinhardt
2023-10-02 18:13 ` [FFmpeg-devel] [PATCH 46/49] avcodec/rkmppdec: Use RefStruct API for references to decoder itself Andreas Rheinhardt
` (3 subsequent siblings)
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-10-02 18:13 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/rkmppdec.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
index 2ca368e0a9..4cca65d8fb 100644
--- a/libavcodec/rkmppdec.c
+++ b/libavcodec/rkmppdec.c
@@ -449,6 +449,10 @@ static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame)
// MPP decoder needs to be closed only when all frames have been released.
framecontext = (RKMPPFrameContext *)framecontextref->data;
framecontext->decoder_ref = av_buffer_ref(rk_context->decoder_ref);
+ if (!framecontext->decoder_ref) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
framecontext->frame = mppframe;
frame->data[0] = (uint8_t *)desc;
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 46/49] avcodec/rkmppdec: Use RefStruct API for references to decoder itself
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (44 preceding siblings ...)
2023-10-02 18:13 ` [FFmpeg-devel] [PATCH 45/49] avcodec/rkmppdec: Check av_buffer_ref() Andreas Rheinhardt
@ 2023-10-02 18:13 ` Andreas Rheinhardt
2023-10-02 18:13 ` [FFmpeg-devel] [PATCH 47/49] avcodec/rkmppdec: Allocate AVDRMFrameDescriptor and frame ctx jointly Andreas Rheinhardt
` (2 subsequent siblings)
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-10-02 18:13 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
Avoids boilerplate code when creating the context
and avoids allocations and therefore whole error paths
when creating references to it. Also avoids an indirection
and improves type-safety.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/rkmppdec.c | 46 +++++++++++++++----------------------------
1 file changed, 16 insertions(+), 30 deletions(-)
diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
index 4cca65d8fb..dd0b9c5a4d 100644
--- a/libavcodec/rkmppdec.c
+++ b/libavcodec/rkmppdec.c
@@ -30,6 +30,7 @@
#include "codec_internal.h"
#include "decode.h"
#include "hwconfig.h"
+#include "refstruct.h"
#include "libavutil/buffer.h"
#include "libavutil/common.h"
#include "libavutil/frame.h"
@@ -56,12 +57,12 @@ typedef struct {
typedef struct {
AVClass *av_class;
- AVBufferRef *decoder_ref;
+ RKMPPDecoder *decoder; ///< RefStruct reference
} RKMPPDecodeContext;
typedef struct {
MppFrame frame;
- AVBufferRef *decoder_ref;
+ const RKMPPDecoder *decoder_ref; ///< RefStruct reference
} RKMPPFrameContext;
static MppCodingType rkmpp_get_codingtype(AVCodecContext *avctx)
@@ -89,7 +90,7 @@ static uint32_t rkmpp_get_frameformat(MppFrameFormat mppformat)
static int rkmpp_write_data(AVCodecContext *avctx, uint8_t *buffer, int size, int64_t pts)
{
RKMPPDecodeContext *rk_context = avctx->priv_data;
- RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
+ RKMPPDecoder *decoder = rk_context->decoder;
int ret;
MppPacket packet;
@@ -124,13 +125,13 @@ static int rkmpp_write_data(AVCodecContext *avctx, uint8_t *buffer, int size, in
static int rkmpp_close_decoder(AVCodecContext *avctx)
{
RKMPPDecodeContext *rk_context = avctx->priv_data;
- av_buffer_unref(&rk_context->decoder_ref);
+ ff_refstruct_unref(&rk_context->decoder);
return 0;
}
-static void rkmpp_release_decoder(void *opaque, uint8_t *data)
+static void rkmpp_release_decoder(FFRefStructOpaque unused, void *obj)
{
- RKMPPDecoder *decoder = (RKMPPDecoder *)data;
+ RKMPPDecoder *decoder = obj;
if (decoder->mpi) {
decoder->mpi->reset(decoder->ctx);
@@ -145,8 +146,6 @@ static void rkmpp_release_decoder(void *opaque, uint8_t *data)
av_buffer_unref(&decoder->frames_ref);
av_buffer_unref(&decoder->device_ref);
-
- av_free(decoder);
}
static int rkmpp_init_decoder(AVCodecContext *avctx)
@@ -161,19 +160,13 @@ static int rkmpp_init_decoder(AVCodecContext *avctx)
avctx->pix_fmt = AV_PIX_FMT_DRM_PRIME;
// create a decoder and a ref to it
- decoder = av_mallocz(sizeof(RKMPPDecoder));
+ decoder = ff_refstruct_alloc_ext(sizeof(*decoder), 0,
+ NULL, rkmpp_release_decoder);
if (!decoder) {
ret = AVERROR(ENOMEM);
goto fail;
}
-
- rk_context->decoder_ref = av_buffer_create((uint8_t *)decoder, sizeof(*decoder), rkmpp_release_decoder,
- NULL, AV_BUFFER_FLAG_READONLY);
- if (!rk_context->decoder_ref) {
- av_free(decoder);
- ret = AVERROR(ENOMEM);
- goto fail;
- }
+ rk_context->decoder = decoder;
av_log(avctx, AV_LOG_DEBUG, "Initializing RKMPP decoder.\n");
@@ -269,7 +262,7 @@ fail:
static int rkmpp_send_packet(AVCodecContext *avctx, const AVPacket *avpkt)
{
RKMPPDecodeContext *rk_context = avctx->priv_data;
- RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
+ RKMPPDecoder *decoder = rk_context->decoder;
int ret;
// handle EOF
@@ -311,7 +304,7 @@ static void rkmpp_release_frame(void *opaque, uint8_t *data)
RKMPPFrameContext *framecontext = (RKMPPFrameContext *)framecontextref->data;
mpp_frame_deinit(&framecontext->frame);
- av_buffer_unref(&framecontext->decoder_ref);
+ ff_refstruct_unref(&framecontext->decoder_ref);
av_buffer_unref(&framecontextref);
av_free(desc);
@@ -320,7 +313,7 @@ static void rkmpp_release_frame(void *opaque, uint8_t *data)
static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame)
{
RKMPPDecodeContext *rk_context = avctx->priv_data;
- RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
+ RKMPPDecoder *decoder = rk_context->decoder;
RKMPPFrameContext *framecontext = NULL;
AVBufferRef *framecontextref = NULL;
int ret;
@@ -448,11 +441,6 @@ static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame)
// MPP decoder needs to be closed only when all frames have been released.
framecontext = (RKMPPFrameContext *)framecontextref->data;
- framecontext->decoder_ref = av_buffer_ref(rk_context->decoder_ref);
- if (!framecontext->decoder_ref) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
framecontext->frame = mppframe;
frame->data[0] = (uint8_t *)desc;
@@ -463,6 +451,7 @@ static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame)
ret = AVERROR(ENOMEM);
goto fail;
}
+ framecontext->decoder_ref = ff_refstruct_ref(rk_context->decoder);
frame->hw_frames_ctx = av_buffer_ref(decoder->frames_ref);
if (!frame->hw_frames_ctx) {
@@ -487,9 +476,6 @@ fail:
if (mppframe)
mpp_frame_deinit(&mppframe);
- if (framecontext)
- av_buffer_unref(&framecontext->decoder_ref);
-
if (framecontextref)
av_buffer_unref(&framecontextref);
@@ -502,7 +488,7 @@ fail:
static int rkmpp_receive_frame(AVCodecContext *avctx, AVFrame *frame)
{
RKMPPDecodeContext *rk_context = avctx->priv_data;
- RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
+ RKMPPDecoder *decoder = rk_context->decoder;
int ret = MPP_NOK;
AVPacket pkt = {0};
RK_S32 usedslots, freeslots;
@@ -542,7 +528,7 @@ static int rkmpp_receive_frame(AVCodecContext *avctx, AVFrame *frame)
static void rkmpp_flush(AVCodecContext *avctx)
{
RKMPPDecodeContext *rk_context = avctx->priv_data;
- RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
+ RKMPPDecoder *decoder = rk_context->decoder;
int ret = MPP_NOK;
av_log(avctx, AV_LOG_DEBUG, "Flush.\n");
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 47/49] avcodec/rkmppdec: Allocate AVDRMFrameDescriptor and frame ctx jointly
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (45 preceding siblings ...)
2023-10-02 18:13 ` [FFmpeg-devel] [PATCH 46/49] avcodec/rkmppdec: Use RefStruct API for references to decoder itself Andreas Rheinhardt
@ 2023-10-02 18:13 ` Andreas Rheinhardt
2023-10-02 18:13 ` [FFmpeg-devel] [PATCH 48/49] avcodec/v4l2_m2m: Remove redundant av_frame_unref() Andreas Rheinhardt
2023-10-02 18:13 ` [FFmpeg-devel] [PATCH 49/49] avcodec/v4l2_(m2m|buffers): Use RefStruct API for context references Andreas Rheinhardt
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-10-02 18:13 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
Avoids an allocation and therefore one error path.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/rkmppdec.c | 39 +++++++++++++++------------------------
1 file changed, 15 insertions(+), 24 deletions(-)
diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
index dd0b9c5a4d..5998b6edef 100644
--- a/libavcodec/rkmppdec.c
+++ b/libavcodec/rkmppdec.c
@@ -300,12 +300,10 @@ static int rkmpp_send_packet(AVCodecContext *avctx, const AVPacket *avpkt)
static void rkmpp_release_frame(void *opaque, uint8_t *data)
{
AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)data;
- AVBufferRef *framecontextref = (AVBufferRef *)opaque;
- RKMPPFrameContext *framecontext = (RKMPPFrameContext *)framecontextref->data;
+ RKMPPFrameContext *framecontext = opaque;
mpp_frame_deinit(&framecontext->frame);
ff_refstruct_unref(&framecontext->decoder_ref);
- av_buffer_unref(&framecontextref);
av_free(desc);
}
@@ -314,12 +312,9 @@ static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame)
{
RKMPPDecodeContext *rk_context = avctx->priv_data;
RKMPPDecoder *decoder = rk_context->decoder;
- RKMPPFrameContext *framecontext = NULL;
- AVBufferRef *framecontextref = NULL;
int ret;
MppFrame mppframe = NULL;
MppBuffer buffer = NULL;
- AVDRMFrameDescriptor *desc = NULL;
AVDRMLayerDescriptor *layer = NULL;
int mode;
MppFrameFormat mppformat;
@@ -408,11 +403,21 @@ static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame)
// now setup the frame buffer info
buffer = mpp_frame_get_buffer(mppframe);
if (buffer) {
- desc = av_mallocz(sizeof(AVDRMFrameDescriptor));
- if (!desc) {
+ RKMPPFrameContext *framecontext;
+ AVDRMFrameDescriptor *desc;
+ // We allocate the descriptor in buf[0] jointly with a structure
+ // that will allow to hold additional information
+ // for properly releasing MPP frames and decoder.
+ struct {
+ AVDRMFrameDescriptor desc;
+ RKMPPFrameContext framecontext;
+ } *combined_desc = av_mallocz(sizeof(*combined_desc));
+ if (!combined_desc) {
ret = AVERROR(ENOMEM);
goto fail;
}
+ desc = &combined_desc->desc;
+ framecontext = &combined_desc->framecontext;
desc->nb_objects = 1;
desc->objects[0].fd = mpp_buffer_get_fd(buffer);
@@ -431,23 +436,15 @@ static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame)
layer->planes[1].offset = layer->planes[0].pitch * mpp_frame_get_ver_stride(mppframe);
layer->planes[1].pitch = layer->planes[0].pitch;
- // we also allocate a struct in buf[0] that will allow to hold additionnal information
- // for releasing properly MPP frames and decoder
- framecontextref = av_buffer_allocz(sizeof(*framecontext));
- if (!framecontextref) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
-
// MPP decoder needs to be closed only when all frames have been released.
- framecontext = (RKMPPFrameContext *)framecontextref->data;
framecontext->frame = mppframe;
frame->data[0] = (uint8_t *)desc;
frame->buf[0] = av_buffer_create((uint8_t *)desc, sizeof(*desc), rkmpp_release_frame,
- framecontextref, AV_BUFFER_FLAG_READONLY);
+ framecontext, AV_BUFFER_FLAG_READONLY);
if (!frame->buf[0]) {
+ av_free(combined_desc);
ret = AVERROR(ENOMEM);
goto fail;
}
@@ -476,12 +473,6 @@ fail:
if (mppframe)
mpp_frame_deinit(&mppframe);
- if (framecontextref)
- av_buffer_unref(&framecontextref);
-
- if (desc)
- av_free(desc);
-
return ret;
}
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 48/49] avcodec/v4l2_m2m: Remove redundant av_frame_unref()
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (46 preceding siblings ...)
2023-10-02 18:13 ` [FFmpeg-devel] [PATCH 47/49] avcodec/rkmppdec: Allocate AVDRMFrameDescriptor and frame ctx jointly Andreas Rheinhardt
@ 2023-10-02 18:13 ` Andreas Rheinhardt
2023-10-02 18:13 ` [FFmpeg-devel] [PATCH 49/49] avcodec/v4l2_(m2m|buffers): Use RefStruct API for context references Andreas Rheinhardt
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-10-02 18:13 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
This frame will be freed in the next line.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/v4l2_m2m.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/libavcodec/v4l2_m2m.c b/libavcodec/v4l2_m2m.c
index 602efb7a16..bac3eb0588 100644
--- a/libavcodec/v4l2_m2m.c
+++ b/libavcodec/v4l2_m2m.c
@@ -255,7 +255,6 @@ static void v4l2_m2m_destroy_context(void *opaque, uint8_t *context)
if (s->fd >= 0)
close(s->fd);
- av_frame_unref(s->frame);
av_frame_free(&s->frame);
av_packet_unref(&s->buf_pkt);
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread
* [FFmpeg-devel] [PATCH 49/49] avcodec/v4l2_(m2m|buffers): Use RefStruct API for context references
2023-09-19 19:38 [FFmpeg-devel] [PATCH 00/42] New API for reference counting and ThreadFrames Andreas Rheinhardt
` (47 preceding siblings ...)
2023-10-02 18:13 ` [FFmpeg-devel] [PATCH 48/49] avcodec/v4l2_m2m: Remove redundant av_frame_unref() Andreas Rheinhardt
@ 2023-10-02 18:13 ` Andreas Rheinhardt
48 siblings, 0 replies; 106+ messages in thread
From: Andreas Rheinhardt @ 2023-10-02 18:13 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
Avoids allocations and therefore error checks; also avoids
indirections and allows to remove the boilerplate code
for creating an object with a dedicated free function.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/v4l2_buffers.c | 7 +++----
libavcodec/v4l2_buffers.h | 6 +++---
libavcodec/v4l2_m2m.c | 25 +++++++++----------------
libavcodec/v4l2_m2m.h | 5 ++---
4 files changed, 17 insertions(+), 26 deletions(-)
diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
index 2277135699..23474ee143 100644
--- a/libavcodec/v4l2_buffers.c
+++ b/libavcodec/v4l2_buffers.c
@@ -29,6 +29,7 @@
#include <poll.h>
#include "libavcodec/avcodec.h"
#include "libavutil/pixdesc.h"
+#include "refstruct.h"
#include "v4l2_context.h"
#include "v4l2_buffers.h"
#include "v4l2_m2m.h"
@@ -229,7 +230,7 @@ static void v4l2_free_buffer(void *opaque, uint8_t *unused)
ff_v4l2_buffer_enqueue(avbuf);
}
- av_buffer_unref(&avbuf->context_ref);
+ ff_refstruct_unref(&avbuf->context_ref);
}
}
@@ -240,9 +241,7 @@ static int v4l2_buf_increase_ref(V4L2Buffer *in)
if (in->context_ref)
atomic_fetch_add(&in->context_refcount, 1);
else {
- in->context_ref = av_buffer_ref(s->self_ref);
- if (!in->context_ref)
- return AVERROR(ENOMEM);
+ in->context_ref = ff_refstruct_ref(s->self_ref);
in->context_refcount = 1;
}
diff --git a/libavcodec/v4l2_buffers.h b/libavcodec/v4l2_buffers.h
index 3d2ff1b9a5..e35b161309 100644
--- a/libavcodec/v4l2_buffers.h
+++ b/libavcodec/v4l2_buffers.h
@@ -28,7 +28,6 @@
#include <stddef.h>
#include <linux/videodev2.h>
-#include "libavutil/buffer.h"
#include "libavutil/frame.h"
#include "packet.h"
@@ -46,8 +45,9 @@ typedef struct V4L2Buffer {
struct V4L2Context *context;
/* This object is refcounted per-plane, so we need to keep track
- * of how many context-refs we are holding. */
- AVBufferRef *context_ref;
+ * of how many context-refs we are holding.
+ * This pointer is a RefStruct reference. */
+ const struct V4L2m2mContext *context_ref;
atomic_uint context_refcount;
/* keep track of the mmap address and mmap length */
diff --git a/libavcodec/v4l2_m2m.c b/libavcodec/v4l2_m2m.c
index bac3eb0588..007e725b70 100644
--- a/libavcodec/v4l2_m2m.c
+++ b/libavcodec/v4l2_m2m.c
@@ -31,6 +31,7 @@
#include "libavutil/pixdesc.h"
#include "libavutil/imgutils.h"
#include "libavutil/pixfmt.h"
+#include "refstruct.h"
#include "v4l2_context.h"
#include "v4l2_fmt.h"
#include "v4l2_m2m.h"
@@ -246,9 +247,9 @@ int ff_v4l2_m2m_codec_reinit(V4L2m2mContext *s)
return 0;
}
-static void v4l2_m2m_destroy_context(void *opaque, uint8_t *context)
+static void v4l2_m2m_destroy_context(FFRefStructOpaque unused, void *context)
{
- V4L2m2mContext *s = (V4L2m2mContext*)context;
+ V4L2m2mContext *s = context;
ff_v4l2_context_release(&s->capture);
sem_destroy(&s->refsync);
@@ -257,8 +258,6 @@ static void v4l2_m2m_destroy_context(void *opaque, uint8_t *context)
close(s->fd);
av_frame_free(&s->frame);
av_packet_unref(&s->buf_pkt);
-
- av_free(s);
}
int ff_v4l2_m2m_codec_end(V4L2m2mPriv *priv)
@@ -282,7 +281,7 @@ int ff_v4l2_m2m_codec_end(V4L2m2mPriv *priv)
ff_v4l2_context_release(&s->output);
s->self_ref = NULL;
- av_buffer_unref(&priv->context_ref);
+ ff_refstruct_unref(&priv->context);
return 0;
}
@@ -327,17 +326,11 @@ int ff_v4l2_m2m_codec_init(V4L2m2mPriv *priv)
int ff_v4l2_m2m_create_context(V4L2m2mPriv *priv, V4L2m2mContext **s)
{
- *s = av_mallocz(sizeof(V4L2m2mContext));
+ *s = ff_refstruct_alloc_ext(sizeof(**s), 0, NULL,
+ &v4l2_m2m_destroy_context);
if (!*s)
return AVERROR(ENOMEM);
- priv->context_ref = av_buffer_create((uint8_t *) *s, sizeof(V4L2m2mContext),
- &v4l2_m2m_destroy_context, NULL, 0);
- if (!priv->context_ref) {
- av_freep(s);
- return AVERROR(ENOMEM);
- }
-
/* assign the context */
priv->context = *s;
(*s)->priv = priv;
@@ -345,13 +338,13 @@ int ff_v4l2_m2m_create_context(V4L2m2mPriv *priv, V4L2m2mContext **s)
/* populate it */
priv->context->capture.num_buffers = priv->num_capture_buffers;
priv->context->output.num_buffers = priv->num_output_buffers;
- priv->context->self_ref = priv->context_ref;
+ priv->context->self_ref = priv->context;
priv->context->fd = -1;
priv->context->frame = av_frame_alloc();
if (!priv->context->frame) {
- av_buffer_unref(&priv->context_ref);
- *s = NULL; /* freed when unreferencing context_ref */
+ ff_refstruct_unref(&priv->context);
+ *s = NULL; /* freed when unreferencing context */
return AVERROR(ENOMEM);
}
diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
index 04d86d7b92..4ba33dc335 100644
--- a/libavcodec/v4l2_m2m.h
+++ b/libavcodec/v4l2_m2m.h
@@ -62,7 +62,7 @@ typedef struct V4L2m2mContext {
AVFrame *frame;
/* Reference to self; only valid while codec is active. */
- AVBufferRef *self_ref;
+ struct V4L2m2mContext *self_ref;
/* reference back to V4L2m2mPriv */
void *priv;
@@ -71,8 +71,7 @@ typedef struct V4L2m2mContext {
typedef struct V4L2m2mPriv {
AVClass *class;
- V4L2m2mContext *context;
- AVBufferRef *context_ref;
+ V4L2m2mContext *context; ///< RefStruct reference
int num_output_buffers;
int num_capture_buffers;
--
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-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 106+ messages in thread