[vlc-commits] [Git][videolan/vlc][master] 6 commits: frame: use vlc_frame_CopyProperties instead of BlockMetaCopy

Jean-Baptiste Kempf (@jbk) gitlab at videolan.org
Fri Dec 24 08:17:45 UTC 2021



Jean-Baptiste Kempf pushed to branch master at VideoLAN / VLC


Commits:
5a1e47b0 by Thomas Guillem at 2021-12-24T08:00:32+01:00
frame: use vlc_frame_CopyProperties instead of BlockMetaCopy

- - - - -
20b6faa8 by Thomas Guillem at 2021-12-24T08:00:32+01:00
frame: move vlc_frame_CopyProperties to frame.c

Will be needed by the next commit.
No functional changes.

Refs #18762

- - - - -
9287173a by Thomas Guillem at 2021-12-24T08:03:44+01:00
core: add the vlc_ancillary API

Ancillaries can be attached to any vlc_frame_t or picture_t (in next
commits).

Ancillaries can be created from:
 - packetized demuxer modules
 - packetizer modules
 - decoder modules

It can't be created from a non packetized demuxer module since the
attachement to the vlc_frame will be lost by the packetizer module that
will be automatically inserted.

Ancillaries are automatically forwarded from a vlc_frame_t to an other
vlc_frame_t and from a picture_t to an other picture_t. This allow to keep
ancillaries untouched when audio filters or video filters are used (these
filters don't have to know about the ancillary).

Ancillary readers can be either:
 - A decoder module
 - An audio output
 - A video output
 - Any filters

Refs #18762

- - - - -
d453e8f4 by Thomas Guillem at 2021-12-24T08:03:44+01:00
frame: add the ancillary API

Refs #18762

- - - - -
e0b6a09a by Thomas Guillem at 2021-12-24T08:03:44+01:00
picture: use the ancillary API

Fixes #18762

- - - - -
d0547192 by Thomas Guillem at 2021-12-24T08:03:44+01:00
test: test the ancillary API

- - - - -


12 changed files:

- + include/vlc_ancillary.h
- include/vlc_frame.h
- include/vlc_picture.h
- src/Makefile.am
- src/libvlccore.sym
- + src/misc/ancillary.c
- + src/misc/ancillary.h
- src/misc/frame.c
- src/misc/picture.c
- src/misc/picture.h
- test/Makefile.am
- + test/src/misc/ancillary.c


Changes:

=====================================
include/vlc_ancillary.h
=====================================
@@ -0,0 +1,121 @@
+/*****************************************************************************
+ * vlc_ancillary.h: ancillary management functions
+ *****************************************************************************
+ * Copyright (C) 2021 VLC authors and VideoLAN
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef VLC_ANCILLARY_H
+#define VLC_ANCILLARY_H 1
+
+/**
+ * \defgroup ancillary Ancillary
+ * \ingroup input
+ *
+ * Ancillary that can be attached to any vlc_frame_t or picture_t.
+ *
+ * Ancillaries can be created from:
+ *  - packetized demuxer modules,
+ *  - packetizer modules,
+ *  - decoder modules.
+ *
+ *  @warning Ancillaries should not be attached from a non packetized demuxer
+ *  module since the attachment to the vlc_frame will be lost by the packetizer
+ *  module that will be automatically inserted.
+ *
+ * Ancillaries are automatically forwarded from a vlc_frame_t to an other
+ * vlc_frame_t and from a picture_t to an other picture_t. This allow to keep
+ * ancillaries untouched when audio filters or video filters are used (these
+ * filters don't have to know about the ancillary).
+ *
+ * Ancillary readers can be either:
+ *  - A decoder module,
+ *  - An audio output,
+ *  - A video output,
+ *  - A video or audio filter.
+ *
+ * @{
+ * \file
+ * Ancillary definition and functions
+ */
+
+/**
+ * Ancillary opaque struct, refcounted struct that hold user data with a free
+ * callback.
+ */
+struct vlc_ancillary;
+
+/**
+ * ID of an ancillary. Each ancillary user can create its own unique ID via
+ * VLC_ANCILLARY_ID.
+ */
+typedef uint32_t vlc_ancillary_id;
+#define VLC_ANCILLARY_ID(a,b,c,d) VLC_FOURCC(a,b,c,d)
+
+/**
+ * Callback to free an ancillary data
+ */
+typedef void (*vlc_ancillary_free_cb)(void *data);
+
+/**
+ * Create an ancillary
+ *
+ * @param data an opaque ancillary, can't be NULL
+ * @param id id of ancillary
+ * @param free_cb callback to release the data, can be NULL
+ * @return a valid vlc_ancillary pointer or NULL in case of allocation error
+ */
+VLC_API struct vlc_ancillary *
+vlc_ancillary_CreateWithFreeCb(void *data, vlc_ancillary_id id,
+                               vlc_ancillary_free_cb free_cb);
+
+/**
+ * Helper to create an ancillary holding an allocated data
+ */
+static inline struct vlc_ancillary *
+vlc_ancillary_Create(void *data, vlc_ancillary_id id)
+{
+    return vlc_ancillary_CreateWithFreeCb(data, id, free);
+}
+
+/**
+ * Release an ancillary
+ *
+ * If the refcount reachs 0, the free_cb provided by
+ * vlc_ancillary_CreateWithFreeCb() is called.
+ *
+ * @param ancillary ancillary to release
+ */
+VLC_API void
+vlc_ancillary_Release(struct vlc_ancillary *ancillary);
+
+/**
+ * Hold an ancillary
+ *
+ * @param ancillary ancillary to hold
+ * @return the same ancillary
+ */
+VLC_API struct vlc_ancillary *
+vlc_ancillary_Hold(struct vlc_ancillary *ancillary);
+
+VLC_API void *
+vlc_ancillary_GetData(const struct vlc_ancillary *ancillary);
+
+/** @} */
+
+/** @} */
+
+#endif /* VLC_ANCILLARY_H */


=====================================
include/vlc_frame.h
=====================================
@@ -23,6 +23,9 @@
 #ifndef VLC_FRAME_H
 #define VLC_FRAME_H 1
 
+struct vlc_ancillary;
+typedef uint32_t vlc_ancillary_id;
+
 /**
  * \defgroup frame Frames
  * \ingroup input
@@ -131,6 +134,10 @@ struct vlc_frame_t
     vlc_tick_t  i_dts;
     vlc_tick_t  i_length;
 
+    /** Private ancillary struct. Don't use it directly, but use it via
+     * vlc_frame_AttachAncillary() and vlc_frame_GetAncillary(). */
+    struct vlc_ancillary **priv_ancillaries;
+
     const struct vlc_frame_callbacks *cbs;
 };
 
