diff mbox series

[FFmpeg-devel,v3] avutil/frame: add av_frame_replace

Message ID 20220607120247.1666-1-jamrial@gmail.com
State New
Headers show
Series [FFmpeg-devel,v3] avutil/frame: add av_frame_replace | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_armv7_RPi4 success Make finished
andriy/make_fate_armv7_RPi4 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

James Almer June 7, 2022, 12:02 p.m. UTC
Signed-off-by: James Almer <jamrial@gmail.com>
---
 libavutil/frame.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++
 libavutil/frame.h |  13 +++++
 2 files changed, 145 insertions(+)

Comments

Nicolas George June 7, 2022, 12:18 p.m. UTC | #1
James Almer (12022-06-07):
> Signed-off-by: James Almer <jamrial@gmail.com>
> ---
>  libavutil/frame.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++
>  libavutil/frame.h |  13 +++++
>  2 files changed, 145 insertions(+)

I do not like having a new function without anything that uses it. It
results in several cases in a function that is not really useful because
of a small design flaw. Can you update other parts of the code to make
use of the new function?

Regards,
James Almer June 7, 2022, 12:22 p.m. UTC | #2
On 6/7/2022 9:18 AM, Nicolas George wrote:
> James Almer (12022-06-07):
>> Signed-off-by: James Almer <jamrial@gmail.com>
>> ---
>>   libavutil/frame.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++
>>   libavutil/frame.h |  13 +++++
>>   2 files changed, 145 insertions(+)
> 
> I do not like having a new function without anything that uses it. It
> results in several cases in a function that is not really useful because
> of a small design flaw. Can you update other parts of the code to make
> use of the new function?
> 
> Regards,

I did the first time i wrote this function and sent it last August. See
http://ffmpeg.org/pipermail/ffmpeg-devel/2021-August/283448.html
http://ffmpeg.org/pipermail/ffmpeg-devel/2021-August/283449.html

I can rebase them if they don't apply anymore, but either way, Anton 
asked me to resurrect this patch since he intends to use this function too.
Nicolas George June 7, 2022, 12:23 p.m. UTC | #3
James Almer (12022-06-07):
> I did the first time i wrote this function and sent it last August. See
> http://ffmpeg.org/pipermail/ffmpeg-devel/2021-August/283448.html
> http://ffmpeg.org/pipermail/ffmpeg-devel/2021-August/283449.html
> 
> I can rebase them if they don't apply anymore, but either way, Anton asked
> me to resurrect this patch since he intends to use this function too.

Ok, thanks for pointing it, I have no objection then.

Regards,
diff mbox series

Patch

diff --git a/libavutil/frame.c b/libavutil/frame.c
index 4c16488c66..293bf6a437 100644
--- a/libavutil/frame.c
+++ b/libavutil/frame.c
@@ -461,6 +461,138 @@  fail:
     return ret;
 }
 
