From patchwork Sun Feb 23 23:41:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Thompson X-Patchwork-Id: 17891 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 2B82F44A08D for ; Mon, 24 Feb 2020 01:49:44 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 16D1D68B522; Mon, 24 Feb 2020 01:49:44 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-ed1-f65.google.com (mail-ed1-f65.google.com [209.85.208.65]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id A0E1868B501 for ; Mon, 24 Feb 2020 01:49:42 +0200 (EET) Received: by mail-ed1-f65.google.com with SMTP id p23so9824687edr.5 for ; Sun, 23 Feb 2020 15:49:42 -0800 (PST) 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=XeXZBFcDdRMLZwBGw4+b3CTcExYjFYyEhJHooMC7UE8=; b=j8MI5jP3K9s8FokbSzGry8H1R7UHr3JOUOO6ops6jb2rJvVkOl4kvNEdbFkb7aOffP 452Uz1LVgJhBY5m8vIhpbT5t0NC0BtA4dRAUVoXeg8/EdcjQEd8yBW2QiroO2+c2vtLU qJX0vuHsDgms35z9US+G9u5FnvP2wmoPr9V8iCErM3IQMlBEfSwyqDbjUzuJ5secHq/3 Jd48Rp3BachIutClAdW5FA0nLxxYb9xxBqmsByMZsPS+1GS3BUYSBJl+DIS25xUaGnA6 v9ty0yIitTlPzjNEWynvi6ewnZmo9KCJvCsLJe4OXjR4Js+0umBPS4iug25zPZNWfFGY 53Cg== 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=XeXZBFcDdRMLZwBGw4+b3CTcExYjFYyEhJHooMC7UE8=; b=NT9rrJGRdKE3v2WjF/CLVEHrFfEpUl9AUxHx0xhGbCxQ4Odqx004mLNUxyllQdbBjY qp6X3g3+W/GDj1eCWQDIRVsv9UShzUJblGLf86b9DXQvtpRKymE4CW7FVFJ8GZg7am1M I3uoRxp6q9g1UReQRZct/3GnsuKcsP48K8Ao3wJIs80T+ZQohETNvKnLJL2ENPoMmHIM PtXQkEUwPlwqXDIfHMIApyWkM6NsdrI4TmoDpc88bbZTDMJ1gO1dMpRjBw4huISIMVvB SzXtgORyIaTo0X3zXZM7qLZNyQwmhzoYdHlIjFbJRQ/kSXz3ycRaBL2g/OqdpEMPPhOF QNiQ== X-Gm-Message-State: APjAAAXY5TGwFmPycW3CYd6xTl/7WpIVNAIyAjSzKXnNgvWihuzm4IwF BDlNR9AZ4CmlAYFbVhHLvBXPWFjuzGk= X-Google-Smtp-Source: APXvYqzYPkNrjtSTMnz3i8QvS961m67MUyzTnd2CKiJKmmbTWMfxoUcA+qv30gyWXeH6bnGTj7Q2fQ== X-Received: by 2002:a5d:410e:: with SMTP id l14mr59939087wrp.238.1582501298950; Sun, 23 Feb 2020 15:41:38 -0800 (PST) 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 y131sm16358070wmc.13.2020.02.23.15.41.38 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 23 Feb 2020 15:41:38 -0800 (PST) From: Mark Thompson To: ffmpeg-devel@ffmpeg.org Date: Sun, 23 Feb 2020 23:41:09 +0000 Message-Id: <20200223234124.17689-6-sw@jkqxz.net> X-Mailer: git-send-email 2.25.0 In-Reply-To: <20200223234124.17689-1-sw@jkqxz.net> References: <20200223234124.17689-1-sw@jkqxz.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v4 06/21] 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 | 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 6cc559e545..91788f6dfb 100644 --- a/libavcodec/cbs.c +++ b/libavcodec/cbs.c @@ -881,3 +881,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 2a5959a2b0..eb7f4b878b 100644 --- a/libavcodec/cbs.h +++ b/libavcodec/cbs.h @@ -407,4 +407,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 2922878ed0..6fee4e90a5 100644 --- a/libavcodec/cbs_internal.h +++ b/libavcodec/cbs_internal.h @@ -79,6 +79,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 {