@@ -204,14 +211,44 @@ VLC_API vlc_frame_t *vlc_frame_Realloc(vlc_frame_t *, ssize_t pre, size_t body)
  */
 VLC_API void vlc_frame_Release(vlc_frame_t *frame);
 
-static inline void vlc_frame_CopyProperties( vlc_frame_t *dst, const vlc_frame_t *src )
-{
-    dst->i_flags   = src->i_flags;
-    dst->i_nb_samples = src->i_nb_samples;
-    dst->i_dts     = src->i_dts;
-    dst->i_pts     = src->i_pts;
-    dst->i_length  = src->i_length;
-}
+/**
+ * Attach an ancillary to the frame
+ *
+ * @warning the ancillary will be released only if the frame is allocated from
+ * a vlc_frame Alloc function (vlc_frame_Alloc(), vlc_frame_mmap_Alloc()...).
+ *
+ * @note Several ancillaries can be attached to a frame, but if two ancillaries
+ * are identified by the same ID, only the last one take precedence.
+ *
+ * @param frame the frame to attach an ancillary
+ * @param ancillary ancillary that will be held by the frame, can't be NULL
+ * @return VLC_SUCCESS in case of success, VLC_ENOMEM in case of alloc error
+ */
+VLC_API int
+vlc_frame_AttachAncillary(vlc_frame_t *frame, struct vlc_ancillary *ancillary);
+
+/**
+ * Return the ancillary identified by an ID
+ *
+ * @param id id of ancillary to request
+ * @return the ancillary or NULL if the ancillary for that particular id is
+ * not present
+ */
+VLC_API struct vlc_ancillary *
+vlc_frame_GetAncillary(vlc_frame_t *frame, vlc_ancillary_id id);
+
+/**
+ * Copy frame properties from src to dst
+ *
+ * Copy i_flags, i_nb_samples, i_dts, i_pts, and i_length.
+ *
+ * @note if src has an ancillary, the ancillary will be copied and refcounted
+ * to dst.
+ *
+ * @param dst the frame to copy properties into
+ * @param src the frame to copy properties from
+ */
+VLC_API void vlc_frame_CopyProperties( vlc_frame_t *dst, const vlc_frame_t *src );
 
 /**
  * Duplicates a frame.


=====================================
include/vlc_picture.h
=====================================
@@ -28,6 +28,9 @@
 #include <assert.h>
 #include <vlc_atomic.h>
 
+struct vlc_ancillary;
+typedef uint32_t vlc_ancillary_id;
+
 /**
  * \defgroup picture Generic picture API
  * \ingroup output
@@ -411,6 +414,33 @@ VLC_API void picture_Copy( picture_t *p_dst, const picture_t *p_src );
  */
 VLC_API picture_t *picture_Clone(picture_t *pic);
 
