From patchwork Wed Nov 18 16:52:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Almer X-Patchwork-Id: 23717 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id DA30F44BBEA for ; Wed, 18 Nov 2020 19:01:39 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id BD7B768B60D; Wed, 18 Nov 2020 19:01:39 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-qt1-f194.google.com (mail-qt1-f194.google.com [209.85.160.194]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 1245E6881FE for ; Wed, 18 Nov 2020 19:01:38 +0200 (EET) Received: by mail-qt1-f194.google.com with SMTP id v11so2076462qtq.12 for ; Wed, 18 Nov 2020 09:01:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=UROlOu+LPzbGbxfBVoSIXYr2xYxrFKclT7cnpuyfuP0=; b=ICkzBh1CXrfoZspTDq1+wDl8OoWUmDTfN7fgBoFE4nJVoZKaFdyxDrNV+SjvVD/cbu 89hJYRfcqY6JpKnf2Z/umSdL1h3xcBQcX8sCG5CMyWh79JqHoRjX2zPnQD403WMTouAq ldsJJmPPIbbW9Os14QHSvmqoIXiAP3t4txmQ9eAAY9pRoeqOMUgCdY80H6j3KpKbozbF JMNB6KPB2c9pIGjsLD0k471wcqZUOgFnEnOTvSurBkvkHCKArOgQpCAbSfQOOz1CDKtf xYsKfXEQ4kNttiTW4PhhRighJqAXf0ctyaOKBgWlidjSWwRHi6qQ7Ih/7Pt1m/lHGbFS /fww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=UROlOu+LPzbGbxfBVoSIXYr2xYxrFKclT7cnpuyfuP0=; b=ob9FJiOTjNcmgzNfk/Mupi/n7tnTq5uZD9RPJSVv73YlV4lrO47pakAzxroaVDmFNM WeyeDju8zCQurI9VKPEHZ8AlC9WqKv8jiL0JJxorUNrbQcj93vISlfqza2j8uBYgfmXK /+v9GplVDBf2wGBYCurXvaNIz4WdOAa4PB3VPBGut3sjZrs5Dpokj47RxLLJE6KJhwpF D+/oXXkD67A5XL40aJGaZthadjYFI4lMkVDo+nNr/hMbN7SfmWFZpCesRoDEzddThh2E OJQdysDfZMPspcTRYcwsd1XcXE1Jj0TahWrH2YrbHX6NY8C8BI4wH/KEs0nP8wPqAfB1 gAfQ== X-Gm-Message-State: AOAM531ZpV64szGCm1gM3w3hHrZTD2JAJQy7J2YEVjlNAuHi7gFzdCrd 7E/hAnNcMpXPWFhpedp/PLrPPXNtOYulXw== X-Google-Smtp-Source: ABdhPJyT+dGGrm7m6IslcmZUVSXcVQ+zV0OQs5wwGPiTcvwtEWcY30fM260l7vpn503DXQgABjD+jw== X-Received: by 2002:a37:9dd8:: with SMTP id g207mr5594891qke.294.1605718394317; Wed, 18 Nov 2020 08:53:14 -0800 (PST) Received: from localhost.localdomain ([181.23.91.217]) by smtp.gmail.com with ESMTPSA id f14sm4863788qkk.89.2020.11.18.08.53.12 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Nov 2020 08:53:13 -0800 (PST) From: James Almer To: ffmpeg-devel@ffmpeg.org Date: Wed, 18 Nov 2020 13:52:33 -0300 Message-Id: <20201118165247.4130-5-jamrial@gmail.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201118165247.4130-1-jamrial@gmail.com> References: <20201118165247.4130-1-jamrial@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 04/18] avcodec/avpacket: add a new public AVPacketList API X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" 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 --- 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 --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 */