From patchwork Mon May 20 23:02:19 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Thompson X-Patchwork-Id: 13209 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 AE7214473DF for ; Tue, 21 May 2019 02:08:57 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 977B268A833; Tue, 21 May 2019 02:08:57 +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 5359D68A7FD for ; Tue, 21 May 2019 02:08:51 +0300 (EEST) Received: by mail-wr1-f66.google.com with SMTP id f10so959760wre.7 for ; Mon, 20 May 2019 16:08:51 -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=KVvawhdBVvVLh4J2yjARek/hbsORy5rmkFUz3s+YNn8=; b=BqCO8amuJvcvObgmiZ/ph4SfZITM+yHf993oaC+teIh09SY0FmqsDJM0tkO4RuDa6J JX+eYRKlFRO9mZb3cBJDGc0dp03C1VwNy+Aiha2I4GESP8JeLQsjWU+aqLmwwgm1nEaI YVcfvKac/CwdAkUyMCVUJCqT7xjWQL7mkHyPgF6LP6uAGX6uDPTMQsomZqZgOD/Y1lv1 unwmPa5jAx9im68xkUxLTHAqryXfh3GhtWgI4YDDg/ShWWZrcnhb5536TN/6wtBQjIQr BESzzzPbQcGGGkDkQiuYN61gG+YOaQudIdfBOBUA3RmjhS5gc+pxGbJqFJwz05TA8aRl dcNQ== 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=KVvawhdBVvVLh4J2yjARek/hbsORy5rmkFUz3s+YNn8=; b=rDE/LIvanE5lFxoQfoo+EazosnWRtDKZ1cXObt8iGEOkz54JoPnKxaMNBROrfFlV/B 4SZt+oe9Qq6S3GGawCU0tBQSTFpOw2jJ3gdfpsRjEJIiazT4cJDp+sNACK+164eNdd9+ aU7qBbBF6HFx/MCFN5onz205GAhre0HLe60unK+TQit1dw2nIUwGKnnbcFO2n29zMKLw VKiMb9BUhK8PXnQyWY27gGpQv5mwZS1J0Fcvzr7//lZ0c73U6Tz5VzMb+Y+MK8mt+W2n ZWPNKBEkqc3OOKG6stYL6NJ0G5Dca2zcx0S1kc8bzxar/xRpLJStSUFSgQKkukCe72oz sc3Q== X-Gm-Message-State: APjAAAUCGnfRoeOUkQklj7AYVMDKZxN0F/n9EzpNYgG5HLDWlXT1IBXw Yp4ku9B3LiJ9iE4aH/pQG35oPSWd0g0= X-Google-Smtp-Source: APXvYqxhJXtIVp2OQast0U0dIoJPxXBA/wCuFOLz/rE/jZ3rnlm0RML5BH+nMCWDp/P0TYxRHAFFuA== X-Received: by 2002:a5d:554f:: with SMTP id g15mr18997056wrw.318.1558393354178; Mon, 20 May 2019 16:02:34 -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 z14sm13858538wrq.22.2019.05.20.16.02.33 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 20 May 2019 16:02:33 -0700 (PDT) From: Mark Thompson To: ffmpeg-devel@ffmpeg.org Date: Tue, 21 May 2019 00:02:19 +0100 Message-Id: <20190520230224.19221-6-sw@jkqxz.net> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190520230224.19221-1-sw@jkqxz.net> References: <20190520230224.19221-1-sw@jkqxz.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v2 06/11] 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. --- libavcodec/cbs.c | 168 ++++++++++++++++++++++++++++++++++++++ libavcodec/cbs.h | 23 ++++++ libavcodec/cbs_internal.h | 1 + 3 files changed, 192 insertions(+) diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c index 1963d86133..9fc8e1eb47 100644 --- a/libavcodec/cbs.c +++ b/libavcodec/cbs.c @@ -816,3 +816,171 @@ 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; + void **src_ptr, **copy_ptr; + AVBufferRef **src_buf, **copy_buf; + int err, i; + + av_assert0(unit->type == desc->unit_type); + av_assert0(unit->content); + src = unit->content; + + copy = av_malloc(desc->content_size); + if (!copy) { + err = AVERROR(ENOMEM); + goto fail; + } + memcpy(copy, src, desc->content_size); + + for (i = 0; i < desc->nb_ref_offsets; i++) { + src_ptr = (void**)(src + desc->ref_offsets[i]); + src_buf = (AVBufferRef**)(src_ptr + 1); + copy_ptr = (void**)(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((uint8_t*)*src_ptr >= (*src_buf)->data && + (uint8_t*)*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 + + ((uint8_t*)*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) + 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; + + if (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: + 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; + + av_buffer_unref(&unit->content_ref); + 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: + return av_buffer_make_writable(&unit->content_ref); + + 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; + + av_buffer_unref(&unit->content_ref); + unit->content_ref = ref; + unit->content = ref->data; + return 0; +} diff --git a/libavcodec/cbs.h b/libavcodec/cbs.h index 8f764905bd..f5d2dcdb08 100644 --- a/libavcodec/cbs.h +++ b/libavcodec/cbs.h @@ -396,4 +396,27 @@ int 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. + */ +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. + */ +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 439fa7934b..194adc42c1 100644 --- a/libavcodec/cbs_internal.h +++ b/libavcodec/cbs_internal.h @@ -55,6 +55,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 {