+/**
+ * Attach an ancillary to the picture
+ *
+ * @warning the ancillary will be released only if the picture is created from
+ * picture_New(), and picture_Clone().
+ *
+ * @note Several ancillaries can be attached to a picture, but if two
+ * ancillaries are identified by the same ID, only the last one take
+ * precedence.
+ *
+ * @param pic the picture to attach an ancillary
+ * @param ancillary ancillary that will be held by the frame, can't be NULL
+ * @return VLC_SUCCESS in case of success, VLC_ENOMEM in case of alloc error
+ */
+VLC_API int
+picture_AttachAncillary(picture_t *pic, struct vlc_ancillary *ancillary);
+
+/**
+ * Return the ancillary identified by an ID
+ *
+ * @param id id of ancillary to request
+ * @return the ancillary or NULL if the ancillary for that particular id is
+ * not present
+ */
+VLC_API struct vlc_ancillary *
+picture_GetAncillary(picture_t *pic, vlc_ancillary_id id);
+
 /**
  * This function will export a picture to an encoded bitstream.
  *


=====================================
src/Makefile.am
=====================================
@@ -25,6 +25,7 @@ pluginsinclude_HEADERS = \
 	../include/vlc_access.h \
 	../include/vlc_actions.h \
 	../include/vlc_addons.h \
+	../include/vlc_ancillary.h \
 	../include/vlc_aout.h \
 	../include/vlc_aout_volume.h \
 	../include/vlc_arrays.h \
@@ -359,6 +360,8 @@ libvlccore_la_SOURCES = \
 	text/iso_lang.c \
 	text/iso-639_def.h \
 	misc/actions.c \
+	misc/ancillary.h \
+	misc/ancillary.c \
 	misc/executor.c \
 	misc/md5.c \
 	misc/probe.c \


=====================================
src/libvlccore.sym
=====================================
@@ -29,6 +29,10 @@ aout_FiltersPlay
 aout_FiltersAdjustResampling
 aout_Hold
 aout_Release
+vlc_ancillary_CreateWithFreeCb
+vlc_ancillary_Release
+vlc_ancillary_Hold
+vlc_ancillary_GetData
 vlc_audio_meter_Init
 vlc_audio_meter_Destroy
 vlc_audio_meter_Reset
@@ -41,8 +45,11 @@ vlc_fifo_New
 vlc_fifo_Release
 vlc_fifo_Show
 vlc_frame_Alloc
+vlc_frame_AttachAncillary
+vlc_frame_CopyProperties
 vlc_frame_File
 vlc_frame_FilePath
+vlc_frame_GetAncillary
 vlc_frame_heap_Alloc
 vlc_frame_Init
 vlc_frame_mmap_Alloc
@@ -301,6 +308,7 @@ net_Read
 net_SetCSCov
 net_Write
 NTPtime64
+picture_AttachAncillary
 picture_BlendSubpicture
 picture_Clone
 picture_CopyPixels
@@ -314,6 +322,7 @@ picture_fifo_New
 picture_fifo_IsEmpty
 picture_fifo_Pop
 picture_fifo_Push
+picture_GetAncillary
 picture_New
 picture_NewFromFormat
 picture_NewFromResource


=====================================
src/misc/ancillary.c
=====================================
@@ -0,0 +1,201 @@
+/*****************************************************************************
+ * ancillary.c: ancillary management functions
+ *****************************************************************************
+ * Copyright (C) 2021 VLC authors and VideoLAN
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_atomic.h>
+
+#include "ancillary.h"
+
+struct vlc_ancillary
+{
+    vlc_atomic_rc_t rc;
+
+    vlc_ancillary_id id;
+    void *data;
+    vlc_ancillary_free_cb free_cb;
+};
+
+struct vlc_ancillary *
+vlc_ancillary_CreateWithFreeCb(void *data,
+                               vlc_ancillary_id id,
+                               vlc_ancillary_free_cb free_cb)
+{
+    struct vlc_ancillary *ancillary = malloc(sizeof(*ancillary));
+
+    if (ancillary == NULL)
+        return NULL;
+
+    vlc_atomic_rc_init(&ancillary->rc);
+    ancillary->id = id;
+    ancillary->data = data;
+    ancillary->free_cb = free_cb;
+
+    return ancillary;
+}
+
+void
+vlc_ancillary_Release(struct vlc_ancillary *ancillary)
+{
+    if (vlc_atomic_rc_dec(&ancillary->rc))
+    {
+        if (ancillary->free_cb != NULL)
+            ancillary->free_cb(ancillary->data);
+        free(ancillary);
+    }
+}
+
+struct vlc_ancillary *
+vlc_ancillary_Hold(struct vlc_ancillary *ancillary)
+{
+    vlc_atomic_rc_inc(&ancillary->rc);
+    return ancillary;
+}
+
+void *
+vlc_ancillary_GetData(const struct vlc_ancillary *ancillary)
+{
+    return ancillary->data;
+}
+
+void
+vlc_ancillary_array_Clear(struct vlc_ancillary ***array)
+{
+    if (*array != NULL)
+    {
+        for (struct vlc_ancillary **ancillary = *array;
+             *ancillary != NULL; ancillary++)
+        {
+            vlc_ancillary_Release(*ancillary);
+        }
+
+        free(*array);
+        *array = NULL;
+    }
+}
+
+static size_t
+vlc_ancillary_array_Count(struct vlc_ancillary **array)
+{
+    size_t count = 0;
+    for (struct vlc_ancillary **ancillary = array;
+         *ancillary != NULL; ancillary++)
+    {
+        count++;
+    }
+
+    return count;
+}
+
+int
+vlc_ancillary_array_Dup(struct vlc_ancillary ***dst_arrayp,
+                        struct vlc_ancillary ** const*src_arrayp)
+{
+    if (unlikely(*dst_arrayp != NULL))
+        vlc_ancillary_array_Clear(dst_arrayp);
+
+    if (*src_arrayp == NULL)
+        return VLC_SUCCESS;
+
+    struct vlc_ancillary **src_array = *src_arrayp;
+    size_t count = vlc_ancillary_array_Count(src_array);
+
+    struct vlc_ancillary **dst_array =
+        vlc_alloc(count + 1, sizeof(struct vlc_ancillary *));
+    if (dst_array == NULL)
+        return VLC_ENOMEM;
+
+    for (size_t i = 0; i < count; ++i)
+    {
+        dst_array[i] = vlc_ancillary_Hold(src_array[i]);
+        assert(dst_array[i] != NULL);
+    }
+    dst_array[count] = NULL;
+    *dst_arrayp = dst_array;
+
+    return VLC_SUCCESS;
+}
+
+int
+vlc_ancillary_array_Insert(struct vlc_ancillary ***arrayp,
+                           struct vlc_ancillary *ancillary)
+{
+    /* First case: the array is empty */
+    if (*arrayp == NULL)
+    {
+        struct vlc_ancillary **array = vlc_alloc(2, sizeof(struct vlc_ancillary *));
+        if (array == NULL)
+            return VLC_ENOMEM;
+
+        array[0] = vlc_ancillary_Hold(ancillary);
+        array[1] = NULL;
+
+        *arrayp = array;
+
+        return VLC_SUCCESS;
+    }
+
+    struct vlc_ancillary **array = *arrayp;
+    size_t count = vlc_ancillary_array_Count(array);
+
+    /* Second case: the array has already an ancillary of the same id (very
+     * unlikely) */
+    for (size_t i = 0; i < count; ++i)
+    {
+        if (array[i]->id == ancillary->id)
+        {
+            vlc_ancillary_Release(array[i]);
+            array[i] = vlc_ancillary_Hold(ancillary);
+            return VLC_SUCCESS;
+        }
+    }
+
+    /* Third case: realloc the array to add the new ancillary */
+    array = vlc_reallocarray(array, count + 2, sizeof(struct vlc_ancillary *));
+    if (array == NULL)
+        return VLC_ENOMEM;
+
+    array[count] = vlc_ancillary_Hold(ancillary);
+    array[count + 1] = NULL;
+
+    *arrayp = array;
+
+    return VLC_SUCCESS;
+}
+
+struct vlc_ancillary *
+vlc_ancillary_array_Get(struct vlc_ancillary ** const*arrayp,
+                        vlc_ancillary_id id)
+{
+    if (*arrayp == NULL)
+        return NULL;
+
+    struct vlc_ancillary **array = *arrayp;
+    for (struct vlc_ancillary **ancillary = array;
+         *ancillary != NULL; ancillary++)
+    {
+        if ((*ancillary)->id == id)
+            return *ancillary;
+    }
+    return NULL;
+}


