diff mbox series

[FFmpeg-devel,04/18] avcodec/avpacket: add a new public AVPacketList API

Message ID 20201118165247.4130-5-jamrial@gmail.com
State New
Headers show
Series AVPacketList public API | expand

Checks

Context Check Description
andriy/x86_make success Make finished
andriy/x86_make_fate success Make fate finished

Commit Message

James Almer Nov. 18, 2020, 4:52 p.m. UTC
This implements a FIFO packet buffering API.

All existing fields in the AVPacketList struct are deprecated, and will
be removed eventually. After that, AVPacketList will become an opaque struct.

Signed-off-by: James Almer <jamrial@gmail.com>
---
The most important thing is getting the function signatures right. The
internal implementation can always be changed since AVPacketList will not
be publicly exposed.

I've allowed the pkt parameter in av_packet_list_peek() to be NULL, in
which case the function will behave like an is_empty() function of sorts.
I've also added a flags parameter to put(), get() and peek() for future
extensions. For example, we may want to make them append a packet at the
beginning of the list, and return the one at the end.

 libavcodec/avpacket.c        | 141 +++++++++++++++++++++++++++++++++++
 libavcodec/packet.h          |  88 +++++++++++++++++++++-
 libavcodec/packet_internal.h |  10 +++
 libavcodec/version.h         |   3 +
 4 files changed, 240 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/libavcodec/avpacket.c b/libavcodec/avpacket.c
index c12515cf05..c79200b63b 100644
--- a/libavcodec/avpacket.c
+++ b/libavcodec/avpacket.c
@@ -793,6 +793,147 @@  void avpriv_packet_list_free(PacketListEntry **pkt_buf, PacketListEntry **pkt_bu
     *pkt_buf_end = NULL;
 }
 
