From patchwork Wed Oct 2 23:04:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Thompson X-Patchwork-Id: 15485 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 9AA4344A2A3 for ; Thu, 3 Oct 2019 02:12:53 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 841A36881D7; Thu, 3 Oct 2019 02:12:53 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wr1-f66.google.com (mail-wr1-f66.google.com [209.85.221.66]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 4C0996881CF for ; Thu, 3 Oct 2019 02:12:52 +0300 (EEST) Received: by mail-wr1-f66.google.com with SMTP id i1so813606wro.4 for ; Wed, 02 Oct 2019 16:12:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jkqxz-net.20150623.gappssmtp.com; s=20150623; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=6pd7Hq2cDGNCPHN/Of2jz0rp0GOogOOGcLg1SdCFRDc=; b=zuVUIMZj4tWUVucI75pr3uY3LupYIpUV8Ci9x4NLZsmhNLZ4tvDBdrSmRREebiuKDB jMQoRGx/Xn8zNdUgBBA1yaoHXdZZZSAgcX9qw/oS1GxP4MwspDAAjSfrUebvl40ZV7eU VptzzDd5IEFbZhsreH9R2GAfZIuBQ8r5Bm9vqe4OOVQcwpfvG9GsCDiGPSN52abWAX3b kmGxYQ1/hf9s/NvTh58oIJ4yrxW6UiAzizDoxmQjPYFFHbo6vxmLjyvOk2kRDAiLME0f KUodPrCNnH6xgE6NgWXUTXCVSL7fAo6Vp0YUebJd8SwuYcJ7iasxDpdFbxWK4851Qn+0 QBXg== 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=6pd7Hq2cDGNCPHN/Of2jz0rp0GOogOOGcLg1SdCFRDc=; b=eaS14VUyZk4JWL9xwboN4BqSrSGgblNv/GoUYNze1qTUdo2EZ/ajh4uTQ0pm+rgAeQ ZejeEu4cqf8RnJ2uYEUj+evWoxBENARx01hGzDDaaOvImThWqxllsdYoz0w+7ZJNZxfo 4Ss9iX7em5Tbhei6087wQLZNbTr4pJWdev1y6Xj44tEVe1InpH7OuRMDX00o8vEqirET xQGgz2fioiV9Q2ojHUmJclaaO43kjWMRCu4ckOYynaSfDK+PpBIBmHbdrxXzA5F0ebmq XIfePkGmliLff3lg5Z8cPiBQ3vRx6PXwSJxEZ5atuY3yia4+z2JU/sTEQeveGUQs/H3j g+2Q== X-Gm-Message-State: APjAAAUCBbIp8hF5JEG1fQLYkOeZxaFo0X6C67kEtVH5ABGVrwFiOG0t Jkd+rU1IEDeTD/G3TAb+Y8CQVJLcqgU= X-Google-Smtp-Source: APXvYqzmF+pJb4Brg2wYbNuLu+uMNXTxJp8r1TpVODMODU9DPgeYwy1kSqyDN2N7hY2lvvb0YFnKbw== X-Received: by 2002:adf:f7c3:: with SMTP id a3mr3385686wrq.275.1570057502652; Wed, 02 Oct 2019 16:05:02 -0700 (PDT) Received: from rywe.jkqxz.net (cpc91242-cmbg18-2-0-cust650.5-4.cable.virginm.net. [82.8.130.139]) by smtp.gmail.com with ESMTPSA id o9sm1489808wrh.46.2019.10.02.16.05.01 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 02 Oct 2019 16:05:01 -0700 (PDT) From: Mark Thompson To: ffmpeg-devel@ffmpeg.org Date: Thu, 3 Oct 2019 00:04:41 +0100 Message-Id: <20191002230453.6462-6-sw@jkqxz.net> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191002230453.6462-1-sw@jkqxz.net> References: <20191002230453.6462-1-sw@jkqxz.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 06/18] cbs: Add support functions for handling unit content references 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" Use the unit type table to determine what we need to do to clone the internals of the unit content when making copies for refcounting or writeability. (This will still fail for units with complex content if they do not have a defined clone function.) Setup and naming from a patch by Andreas Rheinhardt , but with the implementation changed to use the unit type information if possible rather than requiring a codec-specific function. --- I decided against pushing this into the AVBuffer layer for now - there would be new external API in that, and I'm not sure exactly what it would look like. This code can be simplified a lot if that gets revisited in future, though. libavcodec/cbs.c | 172 ++++++++++++++++++++++++++++++++++++++ libavcodec/cbs.h | 29 +++++++ libavcodec/cbs_internal.h | 1 + 3 files changed, 202 insertions(+) diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c index 57f0c2257a..f689221945 100644 --- a/libavcodec/cbs.c +++ b/libavcodec/cbs.c @@ -816,3 +816,175 @@ int ff_cbs_alloc_unit_content2(CodedBitstreamContext *ctx, return 0; } + +static int cbs_clone_unit_content(AVBufferRef **clone_ref, + CodedBitstreamUnit *unit, + const CodedBitstreamUnitTypeDescriptor *desc) +{ + uint8_t *src, *copy; + uint8_t **src_ptr, **copy_ptr; + AVBufferRef **src_buf, **copy_buf; + int err, i; + + av_assert0(unit->content); + src = unit->content; + + copy = av_malloc(desc->content_size); + if (!copy) + return AVERROR(ENOMEM); + + memcpy(copy, src, desc->content_size); + + for (i = 0; i < desc->nb_ref_offsets; i++) { + src_ptr = (uint8_t**)(src + desc->ref_offsets[i]); + src_buf = (AVBufferRef**)(src_ptr + 1); + copy_ptr = (uint8_t**)(copy + desc->ref_offsets[i]); + copy_buf = (AVBufferRef**)(copy_ptr + 1); + + if (!*src_ptr) { + av_assert0(!*src_buf); + continue; + } + if (!*src_buf) { + // We can't handle a non-refcounted pointer here - we don't + // have enough information to handle whatever structure lies + // at the other end of it. + err = AVERROR(EINVAL); + goto fail; + } + + // src_ptr is required to point somewhere inside src_buf. If it + // doesn't, there is a bug somewhere. + av_assert0(*src_ptr >= (*src_buf)->data && + *src_ptr < (*src_buf)->data + (*src_buf)->size); + + *copy_buf = av_buffer_ref(*src_buf); + if (!*copy_buf) { + err = AVERROR(ENOMEM); + goto fail; + } + + err = av_buffer_make_writable(copy_buf); + if (err < 0) { + av_buffer_unref(copy_buf); + goto fail; + } + + *copy_ptr = (*copy_buf)->data + (*src_ptr - (*src_buf)->data); + } + + *clone_ref = av_buffer_create(copy, desc->content_size, + desc->content_free ? desc->content_free : + cbs_default_free_unit_content, + (void*)desc, 0); + if (!*clone_ref) { + err = AVERROR(ENOMEM); + goto fail; + } + + return 0; + +fail: + for (--i; i >= 0; i--) + av_buffer_unref((AVBufferRef**)(copy + desc->ref_offsets[i])); + av_freep(©); + *clone_ref = NULL; + return err; +} + +int ff_cbs_make_unit_refcounted(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + const CodedBitstreamUnitTypeDescriptor *desc; + AVBufferRef *ref; + int err; + + av_assert0(unit->content); + if (unit->content_ref) { + // Already refcounted, nothing to do. + return 0; + } + + desc = cbs_find_unit_type_desc(ctx, unit); + if (!desc) + return AVERROR(ENOSYS); + + switch (desc->content_type) { + case CBS_CONTENT_TYPE_POD: + ref = av_buffer_alloc(desc->content_size); + if (!ref) + return AVERROR(ENOMEM); + memcpy(ref->data, unit->content, desc->content_size); + err = 0; + break; + + case CBS_CONTENT_TYPE_INTERNAL_REFS: + err = cbs_clone_unit_content(&ref, unit, desc); + break; + + case CBS_CONTENT_TYPE_COMPLEX: + if (!desc->content_clone) + return AVERROR_PATCHWELCOME; + err = desc->content_clone(&ref, unit); + break; + + default: + av_assert0(0 && "Invalid content type."); + } + + if (err < 0) + return err; + + unit->content_ref = ref; + unit->content = ref->data; + return 0; +} + +int ff_cbs_make_unit_writable(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + const CodedBitstreamUnitTypeDescriptor *desc; + AVBufferRef *ref; + int err; + + // This can only be applied to refcounted units. + err = ff_cbs_make_unit_refcounted(ctx, unit); + if (err < 0) + return err; + av_assert0(unit->content && unit->content_ref); + + if (av_buffer_is_writable(unit->content_ref)) + return 0; + + desc = cbs_find_unit_type_desc(ctx, unit); + if (!desc) + return AVERROR(ENOSYS); + + switch (desc->content_type) { + case CBS_CONTENT_TYPE_POD: + err = av_buffer_make_writable(&unit->content_ref); + break; + + case CBS_CONTENT_TYPE_INTERNAL_REFS: + err = cbs_clone_unit_content(&ref, unit, desc); + break; + + case CBS_CONTENT_TYPE_COMPLEX: + if (!desc->content_clone) + return AVERROR_PATCHWELCOME; + err = desc->content_clone(&ref, unit); + break; + + default: + av_assert0(0 && "Invalid content type."); + } + if (err < 0) + return err; + + if (desc->content_type != CBS_CONTENT_TYPE_POD) { + av_buffer_unref(&unit->content_ref); + unit->content_ref = ref; + } + unit->content = unit->content_ref->data; + return 0; +} diff --git a/libavcodec/cbs.h b/libavcodec/cbs.h index 42896042c1..1144b9f186 100644 --- a/libavcodec/cbs.h +++ b/libavcodec/cbs.h @@ -399,4 +399,33 @@ void ff_cbs_delete_unit(CodedBitstreamContext *ctx, int position); +/** + * Make the content of a unit refcounted. + * + * If the unit is not refcounted, this will do a deep copy of the unit + * content to new refcounted buffers. + * + * It is not valid to call this function on a unit which does not have + * decomposed content. + */ +int ff_cbs_make_unit_refcounted(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit); + +/** + * Make the content of a unit writable so that internal fields can be + * modified. + * + * If it is known that there are no other references to the content of + * the unit, does nothing and returns success. Otherwise (including the + * case where the unit content is not refcounted), it does a full clone + * of the content (including any internal buffers) to make a new copy, + * and replaces the existing references inside the unit with that. + * + * It is not valid to call this function on a unit which does not have + * decomposed content. + */ +int ff_cbs_make_unit_writable(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit); + + #endif /* AVCODEC_CBS_H */ diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h index 2b83c03408..f91b01a21f 100644 --- a/libavcodec/cbs_internal.h +++ b/libavcodec/cbs_internal.h @@ -61,6 +61,7 @@ typedef struct CodedBitstreamUnitTypeDescriptor { size_t ref_offsets[CBS_MAX_REF_OFFSETS]; void (*content_free)(void *opaque, uint8_t *data); + int (*content_clone)(AVBufferRef **ref, CodedBitstreamUnit *unit); } CodedBitstreamUnitTypeDescriptor; typedef struct CodedBitstreamType {