=====================================
src/misc/ancillary.h
=====================================
@@ -0,0 +1,55 @@
+/*****************************************************************************
+ * ancillary.h: helpers to manage ancillaries from a frame or a picture
+ *****************************************************************************
+ * Copyright (C) 2021 VLC authors and VideoLAN
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef VLC_ANCILLARY_INTERNAL_H
+#define VLC_ANCILLARY_INTERNAL_H 1
+
+#include <vlc_ancillary.h>
+
+/*
+ * A NULL terminated array of struct vlc_ancillary *. We don't use a
+ * vlc_vector here in orer to gain few bytes (2 * size_t) for each
+ * ancillary users (each vlc_frame_t/picture_t). Users will likely have one
+ * or zero ancillary so the optimisations of the vlc_vector are not
+ * important here.
+ */
+
+static inline void
+vlc_ancillary_array_Init(struct vlc_ancillary ***array)
+{
+    *array = NULL;
+}
+
+void
+vlc_ancillary_array_Clear(struct vlc_ancillary ***array);
+
+int
+vlc_ancillary_array_Dup(struct vlc_ancillary ***dst_array,
+                        struct vlc_ancillary ** const*src_array);
+
+int
+vlc_ancillary_array_Insert(struct vlc_ancillary ***array,
+                           struct vlc_ancillary *ancillary);
+
+struct vlc_ancillary *
+vlc_ancillary_array_Get(struct vlc_ancillary ** const*array,
+                        vlc_ancillary_id id);
+
+#endif /* VLC_ANCILLARY_INTERNAL_H */


