From patchwork Mon Jul 27 16:32:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Thompson X-Patchwork-Id: 21297 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 0EE8544B627 for ; Mon, 27 Jul 2020 19:33:01 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id F001768B91B; Mon, 27 Jul 2020 19:33:00 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wr1-f42.google.com (mail-wr1-f42.google.com [209.85.221.42]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 25EF868B8A2 for ; Mon, 27 Jul 2020 19:32:50 +0300 (EEST) Received: by mail-wr1-f42.google.com with SMTP id r2so10448788wrs.8 for ; Mon, 27 Jul 2020 09:32:50 -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=69lDmasWXs+nBKGDdrwbBGR38r6lpKRVYX+lIMbskAo=; b=OecmJ8eAStnlljAPaGY5DgMBBT0+ncHjVK0shH2oUuQfT+D5B87jEnPVLryX2gt9pJ OO5ezaCe1S7cDcZ6WQPN0JmnzI4pwK5ktVco6g9Jnvgbtk6XZmAlPE1Seth6y2wGlvjS c57txn/MZR3KIA5ErVP1UfwVxN8R88awD+6i55log0+9cB67lVmZ2v6YhjJZKKbChKWF U36F7sByT6EJ84421ZmuaVBon9cew7VFmc82WYHaIfNWPvsv7RNFJKzEr43/cJ+hcuBd LldorUf+K+iUmfAVHqOjBmKW2lMWT+KLeyJxNf0zvZxMYTquMRWsKZ71xIcbgqu/0Td4 jBhg== 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=69lDmasWXs+nBKGDdrwbBGR38r6lpKRVYX+lIMbskAo=; b=FQ7Et3c3Vpk6MSAYtD5sgpIcMiEK9zxRUrMXZTAe5NS6UjHIKKGGC5Qz4njLtRvoQp irZIKEAY14hDpLBl6L3k/6QT4bNTPq1CRdER8uW6PukBta6Rfnmd4OQIFqfnD4CY3P3B V0E8uSvXLyvKxo/mHUPUDbsPy9x7J8nXJqzPxBfk5Rh6OrLBkW17Ob04rYgKCHB7kgGX zLPgm01EIhOdwKj8ekfDyYZcRwETqILJj/MfMdgNYGElv3umCDKwlexOKi6K5us1QK4D 8+VGjhIArBMNtmWBaNZghEaSpnWRWwUTxnrg9VOl43q/Xv/B54dyl2gRChwH7qgN8ENx V0Pg== X-Gm-Message-State: AOAM530SchpTQ2y3QfT2plpUDS7OjPdn4IMXpAXg+a7qI920rqprFZYT p+wyB6kgvnIOi/kou1DnrdzIBN8h0AM= X-Google-Smtp-Source: ABdhPJzqtgFpqhnV5SolF+i4v5OMw9hn9tGgMQSG96sxLh/OMOYAAXcgCTgSxSHTC5i3ppGm2svs9g== X-Received: by 2002:a5d:4710:: with SMTP id y16mr21782388wrq.189.1595867569145; Mon, 27 Jul 2020 09:32:49 -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 w16sm14706791wrg.95.2020.07.27.09.32.48 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 27 Jul 2020 09:32:48 -0700 (PDT) From: Mark Thompson To: ffmpeg-devel@ffmpeg.org Date: Mon, 27 Jul 2020 17:32:21 +0100 Message-Id: <20200727163237.23371-7-sw@jkqxz.net> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200727163237.23371-1-sw@jkqxz.net> References: <20200727163237.23371-1-sw@jkqxz.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v6 06/22] 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 | 163 ++++++++++++++++++++++++++++++++++++++ libavcodec/cbs.h | 29 +++++++ libavcodec/cbs_internal.h | 1 + 3 files changed, 193 insertions(+) diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c index 61cf8e3466..7c1aa005c2 100644 --- a/libavcodec/cbs.c +++ b/libavcodec/cbs.c @@ -871,3 +871,166 @@ 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_memdup(src, desc->content_size); + if (!copy) + return AVERROR(ENOMEM); + + 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; + } + *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 ea8d942894..3a054aa8f3 100644 --- a/libavcodec/cbs.h +++ b/libavcodec/cbs.h @@ -400,4 +400,33 @@ void ff_cbs_delete_unit(CodedBitstreamFragment *frag, 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 35159f9c5f..d991e1eedf 100644 --- a/libavcodec/cbs_internal.h +++ b/libavcodec/cbs_internal.h @@ -80,6 +80,7 @@ typedef const 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 {