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 */