=====================================
src/misc/frame.c
=====================================
@@ -32,9 +32,12 @@
 #include <fcntl.h>
 
 #include <vlc_common.h>
+#include <vlc_atomic.h>
 #include <vlc_frame.h>
 #include <vlc_fs.h>
 
+#include "ancillary.h"
+
 #ifndef NDEBUG
 static void vlc_frame_Check (vlc_frame_t *frame)
 {
@@ -57,6 +60,18 @@ static void vlc_frame_Check (vlc_frame_t *frame)
 # define vlc_frame_Check(b) ((void)(b))
 #endif
 
+void vlc_frame_CopyProperties(vlc_frame_t *restrict dst, const vlc_frame_t *src)
+{
+    vlc_ancillary_array_Dup(&dst->priv_ancillaries,
+                            &src->priv_ancillaries);
+
+    dst->i_flags   = src->i_flags;
+    dst->i_nb_samples = src->i_nb_samples;
+    dst->i_dts     = src->i_dts;
+    dst->i_pts     = src->i_pts;
+    dst->i_length  = src->i_length;
+}
+
 vlc_frame_t *vlc_frame_Init(vlc_frame_t *restrict f, const struct vlc_frame_callbacks *cbs,
                             void *buf, size_t size)
 {
@@ -71,6 +86,7 @@ vlc_frame_t *vlc_frame_Init(vlc_frame_t *restrict f, const struct vlc_frame_call
     f->i_pts =
     f->i_dts = VLC_TICK_INVALID;
     f->i_length = 0;
+    vlc_ancillary_array_Init(&f->priv_ancillaries);
     f->cbs = cbs;
     return f;
 }
@@ -87,16 +103,6 @@ static const struct vlc_frame_callbacks vlc_frame_generic_cbs =
     vlc_frame_generic_Release,
 };
 
-static void BlockMetaCopy( vlc_frame_t *restrict out, const vlc_frame_t *in )
-{
-    out->p_next    = in->p_next;
-    out->i_nb_samples = in->i_nb_samples;
-    out->i_dts     = in->i_dts;
-    out->i_pts     = in->i_pts;
-    out->i_flags   = in->i_flags;
-    out->i_length  = in->i_length;
-}
-
 /** Initial memory alignment of data frame.
  * @note This must be a multiple of sizeof(void*) and a power of two.
  * libavcodec AVX optimizations require at least 32-bytes. */
@@ -138,6 +144,8 @@ void vlc_frame_Release(vlc_frame_t *frame)
     frame->p_next = NULL;
     vlc_frame_Check (frame);
 #endif
+    vlc_ancillary_array_Clear(&frame->priv_ancillaries);
+
     frame->cbs->free(frame);
 }
 