+int av_frame_replace(AVFrame *dst, const AVFrame *src)
+{
+    int ret = 0;
+
+    if (dst == src)
+        return AVERROR(EINVAL);
+
+    if (!src->buf[0]) {
+        av_frame_unref(dst);
+
+        /* duplicate the frame data if it's not refcounted */
+        if (   src->data[0] || src->data[1]
+            || src->data[2] || src->data[3])
+            return av_frame_ref(dst, src);
+        return 0;
+    }
+
+    dst->format         = src->format;
+    dst->width          = src->width;
+    dst->height         = src->height;
+    dst->nb_samples     = src->nb_samples;
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+    dst->channels       = src->channels;
+    dst->channel_layout = src->channel_layout;
+    if (!av_channel_layout_check(&src->ch_layout)) {
+        av_channel_layout_uninit(&dst->ch_layout);
+        if (src->channel_layout)
+            av_channel_layout_from_mask(&dst->ch_layout, src->channel_layout);
+        else {
+            dst->ch_layout.nb_channels = src->channels;
+            dst->ch_layout.order       = AV_CHANNEL_ORDER_UNSPEC;
+        }
+    } else {
+#endif
+    ret = av_channel_layout_copy(&dst->ch_layout, &src->ch_layout);
+    if (ret < 0)
+        goto fail;
+#if FF_API_OLD_CHANNEL_LAYOUT
+    }
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+
+    wipe_side_data(dst);
+    av_dict_free(&dst->metadata);
+    ret = frame_copy_props(dst, src, 0);
+    if (ret < 0)
+        goto fail;
+
+    /* replace the buffers */
+    for (int i = 0; i < FF_ARRAY_ELEMS(src->buf); i++) {
+        ret = av_buffer_replace(&dst->buf[i], src->buf[i]);
+        if (ret < 0)
+            goto fail;
+    }
+
+    if (src->extended_buf) {
+        if (dst->nb_extended_buf != src->nb_extended_buf) {
+            int nb_extended_buf = FFMIN(dst->nb_extended_buf, src->nb_extended_buf);
+            void *tmp;
+
+            for (int i = nb_extended_buf; i < dst->nb_extended_buf; i++)
+                av_buffer_unref(&dst->extended_buf[i]);
+
+            tmp = av_realloc_array(dst->extended_buf, sizeof(*dst->extended_buf),
+                                   src->nb_extended_buf);
+            if (!tmp) {
+                ret = AVERROR(ENOMEM);
+                goto fail;
+            }
+            dst->extended_buf = tmp;
+            dst->nb_extended_buf = src->nb_extended_buf;
+
+            memset(&dst->extended_buf[nb_extended_buf], 0,
+                   (src->nb_extended_buf - nb_extended_buf) * sizeof(*dst->extended_buf));
+        }
+
+        for (int i = 0; i < src->nb_extended_buf; i++) {
+            ret = av_buffer_replace(&dst->extended_buf[i], src->extended_buf[i]);
+            if (ret < 0)
+                goto fail;
+        }
+    } else if (dst->extended_buf) {
+        for (int i = 0; i < dst->nb_extended_buf; i++)
+            av_buffer_unref(&dst->extended_buf[i]);
+        av_freep(&dst->extended_buf);
+    }
+
+    ret = av_buffer_replace(&dst->hw_frames_ctx, src->hw_frames_ctx);
+    if (ret < 0)
+        goto fail;
+
+    if (dst->extended_data != dst->data)
+        av_freep(&dst->extended_data);
+
+    if (src->extended_data != src->data) {
+        int ch = src->ch_layout.nb_channels;
+
+#if FF_API_OLD_CHANNEL_LAYOUT
+FF_DISABLE_DEPRECATION_WARNINGS
+        if (!ch) {
+            ch = src->channels;
+            CHECK_CHANNELS_CONSISTENCY(src);
+        }
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+        if (!ch) {
+            ret = AVERROR(EINVAL);
+            goto fail;
+        }
+
+        if (ch > SIZE_MAX / sizeof(*dst->extended_data))
+            goto fail;
+
+        dst->extended_data = av_memdup(src->extended_data, sizeof(*dst->extended_data) * ch);
+        if (!dst->extended_data) {
+            ret = AVERROR(ENOMEM);
+            goto fail;
+        }
+    } else
+        dst->extended_data = dst->data;
+
+    memcpy(dst->data,     src->data,     sizeof(src->data));
+    memcpy(dst->linesize, src->linesize, sizeof(src->linesize));
+
+    return 0;
+
+fail:
+    av_frame_unref(dst);
+    return ret;
+}
+
 AVFrame *av_frame_clone(const AVFrame *src)
 {
     AVFrame *ret = av_frame_alloc();
diff --git a/libavutil/frame.h b/libavutil/frame.h
index 33fac2054c..e5c10e2b66 100644
--- a/libavutil/frame.h
+++ b/libavutil/frame.h
@@ -752,6 +752,19 @@  void av_frame_free(AVFrame **frame);
  */
 int av_frame_ref(AVFrame *dst, const AVFrame *src);
 
+/**
+ * Ensure the destination frame refers to the same data described by the source
+ * frame by creating a new reference for each AVBufferRef from src if they
+ * differ from those in dst, or if src is not reference counted, by allocating
+ * new buffers and copying data.
+ *
+ * Frame properties on dst will be replaced by those from src.
+ *
+ * @return 0 on success, a negative AVERROR on error. On error, dst is
+ *         unreferenced.
+ */
+int av_frame_replace(AVFrame *dst, const AVFrame *src);
+
 /**
  * Create a new frame that references the same data as src.
  *