+AVPacketList *av_packet_list_alloc(void)
+{
+#if FF_API_PACKET_LIST
+    struct PacketList *pktl;
+#else
+    AVPacketList *pktl;
+#endif
+    pktl = av_mallocz(sizeof(*pktl));
+
+    if (!pktl)
+        return NULL;
+
+    return (AVPacketList *)pktl;
+}
+
+int av_packet_list_put(AVPacketList *list, AVPacket *pkt,
+                       int (*copy)(AVPacket *dst, const AVPacket *src),
+                       int flags)
+{
+    PacketListEntry *pktle = av_mallocz(sizeof(PacketListEntry));
+#if FF_API_PACKET_LIST
+    struct PacketList *pktl = (struct PacketList *)list;
+#else
+    AVPacketList *pktl = list;
+#endif
+    int ret;
+
+    if (!pktle)
+        return AVERROR(ENOMEM);
+
+    if (copy) {
+        ret = copy(&pktle->pkt, pkt);
+        if (ret < 0) {
+            av_free(pktle);
+            return ret;
+        }
+    } else {
+        ret = av_packet_make_refcounted(pkt);
+        if (ret < 0) {
+            av_free(pktle);
+            return ret;
+        }
+        av_packet_move_ref(&pktle->pkt, pkt);
+    }
+
+    if (pktl->head)
+        pktl->tail->next = pktle;
+    else
+        pktl->head = pktle;
+
+    /* Add the packet in the buffered packet list. */
+    pktl->tail = pktle;
+
+    return 0;
+}
+
+int av_packet_list_get(AVPacketList *list, AVPacket *pkt,
+                       int flags)
+{
+    PacketListEntry *pktle;
+#if FF_API_PACKET_LIST
+    struct PacketList *pktl = (struct PacketList *)list;
+#else
+    AVPacketList *pktl = list;
+#endif
+
+    if (!pktl->head)
+        return AVERROR(EAGAIN);
+
+    pktle      = pktl->head;
+    if (pkt)
+        *pkt   = pktle->pkt;
+    else
+        av_packet_unref(&pktle->pkt);
+    pktl->head = pktle->next;
+
+    if (!pktle->next)
+        pktl->tail = NULL;
+
+    av_freep(&pktle);
+
+    return 0;
+}
+
+int av_packet_list_peek(AVPacketList *list, AVPacket *pkt,
+                        int flags)
+{
+    PacketListEntry *pktle;
+#if FF_API_PACKET_LIST
+    struct PacketList *pktl = (struct PacketList *)list;
+#else
+    AVPacketList *pktl = list;
+#endif
+    AVPacket tmp = { 0 };
+    int ret;
+
+    if (!pktl->head)
+        return AVERROR(EAGAIN);
+
+    if (!pkt)
+       return 0;
+
+    pktle = pktl->head;
+    ret = av_packet_ref(&tmp, &pktle->pkt);
+    if (ret < 0)
+        return ret;
+
+    *pkt = tmp;
+
+    return 0;
+}
+
+void av_packet_list_flush(AVPacketList *list)
+{
+#if FF_API_PACKET_LIST
+    struct PacketList *pktl = (struct PacketList *)list;
+#else
+    AVPacketList *pktl = list;
+#endif
+
+    while (pktl->head) {
+        PacketListEntry *pktle = pktl->head;
+        pktl->head = pktle->next;
+        av_packet_unref(&pktle->pkt);
+        av_freep(&pktle);
+    }
+
+    pktl->tail = NULL;
+}
+
+void av_packet_list_free(AVPacketList **plist)
+{
+    AVPacketList *list = *plist;
+
+    if (!list)
+        return;
+
+    av_packet_list_flush(list);
+    av_freep(plist);
+}
+
 int ff_side_data_set_encoder_stats(AVPacket *pkt, int quality, int64_t *error, int error_count, int pict_type)
 {
     uint8_t *side_data;
diff --git a/libavcodec/packet.h b/libavcodec/packet.h
index b9d4c9c2c8..d3c8ba40b5 100644
--- a/libavcodec/packet.h
+++ b/libavcodec/packet.h
@@ -393,10 +393,94 @@  typedef struct AVPacket {
 #endif
 } AVPacket;
 
-typedef struct AVPacketList {
+typedef struct AVPacketList
+#if FF_API_PACKET_LIST
+{
+    /**
+     * @deprecated This field is unused
+     */
+    attribute_deprecated
     AVPacket pkt;
+    /**
+     * @deprecated This field is unused
+     */
+    attribute_deprecated
     struct AVPacketList *next;
-} AVPacketList;
+}
+#endif
+AVPacketList;
+
+/**
+ * Allocate an AVPacketList struct.
+ *
+ * @note The allocated struct must be freed with av_packet_list_free()
+ *
+ * @return A freshly allocated AVPacketList on success, NULL otherwise.
+ */
+AVPacketList *av_packet_list_alloc(void);
+
+/**
+ * Append an AVPacket to an AVPacketList.
+ *
+ * @param ptkl  The list where the packet should be appended.
+ * @param pkt   The packet being appended.
+ * @param copy  A callback to copy the contents of the packet to the list.
+ *              May be null, in which case the packet's reference will be
+ *              moved to the list.
+ * @param flags Currently unused. Must be set to 0.
+ *
+ * @return 0 on success, negative AVERROR value on failure. On failure,
+ *         the packet and the list are unchanged.
+ */
+int av_packet_list_put(AVPacketList *list, AVPacket *pkt,
+                       int (*copy)(AVPacket *dst, const AVPacket *src),
+                       int flags);
+
+/**
+ * Remove the oldest AVPacket in an AVPacketList and return it.
+ *
+ * @param pktl  The list where to fetch a packet from.
+ * @param pkt   Pointer to an AVPacket struct. May be NULL, in which case
+ *              the packet is freed after being removed from the list.
+ * @param flags Currently unused. Must be set to 0.
+ *
+ * @note pkt, if not NULL, will be overwritten completely on success. The
+ *       caller owns the packet and must unref it by itself.
+ *
+ * @return 0 on success. AVERROR(EAGAIN) if the list was empty.
+ */
+int av_packet_list_get(AVPacketList *pktl, AVPacket *pkt, int flags);
+
+/**
+ * Create a new reference to the oldest AVPacket in an AVPacketList and
+ * return it. The list will remain unchanged.
+ *
+ * @param pktl  The list where to fetch a packet from.
+ * @param pkt   Pointer to an AVPacket struct. May be NULL, in which case
+ *              nothing is returned.
+ * @param flags Currently unused. Must be set to 0.
+ *
+ * @note pkt, if not NULL, will be overwritten completely on success. The
+ *       caller owns the packet and must unref it by itself.
+ *
+ * @return 0 on success. AVERROR(EAGAIN) if the list was empty. Another
+           AVERROR code on error.
+ */
+int av_packet_list_peek(AVPacketList *pktl, AVPacket *pkt, int flags);
+
+/**
+ * Empty an AVPacketList, freeing all the packets contained in it.
+ *
+ * @param pktl The AVPacketList to flush.
+ */
+void av_packet_list_flush(AVPacketList *pktl);
+
+/**
+ * Free a previously allocated AVPacketList struct, and everything in it.
+ *
+ * @param pktl Pointer to the AVPacketList to free.
+ */
+void av_packet_list_free(AVPacketList **pktl);
 
 #define AV_PKT_FLAG_KEY     0x0001 ///< The packet contains a keyframe
 #define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted
diff --git a/libavcodec/packet_internal.h b/libavcodec/packet_internal.h
index 33c9513f16..2774d75a7e 100644
--- a/libavcodec/packet_internal.h
+++ b/libavcodec/packet_internal.h
@@ -28,6 +28,16 @@  typedef struct PacketListEntry {
     struct PacketListEntry *next;
 } PacketListEntry;
 
+#if FF_API_PACKET_LIST
+struct PacketList {
+    AVPacketList dummy;
+#else
+struct AVPacketList {
+#endif
+    PacketListEntry *head;
+    PacketListEntry *tail;
+};
+
 /**
  * Append an AVPacket to the list.
  *
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 1585d95777..191206500c 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -147,5 +147,8 @@ 
 #ifndef FF_API_AVPRIV_PUT_BITS
 #define FF_API_AVPRIV_PUT_BITS     (LIBAVCODEC_VERSION_MAJOR < 59)
 #endif
+#ifndef FF_API_PACKET_LIST
+#define FF_API_PACKET_LIST         (LIBAVCODEC_VERSION_MAJOR < 60)
+#endif
 
 #endif /* AVCODEC_VERSION_H */