@@ -149,7 +157,10 @@ static vlc_frame_t *vlc_frame_ReallocDup( vlc_frame_t *frame, ssize_t i_prebody,
 
     if( frame->i_buffer > 0 )
         memcpy( p_rea->p_buffer + i_prebody, frame->p_buffer, frame->i_buffer );
-    BlockMetaCopy( p_rea, frame );
+
+    p_rea->p_next = frame->p_next;
+    vlc_frame_CopyProperties( p_rea, frame );
+
     vlc_frame_Release( frame );
     return p_rea;
 }
@@ -502,3 +513,15 @@ vlc_frame_t *vlc_frame_FilePath(const char *path, bool write)
     vlc_close (fd);
     return frame;
 }
+
+int
+vlc_frame_AttachAncillary(vlc_frame_t *frame, struct vlc_ancillary *ancillary)
+{
+    return vlc_ancillary_array_Insert(&frame->priv_ancillaries, ancillary);
+}
+
+struct vlc_ancillary *
+vlc_frame_GetAncillary(vlc_frame_t *frame, vlc_ancillary_id id)
+{
+    return vlc_ancillary_array_Get(&frame->priv_ancillaries, id);
+}


=====================================
src/misc/picture.c
=====================================
@@ -38,6 +38,8 @@
 #include <vlc_image.h>
 #include <vlc_block.h>
 
+#include "ancillary.h"
+
 static void PictureDestroyContext( picture_t *p_picture )
 {
     picture_context_t *ctx = p_picture->context;
@@ -98,6 +100,9 @@ void picture_Reset( picture_t *p_picture )
     p_picture->i_nb_fields = 2;
     p_picture->b_top_field_first = false;
     PictureDestroyContext( p_picture );
+
+    picture_priv_t *priv = container_of(p_picture, picture_priv_t, picture);
+    vlc_ancillary_array_Clear(&priv->ancillaries);
 }
 
 /*****************************************************************************
@@ -220,6 +225,8 @@ static bool picture_InitPrivate(const video_format_t *restrict p_fmt,
     else
         priv->gc.destroy = picture_DestroyDummy;
 
+    vlc_ancillary_array_Init(&priv->ancillaries);
+
     return true;
 }
 
@@ -344,6 +351,7 @@ void picture_Destroy(picture_t *picture)
     picture_priv_t *priv = container_of(picture, picture_priv_t, picture);
     assert(priv->gc.destroy != NULL);
     priv->gc.destroy(picture);
+    vlc_ancillary_array_Clear(&priv->ancillaries);
     free(priv);
 }
 
@@ -395,6 +403,10 @@ void picture_CopyProperties( picture_t *p_dst, const picture_t *p_src )
     p_dst->b_progressive = p_src->b_progressive;
     p_dst->i_nb_fields = p_src->i_nb_fields;
     p_dst->b_top_field_first = p_src->b_top_field_first;
+
+    const picture_priv_t *src_priv = container_of(p_src, picture_priv_t, picture);
+    picture_priv_t *dst_priv = container_of(p_dst, picture_priv_t, picture);
+    vlc_ancillary_array_Dup(&dst_priv->ancillaries, &src_priv->ancillaries);
 }
 
 void picture_CopyPixels( picture_t *p_dst, const picture_t *p_src )
@@ -453,9 +465,27 @@ picture_t *picture_InternalClone(picture_t *picture,
 picture_t *picture_Clone(picture_t *picture)
 {
     picture_t *clone = picture_InternalClone(picture, picture_DestroyClone, picture);
+
+    const picture_priv_t *priv = container_of(picture, picture_priv_t, picture);
+    picture_priv_t *clone_priv = container_of(clone, picture_priv_t, picture);
+    vlc_ancillary_array_Dup(&clone_priv->ancillaries, &priv->ancillaries);
     return clone;
 }
 
+int
+picture_AttachAncillary(picture_t *pic, struct vlc_ancillary *ancillary)
+{
+    picture_priv_t *priv = container_of(pic, picture_priv_t, picture);
+    return vlc_ancillary_array_Insert(&priv->ancillaries, ancillary);
+}
+
+struct vlc_ancillary *
+picture_GetAncillary(picture_t *pic, vlc_ancillary_id id)
+{
+    picture_priv_t *priv = container_of(pic, picture_priv_t, picture);
+    return vlc_ancillary_array_Get(&priv->ancillaries, id);
+}
+
 /*****************************************************************************
  *
  *****************************************************************************/


=====================================
src/misc/picture.h
=====================================
@@ -22,6 +22,7 @@
 #include <stddef.h>
 
 #include <vlc_picture.h>
+struct vlc_ancillary;
 
 typedef struct
 {
@@ -31,6 +32,10 @@ typedef struct
         void (*destroy)(picture_t *);
         void *opaque;
     } gc;
+
+    /** Private ancillary struct. Don't use it directly, but use it via
+     * picture_AttachAncillary() and picture_GetAncillary(). */
+    struct vlc_ancillary **ancillaries;
 } picture_priv_t;
 
 void *picture_Allocate(int *, size_t);


=====================================
test/Makefile.am
=====================================
@@ -23,6 +23,7 @@ check_PROGRAMS = \
 	test_libvlc_renderer_discoverer \
 	test_libvlc_slaves \
 	test_src_config_chain \
+	test_src_misc_ancillary \
 	test_src_misc_variables \
 	test_src_input_stream \
 	test_src_input_stream_fifo \
@@ -103,6 +104,8 @@ test_libvlc_slaves_SOURCES = libvlc/slaves.c
 test_libvlc_slaves_LDADD = $(LIBVLCCORE) $(LIBVLC)
 test_libvlc_meta_SOURCES = libvlc/meta.c
 test_libvlc_meta_LDADD = $(LIBVLCCORE) $(LIBVLC)
+test_src_misc_ancillary_SOURCES = src/misc/ancillary.c
+test_src_misc_ancillary_LDADD = $(LIBVLCCORE) $(LIBVLC)
 test_src_misc_variables_SOURCES = src/misc/variables.c
 test_src_misc_variables_LDADD = $(LIBVLCCORE) $(LIBVLC)
 test_src_config_chain_SOURCES = src/config/chain.c


=====================================
test/src/misc/ancillary.c
=====================================
@@ -0,0 +1,118 @@
+/*****************************************************************************
+ * ancillary.c: test for ancillary
+ *****************************************************************************
+ * Copyright (C) 2021 the VideoLAN team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_frame.h>
+#include <vlc_picture.h>
+#include <vlc_ancillary.h>
+
+#include <assert.h>
+
+static void
+ancillary_free(void *data)
+{
+    assert(strncmp(data, "test", 4) == 0);
+    free(data);
+}
+
+int main( void )
+{
+    vlc_frame_t *frame = vlc_frame_Alloc(1);
+    assert(frame);
+
+    int ret;
+    struct vlc_ancillary *ancillary;
+
+    /* Create and try to attach 3 ancillaries to the frame, only 2 will be
+     * attached. */
+    for (size_t i = 0; i < 3; ++i)
+    {
+        char *data;
+        ret = asprintf(&data, "test%zu", i);
+        assert(ret > 0);
+
+        vlc_ancillary_id id;
+        switch (i)
+        {
+            case 0:
+                /* Check that only one ancillary of the same id is added (the
+                 * last one take precedence). */
+            case 1: id = VLC_ANCILLARY_ID('t','s','t','1'); break;
+            case 2: id = VLC_ANCILLARY_ID('t','s','t','2'); break;
+            default: vlc_assert_unreachable();
+        }
+
+        ancillary = vlc_ancillary_CreateWithFreeCb(data, id, ancillary_free);
+        assert(ancillary);
+
+        ret = vlc_frame_AttachAncillary(frame, ancillary);
+        assert(ret == VLC_SUCCESS);
+        vlc_ancillary_Release(ancillary);
+    }
+
+    /* Check that ancillaries are copied via a vlc_frame_CopyProperties() (done
+     * by vlc_frame_Duplicate()). */
+    vlc_frame_t *copy_frame = vlc_frame_Duplicate(frame);
+    assert(copy_frame);
+    vlc_frame_Release(frame);
+    frame = copy_frame;
+
+    picture_t *picture = picture_New(VLC_CODEC_NV12, 1, 1, 1, 1);
+    assert(picture);
+
+    /* Manually attach both ancillaries to a newly allocated picture. */
+    ancillary = vlc_frame_GetAncillary(frame, VLC_ANCILLARY_ID('t','s','t','1'));
+    assert(ancillary);
+    picture_AttachAncillary(picture, ancillary);
+
+    ancillary = vlc_frame_GetAncillary(frame, VLC_ANCILLARY_ID('t','s','t','2'));
+    assert(ancillary);
+    picture_AttachAncillary(picture, ancillary);
+
+    vlc_frame_Release(frame);
+
+    /* Check that ancillaries are copied via a picture_Clone(). */
+    picture_t *clone = picture_Clone(picture);
+    assert(clone);
+    picture_Release(picture);
+
+    /* Check that ancillaries are copied via a picture_Copy(). */
+    picture_t *copy = picture_New(VLC_CODEC_I420, 1, 1, 1, 1);
+    assert(copy);
+    picture_Copy(copy, clone);
+    picture_Release(clone);
+
+    /* Check that ancillaries are still valid. */
+    ancillary = picture_GetAncillary(copy, VLC_ANCILLARY_ID('t','s','t','1'));
+    assert(ancillary);
+    assert(strcmp("test1", vlc_ancillary_GetData(ancillary)) == 0);
+
+    ancillary = picture_GetAncillary(copy, VLC_ANCILLARY_ID('t','s','t','2'));
+    assert(ancillary);
+    assert(strcmp("test2", vlc_ancillary_GetData(ancillary)) == 0);
+
+    picture_Release(copy);
+
+    return 0;
+}



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/543d402ecbf078f3cdd5293ef80b5f14a6c9665c...d0547192a7f7433f9afc64a81dd7264536558f9e

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/543d402ecbf078f3cdd5293ef80b5f14a6c9665c...d0547192a7f7433f9afc64a81dd7264536558f9e
You're receiving this email because of your account on code.videolan.org.




More information about the vlc-commits mailing list