From patchwork Fri Apr 12 11:35:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 48016 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:670b:b0:1a9:af23:56c1 with SMTP id wh11csp202587pzb; Fri, 12 Apr 2024 04:36:44 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCXpOlORt73yBtmawELs7fwsxfKwFtVn3E/d/iqZeBsk9z9CtdbT2MHAtor9bzhlFzzv5hXqxgIK4bOMfCl7WyCMghdI6rdlfRzvfA== X-Google-Smtp-Source: AGHT+IEpiIfdql2mW1U6itxoQmgSldL+8vIYbyV7kBoCqlDC9nJdL7umPHb27rz6NIbit/NROHTN X-Received: by 2002:a2e:8695:0:b0:2d8:a921:dfc1 with SMTP id l21-20020a2e8695000000b002d8a921dfc1mr1480899lji.20.1712921804546; Fri, 12 Apr 2024 04:36:44 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1712921804; cv=none; d=google.com; s=arc-20160816; b=Hej2Wf+M4fYnDDLqpgqTa0ZANltUn016AsAQsg6ZmiMZUE3xX9BeyKxHQ7bha9qKsb hT+qjGeTMq/5+04mrs66pFYGWQKHZKQ/aX3Cx/wMCrQgCcbyqRHeJ0vTfRnrW9rKiRKk GgFUgBOFyC8wZgloiftG6un7MG9B4eMWlUWOqPNPUKhJb5crTc0wWAGv+sUz6w7tte+E ml8uZ4ywr67Vbd283DSWJIxsp1zlvptquz1cbp2JCzi6hDmTPUBz9EUA9VEBEgLvnZpm fL5CTIoDlZ0iYqC4PpEYmTODgG+y4IwS2L6Jjbn16NFGOXBeayFzqhZRlmIGY3iCIoYv IiJA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=8MFzb7DYSRrTcDTz73+cEaqTN/o4fv1z2/PBhx2iyqo=; fh=xmAeKtysnShNOmkhiJmYkS30uw4Fu2hvBJ7qlIwukxQ=; b=FdxYTd8uBmBOmqHh5815BhSlBhFPa5b1230heEa0NG6Bt7XL+48YLwj5LUMIeqxt3J WURnNm4ToqlYbHO7oRs8qojeumCibW5CkfSSGmEiFrDtqVdKJSwkrprQaGXtDvZozMi0 9SpK8g6WnaueefCYjQu9Rtu7yZ1Gp4/DZ6Kz9hRxRzXTLjtS7waztg0ocWKYG8DIJDb3 fda4YFWy5Go05Fwf9UQ0FiJmBX8D32/e+yzsmlKKGJc37rWbNx4MDLQpXlVN4I3lC5lT 7v96LT+fvDrJhP+bqP6dJwdw0htvkAR0xzcqLlJQ/Oqng9FuRmCqBeaMWC8HKXoz5k84 uiCA==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=Xprs4CGK; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id c20-20020a2ea794000000b002d80e20ecd9si937268ljf.564.2024.04.12.04.36.44; Fri, 12 Apr 2024 04:36:44 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=Xprs4CGK; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 78C8068D27A; Fri, 12 Apr 2024 14:36:31 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 5A18E68CD7D for ; Fri, 12 Apr 2024 14:36:23 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1712921783; bh=hdln+QZJ5ouT2yQUp1pyMnW7xAhS3CahXN9KWtz1r8Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Xprs4CGKDOccNEywmk8dTnPIxzcOhjGGob6+fm1v8Q7W7Bavh3Mg0RnnM6lO7UsRr SBd0jUQlZlBtrPpudO93mSmVZqKw7hRFmATW+tBpZXIGl3IlvfeqlevD/IyzKpNeiy KtaKjiQR4CKEmKpv66daNUTcFqGyzDDvS2vAeYQo= Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id 16C6942850; Fri, 12 Apr 2024 13:36:23 +0200 (CEST) From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Fri, 12 Apr 2024 13:35:15 +0200 Message-ID: <20240412113620.84013-2-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240412113620.84013-1-ffmpeg@haasn.xyz> References: <20240412113620.84013-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 01/13] avcodec/dovi_rpu: store entire config record X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: CnAdmLboSPh+ From: Niklas Haas And make it public. For encoding, users may also be interested in the configured level and compatibility ID. So generalize the dv_profile field and just expose the whole configuration record. This makes the already rather reductive ff_dovi_update_cfg() function almost wholly redundant, since users can just directly assign DOVIContext.cfg. --- libavcodec/av1dec.c | 6 +++--- libavcodec/dovi_rpu.c | 16 ++++------------ libavcodec/dovi_rpu.h | 21 ++++++++++++--------- libavcodec/hevcdec.c | 13 ++++++------- libavcodec/libdav1d.c | 6 +++--- 5 files changed, 28 insertions(+), 34 deletions(-) diff --git a/libavcodec/av1dec.c b/libavcodec/av1dec.c index 824725c031..4c1405df77 100644 --- a/libavcodec/av1dec.c +++ b/libavcodec/av1dec.c @@ -888,10 +888,10 @@ static av_cold int av1_decode_init(AVCodecContext *avctx) } s->dovi.logctx = avctx; - s->dovi.dv_profile = 10; // default for AV1 + s->dovi.cfg.dv_profile = 10; // default for AV1 sd = ff_get_coded_side_data(avctx, AV_PKT_DATA_DOVI_CONF); - if (sd && sd->size > 0) - ff_dovi_update_cfg(&s->dovi, (AVDOVIDecoderConfigurationRecord *) sd->data); + if (sd && sd->size >= sizeof(s->dovi.cfg)) + s->dovi.cfg = *(AVDOVIDecoderConfigurationRecord *) sd->data; return ret; } diff --git a/libavcodec/dovi_rpu.c b/libavcodec/dovi_rpu.c index 9f7a6b0066..d95c7e03af 100644 --- a/libavcodec/dovi_rpu.c +++ b/libavcodec/dovi_rpu.c @@ -64,7 +64,7 @@ void ff_dovi_ctx_flush(DOVIContext *s) *s = (DOVIContext) { .logctx = s->logctx, - .dv_profile = s->dv_profile, + .cfg = s->cfg, /* preserve temporary buffer */ .rpu_buf = s->rpu_buf, .rpu_buf_sz = s->rpu_buf_sz, @@ -74,22 +74,14 @@ void ff_dovi_ctx_flush(DOVIContext *s) void ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0) { s->logctx = s0->logctx; + s->cfg = s0->cfg; s->mapping = s0->mapping; s->color = s0->color; - s->dv_profile = s0->dv_profile; for (int i = 0; i <= DOVI_MAX_DM_ID; i++) ff_refstruct_replace(&s->vdr[i], s0->vdr[i]); ff_refstruct_replace(&s->ext_blocks, s0->ext_blocks); } -void ff_dovi_update_cfg(DOVIContext *s, const AVDOVIDecoderConfigurationRecord *cfg) -{ - if (!cfg) - return; - - s->dv_profile = cfg->dv_profile; -} - int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame) { AVFrameSideData *sd; @@ -392,7 +384,7 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, goto fail; /* Container */ - if (s->dv_profile == 10 /* dav1.10 */) { + if (s->cfg.dv_profile == 10 /* dav1.10 */) { /* DV inside AV1 re-uses an EMDF container skeleton, but with fixed * values - so we can effectively treat this as a magic byte sequence. * @@ -517,7 +509,7 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, use_prev_vdr_rpu = get_bits1(gb); use_nlq = (hdr->rpu_format & 0x700) == 0 && !hdr->disable_residual_flag; - profile = s->dv_profile ? s->dv_profile : guess_profile(hdr); + profile = s->cfg.dv_profile ? s->cfg.dv_profile : guess_profile(hdr); if (profile == 5 && use_nlq) { av_log(s->logctx, AV_LOG_ERROR, "Profile 5 RPUs should not use NLQ\n"); goto fail; diff --git a/libavcodec/dovi_rpu.h b/libavcodec/dovi_rpu.h index 9f26f332ce..9a68e45bf1 100644 --- a/libavcodec/dovi_rpu.h +++ b/libavcodec/dovi_rpu.h @@ -31,6 +31,16 @@ typedef struct DOVIContext { void *logctx; + /** + * Currently active dolby vision configuration, or {0} for none. + * Set by the user when decoding. + * + * Note: sizeof(cfg) is not part of the libavutil ABI, so users should + * never pass &cfg to any other library calls. This is included merely as + * a way to look up the values of fields known at compile time. + */ + AVDOVIDecoderConfigurationRecord cfg; + /** * Currently active RPU data header, updates on every dovi_rpu_parse(). */ @@ -56,7 +66,6 @@ typedef struct DOVIContext { struct DOVIVdr *vdr[DOVI_MAX_DM_ID+1]; ///< RefStruct references uint8_t *rpu_buf; ///< temporary buffer unsigned rpu_buf_sz; - uint8_t dv_profile; } DOVIContext; @@ -68,17 +77,11 @@ void ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0); void ff_dovi_ctx_unref(DOVIContext *s); /** - * Partially reset the internal state. Resets per-frame state while preserving - * fields parsed from the configuration record. + * Partially reset the internal state. Resets per-frame state, but preserves + * the stream-wide configuration record. */ void ff_dovi_ctx_flush(DOVIContext *s); -/** - * Read the contents of an AVDOVIDecoderConfigurationRecord (usually provided - * by stream side data) and update internal state accordingly. - */ -void ff_dovi_update_cfg(DOVIContext *s, const AVDOVIDecoderConfigurationRecord *cfg); - /** * Parse the contents of a Dovi RPU NAL and update the parsed values in the * DOVIContext struct. diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c index 007eae6a1e..7825efe2e6 100644 --- a/libavcodec/hevcdec.c +++ b/libavcodec/hevcdec.c @@ -3365,14 +3365,13 @@ static int hevc_decode_frame(AVCodecContext *avctx, AVFrame *rframe, } sd = av_packet_get_side_data(avpkt, AV_PKT_DATA_DOVI_CONF, &sd_size); - if (sd && sd_size > 0) { - int old = s->dovi_ctx.dv_profile; - - ff_dovi_update_cfg(&s->dovi_ctx, (AVDOVIDecoderConfigurationRecord *) sd); + if (sd && sd_size >= sizeof(s->dovi_ctx.cfg)) { + int old = s->dovi_ctx.cfg.dv_profile; + s->dovi_ctx.cfg = *(AVDOVIDecoderConfigurationRecord *) sd; if (old) av_log(avctx, AV_LOG_DEBUG, "New DOVI configuration record from input packet (profile %d -> %u).\n", - old, s->dovi_ctx.dv_profile); + old, s->dovi_ctx.cfg.dv_profile); } s->ref = s->collocated_ref = NULL; @@ -3666,8 +3665,8 @@ static av_cold int hevc_decode_init(AVCodecContext *avctx) } sd = ff_get_coded_side_data(avctx, AV_PKT_DATA_DOVI_CONF); - if (sd && sd->size > 0) - ff_dovi_update_cfg(&s->dovi_ctx, (AVDOVIDecoderConfigurationRecord *) sd->data); + if (sd && sd->size >= sizeof(s->dovi_ctx.cfg)) + s->dovi_ctx.cfg = *(AVDOVIDecoderConfigurationRecord *) sd->data; } return 0; diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c index 93c77ed9c6..09fe767fb8 100644 --- a/libavcodec/libdav1d.c +++ b/libavcodec/libdav1d.c @@ -290,10 +290,10 @@ static av_cold int libdav1d_init(AVCodecContext *c) #endif dav1d->dovi.logctx = c; - dav1d->dovi.dv_profile = 10; // default for AV1 + dav1d->dovi.cfg.dv_profile = 10; // default for AV1 sd = ff_get_coded_side_data(c, AV_PKT_DATA_DOVI_CONF); - if (sd && sd->size > 0) - ff_dovi_update_cfg(&dav1d->dovi, (AVDOVIDecoderConfigurationRecord *) sd->data); + if (sd && sd->size >= sizeof(dav1d->dovi.cfg)) + dav1d->dovi.cfg = *(AVDOVIDecoderConfigurationRecord *) sd->data; return 0; } From patchwork Fri Apr 12 11:35:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 48017 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:670b:b0:1a9:af23:56c1 with SMTP id wh11csp202658pzb; Fri, 12 Apr 2024 04:36:54 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCXFAXAC46mLU7ULABfWW5gVlU/uQiBbp8qzocjHqW+L7Al7k7D2W39rPNKjvqnOtPfGFXkWm5SbM0mtiYV8+qNbX0yTyK5Pl1YewQ== X-Google-Smtp-Source: AGHT+IEVRCpjojqna3mWurTN+BVfkd19HQZQZLex6LVy0dm9xiWdLN4rQ7aI43O71fd0I2eEnbYP X-Received: by 2002:a2e:a40c:0:b0:2d4:7458:b65 with SMTP id p12-20020a2ea40c000000b002d474580b65mr1385429ljn.2.1712921814110; Fri, 12 Apr 2024 04:36:54 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1712921814; cv=none; d=google.com; s=arc-20160816; b=w58eg4vLLA6EYzle+g3mssaSgmq65mcNq+IZ40f3L9hE3aYARlapoJjgkEWmZhEBOZ FyTPRFABL3IW1i7wS7RFwApzDDxodw8cwIqfSfACZ4ryZ7y6WwBTjNd8hPqRmR25O+zy XUBXVLhJDXsHhPrhQgk50+fUku2hK5W2+MvC/eEoQ+Aj2GpoeAy0J45fjST4AeB6uRvB XydYsJx4G0NnLZfw1J7g81Dp/RhxWUL9JYR7Mv1OTQV88ab3QyRO0D/PRoxwKbJ1rTAR Cq0GFMUngCY5ze5d0vdLZvQcHsNxONFcEuQzqp1N3A/oQu1wp1SDbZOnphhNf5mwKRg0 HumA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=JGMOAFPZ9M8unWDs46Mv3GatS2CWqVQ4XobxdI7oJ2A=; fh=xmAeKtysnShNOmkhiJmYkS30uw4Fu2hvBJ7qlIwukxQ=; b=QBoTtgSUs5Q2M7h7uy5olFZl3jWlUrkZNTgTuaMj8AgbzSuboaVFiskO5qKOFd75qI Dxfakpd4L9sDQ/Dso4MRf/P1PZkreQesigV34lWz2HOhKq8nKCHHXeXDQ0frqVkAFo8l /c/O5sgKnEU+qa4iAsnxbDQm8jSTjkq0YDwSqHp92bS3eOiZrq5wW/7y3KKtyBkqUbKn HuSuJxxLOy5jlmtNbazGFWtbB+nNcV8ikDqNEqsMtWOeb0hP/q85X1RqykdDqYjFZIYO lREjT1i8buUTCLBGyo7G6HkWHf6rLkztGdTgpIc88P1feF5/7sYH/KkSYIYETJPQdL4/ JKYg==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=TP7bANcC; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id z2-20020a2e8e82000000b002d851a56324si968494ljk.458.2024.04.12.04.36.53; Fri, 12 Apr 2024 04:36:54 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=TP7bANcC; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 921D568D27E; Fri, 12 Apr 2024 14:36:32 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 99F5868CD7D for ; Fri, 12 Apr 2024 14:36:23 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1712921783; bh=G8uDMX883yMmunPnB1IhhiAPfCY9X6Q6RNZWUEXJ824=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TP7bANcCZSs+0cU7cJYUC6LjTCcxgIlLT98q0RPg11pH8UCKguEcQkp5iDbzIlSU+ qa4d0skPp9rcOxhf1keOpvOdsBKxseQXPBlA33N46cGOS7Im0+AYWeLxx6Tz43sQNx gTDrkiviHFMe6FuPXdHnLS1Y/Ty7QkjnuiUdaYlU= Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id 4B94642922; Fri, 12 Apr 2024 13:36:23 +0200 (CEST) From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Fri, 12 Apr 2024 13:35:16 +0200 Message-ID: <20240412113620.84013-3-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240412113620.84013-1-ffmpeg@haasn.xyz> References: <20240412113620.84013-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 02/13] avcodec/dovi_rpu: properly replace context header X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: 3E5Pu4F8HC0E From: Niklas Haas This was never set in ff_dovi_ctx_replace(), leading to possibly out-of-date when copying from one thread to another. --- libavcodec/dovi_rpu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libavcodec/dovi_rpu.c b/libavcodec/dovi_rpu.c index d95c7e03af..bfb7b9fe66 100644 --- a/libavcodec/dovi_rpu.c +++ b/libavcodec/dovi_rpu.c @@ -75,6 +75,7 @@ void ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0) { s->logctx = s0->logctx; s->cfg = s0->cfg; + s->header = s0->header; s->mapping = s0->mapping; s->color = s0->color; for (int i = 0; i <= DOVI_MAX_DM_ID; i++) From patchwork Fri Apr 12 11:35:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 48021 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:670b:b0:1a9:af23:56c1 with SMTP id wh11csp202944pzb; Fri, 12 Apr 2024 04:37:29 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCVt+TDb5+Cyv4ZRb5nvYepuSKwU91rB/izzFmvxCBaJUsMJntpoyC774H4mzm9ck4zXlPmNBc0JexcG9GNLPiJpSb2tXzrzxUgqjw== X-Google-Smtp-Source: AGHT+IHebTl7Rqd+8TsYlz9hVKVamDLr4eBpNbmS3DT5w5gIF1y/fzuAOfWavUrHaOVAsCn92362 X-Received: by 2002:ac2:58ec:0:b0:517:8a22:e32e with SMTP id v12-20020ac258ec000000b005178a22e32emr1165903lfo.1.1712921849300; Fri, 12 Apr 2024 04:37:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1712921849; cv=none; d=google.com; s=arc-20160816; b=t8cUWdnmOMvbYvmAUB5uINSprVlNhNSNG2PN3DP1Mk4jzXx1euTBCySJru4NQ/CZHG 6fWFQUYJNfq8OypKWS+goxwZ/y2WLI3SymQLzU8prV3dGYua8NTCVaDferI5lRaH7+ZA I+bPvhkOO6siRRTg0kE2wjTPScWU5TkZb6smrnutEFKG5kjXMhbWpUWxq0OdDAf1u/2S BbGU2VENfB/mI71DyfaZ2kZmgQsQMFApp4c4cYVkgBbOAWnt13d2kJ8upHMcxpDJfvfd p/L0bKTtWToiax0x06eM7u5RsxwTd40On/r53Cpa07l4KA5m7LpLLhmRjy8EdXKdlJRx nTxg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=o2ZU1IAeu7vrQxlFjYB2IsxnkfGqT+ryRy0GYuW7yaA=; fh=xmAeKtysnShNOmkhiJmYkS30uw4Fu2hvBJ7qlIwukxQ=; b=p57ClNX7t3fWVeRRi9s/MunKUDpsVZviCxqrDRRHKCHbQJXH7lE3vUDR9XzWpp8NtT rpz0nFUZxV22j+MTrVmu/170zyAX6VA+bukoqkZxiL7rEOXHz4qFTgTR1a7c0ONhYVUL lUipUXZL+Eynps9/UWrsHeXpBT+xjZfRinNXbQAD8RaBl6ynFcsyOfEw7zY/HrOyi58Z nSQakqqazEWKGHbXXtpNqs2qIn88LUjSRBDWIB9GttkHtoYUylhEuNNVUb3Vd/zj+0s/ HNiSlK27w6V3iOd+AwHAcybWBNS6OEJUkc6/e3f0gXmw9m0f/jSGfRpi7TebPQdMOYkS 2CrQ==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=i5Qh3ilV; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id v1-20020a05651203a100b005158e5d8dcbsi1015253lfp.313.2024.04.12.04.37.28; Fri, 12 Apr 2024 04:37:29 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=i5Qh3ilV; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 44AB968D29A; Fri, 12 Apr 2024 14:36:36 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id CFCC768D222 for ; Fri, 12 Apr 2024 14:36:23 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1712921783; bh=PEn6CZGVhkrXT8gy51WOSvFjX15xYmUzk2qSzYIioCY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=i5Qh3ilVjBpeiH3qQAViEh3roa/B34mkUYXMF9twpoYzEu/jqhR6vywvCOdai5yXS QMbKtv17BF/8eEOU2WKPvautx3I7VApHHoVXjJXOl0G0LLyVcOyIq5JSKrnkVpi6EK 3VhjtIAdKcGTaKB5DiBd+wBLztIw0F7hcCS/DRAQ= Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id 932A7429D1; Fri, 12 Apr 2024 13:36:23 +0200 (CEST) From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Fri, 12 Apr 2024 13:35:17 +0200 Message-ID: <20240412113620.84013-4-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240412113620.84013-1-ffmpeg@haasn.xyz> References: <20240412113620.84013-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 03/13] avcodec/dovi_rpu: clarify error on missing RPU VDR X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: OAkvNiZamPVu From: Niklas Haas The code was written under the misguided assumption that these fields would only be present when the value changes, however this does not match the actual patent specification, which says that streams are required to either always signal this metadata, or never signal it. That said, the specification does not really clarify what the defaults of these fields should be in the event that this metadata is missing, so without any sample file or other reference I don't wish to hazard a guess at how to interpret these fields. Fix the current behavior by making sure we always throw this error, even for files that have the vdr sequence info in one frame but are missing it in the next frame. --- libavcodec/dovi_rpu.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libavcodec/dovi_rpu.c b/libavcodec/dovi_rpu.c index bfb7b9fe66..267e52ceb6 100644 --- a/libavcodec/dovi_rpu.c +++ b/libavcodec/dovi_rpu.c @@ -499,11 +499,11 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, hdr->el_spatial_resampling_filter_flag = get_bits1(gb); hdr->disable_residual_flag = get_bits1(gb); } - } - - if (!hdr->bl_bit_depth) { - av_log(s->logctx, AV_LOG_ERROR, "Missing RPU VDR sequence info?\n"); - goto fail; + } else { + /* lack of documentation/samples */ + avpriv_request_sample(s->logctx, "Missing RPU VDR sequence info\n"); + ff_dovi_ctx_unref(s); + return AVERROR_PATCHWELCOME; } vdr_dm_metadata_present = get_bits1(gb); From patchwork Fri Apr 12 11:35:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 48015 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:670b:b0:1a9:af23:56c1 with SMTP id wh11csp203070pzb; Fri, 12 Apr 2024 04:37:45 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCXPRNwIKPK3IsVztkZ5Wb9HMPBcUsPBBiuGZP99ZcNlEfcX+ocdouVMMdKbf5Luh55qDPcGs0ON68ICv1c/2yd6roNXV5Fpid/MGQ== X-Google-Smtp-Source: AGHT+IGuyewzs+6FVVP+ShIaYf+ZwC5ZZTI2nTreKGwUYHzYG2ew1N3vtaMaM81oepTGp63z4Q7E X-Received: by 2002:a17:907:928a:b0:a52:3d34:bde5 with SMTP id bw10-20020a170907928a00b00a523d34bde5mr560222ejc.1.1712921865398; Fri, 12 Apr 2024 04:37:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1712921865; cv=none; d=google.com; s=arc-20160816; b=t5tjYpyc0kGc/6Wy2R66R5T9FojbuxzXDi8o/2Kuz5AYfpxyp79wyl6wHkQJ0wgw4I T87Nmb8F8THJDzdLWS2qGuktTaSPa3b5Dg9MxTNcf/2rSeosbaUiuoNnNiRcm3nVJ6GH S2w+lAp4YxbPPwh1JQ/cNP0AXdyPICWcioUBHh9GLf9tY2Un2q3Aca0G5+wfxM0uTjLL sAG6m0Qccn7M10BzQGuUQ5wjKkkx8+TqONALRz1FrQI5JSSo2wPEgE1UTsdKLmJL16SG DEqFROxBRU8apdFWEhxZ13qJstLkrL/hVjDR+/hkzSUOGhk6jaJZoR5NpTArclnVvMnW XbSA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=U5AfgH3w8w7/FPw7DC98GUqaGmUs9WazTb/50tK1OWU=; fh=xmAeKtysnShNOmkhiJmYkS30uw4Fu2hvBJ7qlIwukxQ=; b=EPdoNSeJEudKPpa0a/FIfWnz7YpAYangQvGtxcdS8kq+fUSNRb8B63c5Sp8n6fEic3 xHGNqYQzDUV5oGuqDsZNUspqfn73W2pw0Knd9b7pHXs9czU5Ks2lo5CNaXXPbui00M// zyRMC4RwYoNhiQwE0rGx/GEpdjR/o667cWAXh3ziLromYlXNNTzEa0YvxbRM/8FzGx87 bYXXg7yFcmJHKOLvU0cEooAtgS599plYCk7YMpZpH4k4NwwWk1SQ83Inde2a0fgET8Rn dp7uCnkqwirmsqugWmxCUdvMemdz89XG54fA1LKRo6dBPGXjXLXe7PHIv6pIUR6FHYIV 3vbA==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=aU4EiUvJ; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id hd44-20020a17090796ac00b00a522434c766si1469923ejc.290.2024.04.12.04.37.45; Fri, 12 Apr 2024 04:37:45 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=aU4EiUvJ; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 0891968D2CE; Fri, 12 Apr 2024 14:36:38 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 1B74668D222 for ; Fri, 12 Apr 2024 14:36:24 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1712921783; bh=/6JPQaqNDsRUydZteFg6OxE8yULFQyhiY3BUFmX/lB0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aU4EiUvJYH/xN+E54EVrCVhcYf7K3c67Afpc4Bf7VIGC0UJ1TyCl7XiWMqe+iXbjm HvdgtjUQjn6j7/1I3qwujGM3oyACiQQ1lHWmyMxfWApYWGX/BA2yBe4swHLH4giYuI MRe7PoXjXGN4v7zcLDr00mPAmuxgwhNcnUllHnSM= Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id CC6C643065; Fri, 12 Apr 2024 13:36:23 +0200 (CEST) From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Fri, 12 Apr 2024 13:35:18 +0200 Message-ID: <20240412113620.84013-5-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240412113620.84013-1-ffmpeg@haasn.xyz> References: <20240412113620.84013-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 04/13] avcodec/dovi_rpu: expose guess_profile(), clarify semantics X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: 7TtwJrMgpQAG From: Niklas Haas To allow internally re-using it for both the encoder and decoder. This is based on HEVC only, H.264/AV1 use their own (hopefully correctly signalled) profiles (and in particular, the AV1 decoders implicitly default the correct profile in the absence of a configuration record). --- libavcodec/dovi_rpu.c | 4 ++-- libavcodec/dovi_rpu.h | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/libavcodec/dovi_rpu.c b/libavcodec/dovi_rpu.c index 267e52ceb6..77fef8c496 100644 --- a/libavcodec/dovi_rpu.c +++ b/libavcodec/dovi_rpu.c @@ -121,7 +121,7 @@ int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame) return 0; } -static int guess_profile(const AVDOVIRpuDataHeader *hdr) +int ff_dovi_guess_profile_hevc(const AVDOVIRpuDataHeader *hdr) { switch (hdr->vdr_rpu_profile) { case 0: @@ -510,7 +510,7 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, use_prev_vdr_rpu = get_bits1(gb); use_nlq = (hdr->rpu_format & 0x700) == 0 && !hdr->disable_residual_flag; - profile = s->cfg.dv_profile ? s->cfg.dv_profile : guess_profile(hdr); + profile = s->cfg.dv_profile ? s->cfg.dv_profile : ff_dovi_guess_profile_hevc(hdr); if (profile == 5 && use_nlq) { av_log(s->logctx, AV_LOG_ERROR, "Profile 5 RPUs should not use NLQ\n"); goto fail; diff --git a/libavcodec/dovi_rpu.h b/libavcodec/dovi_rpu.h index 9a68e45bf1..a866bbfebe 100644 --- a/libavcodec/dovi_rpu.h +++ b/libavcodec/dovi_rpu.h @@ -87,6 +87,10 @@ void ff_dovi_ctx_flush(DOVIContext *s); * DOVIContext struct. * * Returns 0 or an error code. + * + * Note: `DOVIContext.cfg` should be initialized before calling into this + * function. If not done, the profile will be guessed according to HEVC + * semantics. */ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, int err_recognition); @@ -96,4 +100,11 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, */ int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame); +/** + * Internal helper function to guess the correct DV profile for HEVC. + * + * Returns the profile number or 0 if unknown. + */ +int ff_dovi_guess_profile_hevc(const AVDOVIRpuDataHeader *hdr); + #endif /* AVCODEC_DOVI_RPU_H */ From patchwork Fri Apr 12 11:35:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 48024 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:670b:b0:1a9:af23:56c1 with SMTP id wh11csp203184pzb; Fri, 12 Apr 2024 04:38:03 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCUC+u15cOBAWask7geMW5C4PWPsX9aE6E0fFcfVbpD/zDR4+Lqlyv3Y1dzjk2Qslc2EG0el3TvZKtTFeF2QML5IlxyTKzXEus9Mpg== X-Google-Smtp-Source: AGHT+IHc2ZIhebWE9wpbDVSt+A7xQWlF8FvWc+Nnzb0GwJJfoIucHBBF/hYqvVikuZABaklPUrVp X-Received: by 2002:a17:907:76ca:b0:a4e:a2b4:59c with SMTP id kf10-20020a17090776ca00b00a4ea2b4059cmr1366028ejc.6.1712921882831; Fri, 12 Apr 2024 04:38:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1712921882; cv=none; d=google.com; s=arc-20160816; b=D/zaNbUphXX05zTe8ag9MmqM4gD7nICVkz7pF8xUVCz9NmuTn1P2RURQfsducgVgTt cII5hQruHwy/xt/gNf47JBxYJjvmQp/yi3VyOJBc1J7Od4A6af/TB23PJd7h6Q3rJy/u HAKXOofxwx5z4qLYGIfRZN0N05UPXI8bwxcQeLmcOkYGiByGRpy+tgrK3kw3hXZDUY2V hkeQ7Ih7wPhMX/mCfQiWCaUTS+HLv2aCU7tSUQJ58q25qbT/EhdOZcP/VPCIm+acGZck li6lwm1lALG7M2/bdOc2UBbTaSXiVT0viAOUUcnHMn+zYu1HQLXj8FdNNlg4tLR3tI7z CzFg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=KIylkouEBfaLoaIwSr8sNHlX3b6AmXH2crJPM7ADeL0=; fh=xmAeKtysnShNOmkhiJmYkS30uw4Fu2hvBJ7qlIwukxQ=; b=rT/IgrGzz8cTLd91gEx++blgo7Lg1M49Hz9hFsF71WPeyrQMTtFOpt5R8yLL3kyaok FK76lV4GxJDsPcT49VJjPUyCvd1KgRx2F+IgWZ8TNCXbVPXuNPVPwmF1XTpDXQLJkOhI 2c9F8L0VFUT921IbDH4DOpOmnFsbKBfJy0qilJWGwi6kbnxt4rYvEPIL/EOJ9c45lNoR MVvl1lhQxdh6mdC55JclK13djG0YIVaVJ78pFbgGWMEs64lRQXzTlWFS1OOVBOatbwCq qGbMRCa/dPtXZiBFGW5viOVbSXNQgK7GZt+Xue2sxi9wcD3PVcc9/9urnXd6E1mdMVel GIpA==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=EDOdtBPc; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id me17-20020a170906aed100b00a51e0de2752si1697467ejb.34.2024.04.12.04.38.02; Fri, 12 Apr 2024 04:38:02 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=EDOdtBPc; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 3908068D2D6; Fri, 12 Apr 2024 14:36:40 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 5C4BD68D281 for ; Fri, 12 Apr 2024 14:36:28 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1712921784; bh=Z33iBnbTxKNLLWNLFhQdUDf98tdkj3la1ptX1K268wM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EDOdtBPc7qe7Hh7LYPRlNB3hL0D4YDvJ0B9KhVLgQlgT7LDNXSt/o5g9wPoW6XFkS i2nT7bOHRCshvcE7suMu9wBvbzZr10BjbyfJ0xM6Wl18Nc3+WVR/9FzVDbhUtkZ5k2 VDHMby2qywX+riVS3B4arHpVzMNpszJ+Hwi3otwQ= Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id 0EC0743315; Fri, 12 Apr 2024 13:36:24 +0200 (CEST) From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Fri, 12 Apr 2024 13:35:19 +0200 Message-ID: <20240412113620.84013-6-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240412113620.84013-1-ffmpeg@haasn.xyz> References: <20240412113620.84013-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 05/13] configure: rename dovi_rpu subsystem to dovi_rpudec X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: 3anCUyOydpU0 From: Niklas Haas To distinguish it from the to-be-added dovi_rpuenc. --- configure | 10 +++++----- libavcodec/Makefile | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/configure b/configure index 55f1fc354d..c1e1ece1e2 100755 --- a/configure +++ b/configure @@ -2550,7 +2550,7 @@ CONFIG_EXTRA=" deflate_wrapper dirac_parse dnn - dovi_rpu + dovi_rpudec dvprofile evcparse exif @@ -2841,7 +2841,7 @@ cbs_vp8_select="cbs" cbs_vp9_select="cbs" deflate_wrapper_deps="zlib" dirac_parse_select="golomb" -dovi_rpu_select="golomb" +dovi_rpudec_select="golomb" dnn_suggest="libtensorflow libopenvino libtorch" dnn_deps="avformat swscale" error_resilience_select="me_cmp" @@ -2901,7 +2901,7 @@ asv1_encoder_select="aandcttables bswapdsp fdctdsp pixblockdsp" asv2_decoder_select="blockdsp bswapdsp idctdsp" asv2_encoder_select="aandcttables bswapdsp fdctdsp pixblockdsp" atrac1_decoder_select="sinewin" -av1_decoder_select="atsc_a53 cbs_av1 dovi_rpu" +av1_decoder_select="atsc_a53 cbs_av1 dovi_rpudec" bink_decoder_select="blockdsp hpeldsp" binkaudio_dct_decoder_select="wma_freqs" binkaudio_rdft_decoder_select="wma_freqs" @@ -2957,7 +2957,7 @@ h264_decoder_suggest="error_resilience" hap_decoder_select="snappy texturedsp" hap_encoder_deps="libsnappy" hap_encoder_select="texturedspenc" -hevc_decoder_select="bswapdsp cabac dovi_rpu golomb hevcparse hevc_sei videodsp" +hevc_decoder_select="bswapdsp cabac dovi_rpudec golomb hevcparse hevc_sei videodsp" huffyuv_decoder_select="bswapdsp huffyuvdsp llviddsp" huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp llvidencdsp" hymt_decoder_select="huffyuv_decoder" @@ -3490,7 +3490,7 @@ libcelt_decoder_deps="libcelt" libcodec2_decoder_deps="libcodec2" libcodec2_encoder_deps="libcodec2" libdav1d_decoder_deps="libdav1d" -libdav1d_decoder_select="atsc_a53 dovi_rpu" +libdav1d_decoder_select="atsc_a53 dovi_rpudec" libdavs2_decoder_deps="libdavs2" libdavs2_decoder_select="avs2_parser" libfdk_aac_decoder_deps="libfdk_aac" diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 7f6de4470e..61d261d606 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -85,7 +85,7 @@ OBJS-$(CONFIG_CBS_MPEG2) += cbs_mpeg2.o OBJS-$(CONFIG_CBS_VP8) += cbs_vp8.o vp8data.o OBJS-$(CONFIG_CBS_VP9) += cbs_vp9.o OBJS-$(CONFIG_DEFLATE_WRAPPER) += zlib_wrapper.o -OBJS-$(CONFIG_DOVI_RPU) += dovi_rpu.o +OBJS-$(CONFIG_DOVI_RPUDEC) += dovi_rpu.o OBJS-$(CONFIG_ERROR_RESILIENCE) += error_resilience.o OBJS-$(CONFIG_EVCPARSE) += evc_parse.o evc_ps.o OBJS-$(CONFIG_EXIF) += exif.o tiff_common.o From patchwork Fri Apr 12 11:35:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 48025 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:670b:b0:1a9:af23:56c1 with SMTP id wh11csp203254pzb; Fri, 12 Apr 2024 04:38:12 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCVginYmqUUuKuHyefFvfW3VpDF4ognvhfIgFlzbV+VKYtdfAHsHn0rJSWNT4x9ia3dyODfDBcIWlUm7xV7s5gCIF72Cv9x0UsQGsA== X-Google-Smtp-Source: AGHT+IG7b4/jvEUzZmEnj7NVModJlhI3jsgyCTR3scGPXuQmNPduXUMHZVMSRrokHQiSPifABQVC X-Received: by 2002:a50:8d5b:0:b0:56f:ebcf:bd94 with SMTP id t27-20020a508d5b000000b0056febcfbd94mr1549999edt.12.1712921891966; Fri, 12 Apr 2024 04:38:11 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1712921891; cv=none; d=google.com; s=arc-20160816; b=tav1gUOvxjNtdEyV2VSsQcOwatGG31RKluFHnKgnSvWyWGVkw3qwXeMewg/Se1hRCK 7mjsFNqBsm4NvyP/vmUR6E0PjfVUyHGE3aRZMjpfQCgIuoAAbNB07Kg9j0SakWZeuWIl YENVdTETDwI/Ai2cLAHEEulZkyhY0PSOOiNYCK34UE7w8dtKlrDg16GDFQ2jXff9mHxF 4nX/DDR/S6sxwp7WDX8wvAMABgDcX+LJEIjSvBhail2/szlDO4FplKsSI1eYKlAG6d8W +ShkpjcV3Th4vu9nfP+o0kfC1dTFmNg0eHXReDrOICAYycNZsopmtTlDfc3JmMymxmvV OYnQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=ZC3jAaPZxjYhMTd6Klf5e0dJM2AXKcVwQOZl94dPMms=; fh=xmAeKtysnShNOmkhiJmYkS30uw4Fu2hvBJ7qlIwukxQ=; b=tEVVSn3iJ3jodw2UuPNZXIjU6ewX60BoHTRNqoNkRkCr8nmq56o0BJ/w9DOvJ5mxyl fDtLwmKE0feZyuhC+GR/6PqCU4knxAyX4Qfr6W9vrDefyRs63l9TUAASBncHJzV7WMQi QHRyy1tBwCu/VI1kb+RKFAxc2QIF9jjx6lyshCCg84SS0UyJXBEcWD0EEaiXRU2Q/k9W FDK8XHOH1AVbVm0LmTktVYYF5aS4x8WQyQvheJFxvBQafQjz4t/rOvCH2+IS6SZo29y9 XEAJgEWcdN7XHSaov6eHp/s9JML7XLCeN0JG5it/gF6XXcYguzHdzuuzEdztSxl2joJ5 g4gw==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=TIvRnFZP; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id t24-20020a508d58000000b0056e759bdc15si1577220edt.140.2024.04.12.04.38.11; Fri, 12 Apr 2024 04:38:11 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=TIvRnFZP; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 3861468D2E1; Fri, 12 Apr 2024 14:36:41 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 5C7E368D282 for ; Fri, 12 Apr 2024 14:36:28 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1712921784; bh=MR0qUHI+ceYsxGl/OpCylKxMypmAXFU8m/4glzWEC5M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TIvRnFZPIsLrHAJl1uM4/NyHxthDFn7VQdAklY2UfGSLY1QQIYcHa1AoKOsCWU1j7 omxegPJsJDrkgbcZL1pEEOReRIXLtAHPTNrZIHGo4V0LynNOO1oECBQIsoRaQnY0rG /UThxQGa58Wy6FWvq6G6Kdw6T2XropYQ6lQIgv6A= Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id 444E5433CD; Fri, 12 Apr 2024 13:36:24 +0200 (CEST) From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Fri, 12 Apr 2024 13:35:20 +0200 Message-ID: <20240412113620.84013-7-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240412113620.84013-1-ffmpeg@haasn.xyz> References: <20240412113620.84013-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 06/13] avcodec/dovi_rpu: split into dovi_rpu.c and dovi_rpudec.c X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: FumAgD+KIt5R From: Niklas Haas To allow compiling the decoding objects without the encoding objects and vice versa. Common helpers that users of both APIs need are put into the shared dovi_rpu.c. --- libavcodec/Makefile | 2 +- libavcodec/dovi_rpu.c | 624 +------------------------------------- libavcodec/dovi_rpu.h | 14 + libavcodec/dovi_rpudec.c | 635 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 651 insertions(+), 624 deletions(-) create mode 100644 libavcodec/dovi_rpudec.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 61d261d606..45058eb8d2 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -85,7 +85,7 @@ OBJS-$(CONFIG_CBS_MPEG2) += cbs_mpeg2.o OBJS-$(CONFIG_CBS_VP8) += cbs_vp8.o vp8data.o OBJS-$(CONFIG_CBS_VP9) += cbs_vp9.o OBJS-$(CONFIG_DEFLATE_WRAPPER) += zlib_wrapper.o -OBJS-$(CONFIG_DOVI_RPUDEC) += dovi_rpu.o +OBJS-$(CONFIG_DOVI_RPUDEC) += dovi_rpu.o dovi_rpudec.o OBJS-$(CONFIG_ERROR_RESILIENCE) += error_resilience.o OBJS-$(CONFIG_EVCPARSE) += evc_parse.o evc_ps.o OBJS-$(CONFIG_EXIF) += exif.o tiff_common.o diff --git a/libavcodec/dovi_rpu.c b/libavcodec/dovi_rpu.c index 77fef8c496..b26c19dd5e 100644 --- a/libavcodec/dovi_rpu.c +++ b/libavcodec/dovi_rpu.c @@ -2,7 +2,7 @@ * Dolby Vision RPU decoder * * Copyright (C) 2021 Jan Ekström - * Copyright (C) 2021 Niklas Haas + * Copyright (C) 2021-2024 Niklas Haas * * This file is part of FFmpeg. * @@ -21,29 +21,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/buffer.h" #include "libavutil/mem.h" -#include "libavutil/crc.h" -#include "avcodec.h" #include "dovi_rpu.h" -#include "golomb.h" -#include "get_bits.h" #include "refstruct.h" -enum { - RPU_COEFF_FIXED = 0, - RPU_COEFF_FLOAT = 1, -}; - -/** - * Private contents of vdr. - */ -typedef struct DOVIVdr { - AVDOVIDataMapping mapping; - AVDOVIColorMetadata color; -} DOVIVdr; - void ff_dovi_ctx_unref(DOVIContext *s) { for (int i = 0; i < FF_ARRAY_ELEMS(s->vdr); i++) @@ -83,44 +65,6 @@ void ff_dovi_ctx_replace(DOVIContext *s, const DOVIContext *s0) ff_refstruct_replace(&s->ext_blocks, s0->ext_blocks); } -int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame) -{ - AVFrameSideData *sd; - AVBufferRef *buf; - AVDOVIMetadata *dovi; - size_t dovi_size, ext_sz; - - if (!s->mapping || !s->color) - return 0; /* incomplete dovi metadata */ - - dovi = av_dovi_metadata_alloc(&dovi_size); - if (!dovi) - return AVERROR(ENOMEM); - - buf = av_buffer_create((uint8_t *) dovi, dovi_size, NULL, NULL, 0); - if (!buf) { - av_free(dovi); - return AVERROR(ENOMEM); - } - - sd = av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_DOVI_METADATA, buf); - if (!sd) { - av_buffer_unref(&buf); - return AVERROR(ENOMEM); - } - - /* Copy only the parts of these structs known to us at compiler-time. */ -#define COPY(t, a, b, last) memcpy(a, b, offsetof(t, last) + sizeof((b)->last)) - COPY(AVDOVIRpuDataHeader, av_dovi_get_header(dovi), &s->header, disable_residual_flag); - COPY(AVDOVIDataMapping, av_dovi_get_mapping(dovi), s->mapping, nlq_pivots); - COPY(AVDOVIColorMetadata, av_dovi_get_color(dovi), s->color, source_diagonal); - ext_sz = FFMIN(sizeof(AVDOVIDmData), dovi->ext_block_size); - for (int i = 0; i < s->num_ext_blocks; i++) - memcpy(av_dovi_get_ext(dovi, i), &s->ext_blocks[i], ext_sz); - dovi->num_ext_blocks = s->num_ext_blocks; - return 0; -} - int ff_dovi_guess_profile_hevc(const AVDOVIRpuDataHeader *hdr) { switch (hdr->vdr_rpu_profile) { @@ -142,569 +86,3 @@ int ff_dovi_guess_profile_hevc(const AVDOVIRpuDataHeader *hdr) return 0; /* unknown */ } - -static inline uint64_t get_ue_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr) -{ - uint64_t ipart; - union { uint32_t u32; float f32; } fpart; - - switch (hdr->coef_data_type) { - case RPU_COEFF_FIXED: - ipart = get_ue_golomb_long(gb); - fpart.u32 = get_bits_long(gb, hdr->coef_log2_denom); - return (ipart << hdr->coef_log2_denom) | fpart.u32; - - case RPU_COEFF_FLOAT: - fpart.u32 = get_bits_long(gb, 32); - return fpart.f32 * (1LL << hdr->coef_log2_denom); - } - - return 0; /* unreachable */ -} - -static inline int64_t get_se_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr) -{ - int64_t ipart; - union { uint32_t u32; float f32; } fpart; - - switch (hdr->coef_data_type) { - case RPU_COEFF_FIXED: - ipart = get_se_golomb_long(gb); - fpart.u32 = get_bits_long(gb, hdr->coef_log2_denom); - return ipart * (1LL << hdr->coef_log2_denom) | fpart.u32; - - case RPU_COEFF_FLOAT: - fpart.u32 = get_bits_long(gb, 32); - return fpart.f32 * (1LL << hdr->coef_log2_denom); - } - - return 0; /* unreachable */ -} - -static inline unsigned get_variable_bits(GetBitContext *gb, int n) -{ - unsigned int value = get_bits(gb, n); - int read_more = get_bits1(gb); - while (read_more) { - value = (value + 1) << n; - value |= get_bits(gb, n); - read_more = get_bits1(gb); - } - return value; -} - -#define VALIDATE(VAR, MIN, MAX) \ - do { \ - if (VAR < MIN || VAR > MAX) { \ - av_log(s->logctx, AV_LOG_ERROR, "RPU validation failed: " \ - #MIN" <= "#VAR" = %d <= "#MAX"\n", (int) VAR); \ - goto fail; \ - } \ - } while (0) - -static void parse_ext_v1(DOVIContext *s, GetBitContext *gb, AVDOVIDmData *dm) -{ - switch (dm->level) { - case 1: - dm->l1.min_pq = get_bits(gb, 12); - dm->l1.max_pq = get_bits(gb, 12); - dm->l1.avg_pq = get_bits(gb, 12); - break; - case 2: - dm->l2.target_max_pq = get_bits(gb, 12); - dm->l2.trim_slope = get_bits(gb, 12); - dm->l2.trim_offset = get_bits(gb, 12); - dm->l2.trim_power = get_bits(gb, 12); - dm->l2.trim_chroma_weight = get_bits(gb, 12); - dm->l2.trim_saturation_gain = get_bits(gb, 12); - dm->l2.ms_weight = get_bits(gb, 13) - 8192; - break; - case 4: - dm->l4.anchor_pq = get_bits(gb, 12); - dm->l4.anchor_power = get_bits(gb, 12); - break; - case 5: - dm->l5.left_offset = get_bits(gb, 13); - dm->l5.right_offset = get_bits(gb, 13); - dm->l5.top_offset = get_bits(gb, 13); - dm->l5.bottom_offset = get_bits(gb, 13); - break; - case 6: - dm->l6.max_luminance = get_bits(gb, 16); - dm->l6.min_luminance = get_bits(gb, 16); - dm->l6.max_cll = get_bits(gb, 16); - dm->l6.max_fall = get_bits(gb, 16); - break; - case 255: - dm->l255.dm_run_mode = get_bits(gb, 8); - dm->l255.dm_run_version = get_bits(gb, 8); - for (int i = 0; i < 4; i++) - dm->l255.dm_debug[i] = get_bits(gb, 8); - break; - default: - av_log(s->logctx, AV_LOG_WARNING, - "Unknown Dolby Vision DM v1 level: %u\n", dm->level); - } -} - -static AVCIExy get_cie_xy(GetBitContext *gb) -{ - AVCIExy xy; - const int denom = 32767; - xy.x = av_make_q(get_sbits(gb, 16), denom); - xy.y = av_make_q(get_sbits(gb, 16), denom); - return xy; -} - -static void parse_ext_v2(DOVIContext *s, GetBitContext *gb, AVDOVIDmData *dm, - int ext_block_length) -{ - switch (dm->level) { - case 3: - dm->l3.min_pq_offset = get_bits(gb, 12); - dm->l3.max_pq_offset = get_bits(gb, 12); - dm->l3.avg_pq_offset = get_bits(gb, 12); - break; - case 8: - dm->l8.target_display_index = get_bits(gb, 8); - dm->l8.trim_slope = get_bits(gb, 12); - dm->l8.trim_offset = get_bits(gb, 12); - dm->l8.trim_power = get_bits(gb, 12); - dm->l8.trim_chroma_weight = get_bits(gb, 12); - dm->l8.trim_saturation_gain = get_bits(gb, 12); - dm->l8.ms_weight = get_bits(gb, 12) - 8192; - if (ext_block_length < 12) - break; - dm->l8.target_mid_contrast = get_bits(gb, 12); - if (ext_block_length < 13) - break; - dm->l8.clip_trim = get_bits(gb, 12); - if (ext_block_length < 19) - break; - for (int i = 0; i < 6; i++) - dm->l8.saturation_vector_field[i] = get_bits(gb, 8); - if (ext_block_length < 25) - break; - for (int i = 0; i < 6; i++) - dm->l8.hue_vector_field[i] = get_bits(gb, 8); - break; - case 9: - dm->l9.source_primary_index = get_bits(gb, 8); - if (ext_block_length < 17) - break; - dm->l9.source_display_primaries.prim.r = get_cie_xy(gb); - dm->l9.source_display_primaries.prim.g = get_cie_xy(gb); - dm->l9.source_display_primaries.prim.b = get_cie_xy(gb); - dm->l9.source_display_primaries.wp = get_cie_xy(gb); - break; - case 10: - dm->l10.target_display_index = get_bits(gb, 8); - dm->l10.target_max_pq = get_bits(gb, 12); - dm->l10.target_min_pq = get_bits(gb, 12); - dm->l10.target_primary_index = get_bits(gb, 8); - if (ext_block_length < 21) - break; - dm->l10.target_display_primaries.prim.r = get_cie_xy(gb); - dm->l10.target_display_primaries.prim.g = get_cie_xy(gb); - dm->l10.target_display_primaries.prim.b = get_cie_xy(gb); - dm->l10.target_display_primaries.wp = get_cie_xy(gb); - break; - case 11: - dm->l11.content_type = get_bits(gb, 8); - dm->l11.whitepoint = get_bits(gb, 4); - dm->l11.reference_mode_flag = get_bits1(gb); - skip_bits(gb, 3); /* reserved */ - dm->l11.sharpness = get_bits(gb, 2); - dm->l11.noise_reduction = get_bits(gb, 2); - dm->l11.mpeg_noise_reduction = get_bits(gb, 2); - dm->l11.frame_rate_conversion = get_bits(gb, 2); - dm->l11.brightness = get_bits(gb, 2); - dm->l11.color = get_bits(gb, 2); - break; - case 254: - dm->l254.dm_mode = get_bits(gb, 8); - dm->l254.dm_version_index = get_bits(gb, 8); - break; - default: - av_log(s->logctx, AV_LOG_WARNING, - "Unknown Dolby Vision DM v2 level: %u\n", dm->level); - } -} - -static int parse_ext_blocks(DOVIContext *s, GetBitContext *gb, int ver) -{ - int num_ext_blocks, ext_block_length, start_pos, parsed_bits; - - num_ext_blocks = get_ue_golomb_31(gb); - align_get_bits(gb); - if (s->num_ext_blocks + num_ext_blocks > AV_DOVI_MAX_EXT_BLOCKS) - return AVERROR_INVALIDDATA; - - if (!s->ext_blocks) { - s->ext_blocks = ff_refstruct_allocz(sizeof(AVDOVIDmData) * AV_DOVI_MAX_EXT_BLOCKS); - if (!s->ext_blocks) - return AVERROR(ENOMEM); - } - - while (num_ext_blocks--) { - AVDOVIDmData *dm = &s->ext_blocks[s->num_ext_blocks++]; - ext_block_length = get_ue_golomb_31(gb); - dm->level = get_bits(gb, 8); - start_pos = get_bits_count(gb); - - switch (ver) { - case 1: parse_ext_v1(s, gb, dm); break; - case 2: parse_ext_v2(s, gb, dm, ext_block_length); break; - } - - parsed_bits = get_bits_count(gb) - start_pos; - if (parsed_bits > ext_block_length * 8) - return AVERROR_INVALIDDATA; - skip_bits(gb, ext_block_length * 8 - parsed_bits); - } - - return 0; -} - -int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, - int err_recognition) -{ - AVDOVIRpuDataHeader *hdr = &s->header; - GetBitContext *gb = &(GetBitContext){0}; - DOVIVdr *vdr; - int ret; - - uint8_t rpu_type; - uint8_t vdr_seq_info_present; - uint8_t vdr_dm_metadata_present; - uint8_t use_prev_vdr_rpu; - uint8_t use_nlq; - uint8_t profile; - - if (rpu_size < 5) - goto fail; - - /* Container */ - if (s->cfg.dv_profile == 10 /* dav1.10 */) { - /* DV inside AV1 re-uses an EMDF container skeleton, but with fixed - * values - so we can effectively treat this as a magic byte sequence. - * - * The exact fields are, as follows: - * emdf_version : f(2) = 0 - * key_id : f(3) = 6 - * emdf_payload_id : f(5) = 31 - * emdf_payload_id_ext : var(5) = 225 - * smploffste : f(1) = 0 - * duratione : f(1) = 0 - * groupide : f(1) = 0 - * codecdatae : f(1) = 0 - * discard_unknown_payload : f(1) = 1 - */ - const unsigned header_magic = 0x01be6841u; - unsigned emdf_header, emdf_payload_size, emdf_protection; - if ((ret = init_get_bits8(gb, rpu, rpu_size)) < 0) - return ret; - emdf_header = get_bits_long(gb, 27); - VALIDATE(emdf_header, header_magic, header_magic); - emdf_payload_size = get_variable_bits(gb, 8); - VALIDATE(emdf_payload_size, 6, 512); - if (emdf_payload_size * 8 > get_bits_left(gb)) - return AVERROR_INVALIDDATA; - - /* The payload is not byte-aligned (off by *one* bit, curse Dolby), - * so copy into a fresh buffer to preserve byte alignment of the - * RPU struct */ - av_fast_padded_malloc(&s->rpu_buf, &s->rpu_buf_sz, emdf_payload_size); - if (!s->rpu_buf) - return AVERROR(ENOMEM); - for (int i = 0; i < emdf_payload_size; i++) - s->rpu_buf[i] = get_bits(gb, 8); - rpu = s->rpu_buf; - rpu_size = emdf_payload_size; - - /* Validate EMDF footer */ - emdf_protection = get_bits(gb, 5 + 12); - VALIDATE(emdf_protection, 0x400, 0x400); - } else { - /* NAL RBSP with prefix and trailing zeroes */ - VALIDATE(rpu[0], 25, 25); /* NAL prefix */ - rpu++; - rpu_size--; - /* Strip trailing padding bytes */ - while (rpu_size && rpu[rpu_size - 1] == 0) - rpu_size--; - } - - if (!rpu_size || rpu[rpu_size - 1] != 0x80) - goto fail; - - if (err_recognition & AV_EF_CRCCHECK) { - uint32_t crc = av_bswap32(av_crc(av_crc_get_table(AV_CRC_32_IEEE), - -1, rpu, rpu_size - 1)); /* exclude 0x80 */ - if (crc) { - av_log(s->logctx, AV_LOG_ERROR, "RPU CRC mismatch: %X\n", crc); - if (err_recognition & AV_EF_EXPLODE) - goto fail; - } - } - - if ((ret = init_get_bits8(gb, rpu, rpu_size)) < 0) - return ret; - - /* RPU header */ - rpu_type = get_bits(gb, 6); - if (rpu_type != 2) { - av_log(s->logctx, AV_LOG_WARNING, "Unrecognized RPU type " - "%"PRIu8", ignoring\n", rpu_type); - return 0; - } - - hdr->rpu_type = rpu_type; - hdr->rpu_format = get_bits(gb, 11); - - /* Values specific to RPU type 2 */ - hdr->vdr_rpu_profile = get_bits(gb, 4); - hdr->vdr_rpu_level = get_bits(gb, 4); - - vdr_seq_info_present = get_bits1(gb); - if (vdr_seq_info_present) { - hdr->chroma_resampling_explicit_filter_flag = get_bits1(gb); - hdr->coef_data_type = get_bits(gb, 2); - VALIDATE(hdr->coef_data_type, RPU_COEFF_FIXED, RPU_COEFF_FLOAT); - switch (hdr->coef_data_type) { - case RPU_COEFF_FIXED: - hdr->coef_log2_denom = get_ue_golomb(gb); - VALIDATE(hdr->coef_log2_denom, 13, 32); - break; - case RPU_COEFF_FLOAT: - hdr->coef_log2_denom = 32; /* arbitrary, choose maximum precision */ - break; - } - - hdr->vdr_rpu_normalized_idc = get_bits(gb, 2); - hdr->bl_video_full_range_flag = get_bits1(gb); - - if ((hdr->rpu_format & 0x700) == 0) { - int bl_bit_depth_minus8 = get_ue_golomb_31(gb); - int el_bit_depth_minus8 = get_ue_golomb_31(gb); - int vdr_bit_depth_minus8 = get_ue_golomb_31(gb); - VALIDATE(bl_bit_depth_minus8, 0, 8); - VALIDATE(el_bit_depth_minus8, 0, 8); - VALIDATE(vdr_bit_depth_minus8, 0, 8); - hdr->bl_bit_depth = bl_bit_depth_minus8 + 8; - hdr->el_bit_depth = el_bit_depth_minus8 + 8; - hdr->vdr_bit_depth = vdr_bit_depth_minus8 + 8; - hdr->spatial_resampling_filter_flag = get_bits1(gb); - skip_bits(gb, 3); /* reserved_zero_3bits */ - hdr->el_spatial_resampling_filter_flag = get_bits1(gb); - hdr->disable_residual_flag = get_bits1(gb); - } - } else { - /* lack of documentation/samples */ - avpriv_request_sample(s->logctx, "Missing RPU VDR sequence info\n"); - ff_dovi_ctx_unref(s); - return AVERROR_PATCHWELCOME; - } - - vdr_dm_metadata_present = get_bits1(gb); - use_prev_vdr_rpu = get_bits1(gb); - use_nlq = (hdr->rpu_format & 0x700) == 0 && !hdr->disable_residual_flag; - - profile = s->cfg.dv_profile ? s->cfg.dv_profile : ff_dovi_guess_profile_hevc(hdr); - if (profile == 5 && use_nlq) { - av_log(s->logctx, AV_LOG_ERROR, "Profile 5 RPUs should not use NLQ\n"); - goto fail; - } - - if (use_prev_vdr_rpu) { - int prev_vdr_rpu_id = get_ue_golomb_31(gb); - VALIDATE(prev_vdr_rpu_id, 0, DOVI_MAX_DM_ID); - if (!s->vdr[prev_vdr_rpu_id]) { - av_log(s->logctx, AV_LOG_ERROR, "Unknown previous RPU ID: %u\n", - prev_vdr_rpu_id); - goto fail; - } - vdr = s->vdr[prev_vdr_rpu_id]; - s->mapping = &vdr->mapping; - } else { - int vdr_rpu_id = get_ue_golomb_31(gb); - VALIDATE(vdr_rpu_id, 0, DOVI_MAX_DM_ID); - if (!s->vdr[vdr_rpu_id]) { - s->vdr[vdr_rpu_id] = ff_refstruct_allocz(sizeof(DOVIVdr)); - if (!s->vdr[vdr_rpu_id]) - return AVERROR(ENOMEM); - } - - vdr = s->vdr[vdr_rpu_id]; - s->mapping = &vdr->mapping; - - vdr->mapping.vdr_rpu_id = vdr_rpu_id; - vdr->mapping.mapping_color_space = get_ue_golomb_31(gb); - vdr->mapping.mapping_chroma_format_idc = get_ue_golomb_31(gb); - - for (int c = 0; c < 3; c++) { - AVDOVIReshapingCurve *curve = &vdr->mapping.curves[c]; - int num_pivots_minus_2 = get_ue_golomb_31(gb); - int pivot = 0; - - VALIDATE(num_pivots_minus_2, 0, AV_DOVI_MAX_PIECES - 1); - curve->num_pivots = num_pivots_minus_2 + 2; - for (int i = 0; i < curve->num_pivots; i++) { - pivot += get_bits(gb, hdr->bl_bit_depth); - curve->pivots[i] = av_clip_uint16(pivot); - } - } - - if (use_nlq) { - int nlq_pivot = 0; - vdr->mapping.nlq_method_idc = get_bits(gb, 3); - - for (int i = 0; i < 2; i++) { - nlq_pivot += get_bits(gb, hdr->bl_bit_depth); - vdr->mapping.nlq_pivots[i] = av_clip_uint16(nlq_pivot); - } - - /** - * The patent mentions another legal value, NLQ_MU_LAW, but it's - * not documented anywhere how to parse or apply that type of NLQ. - */ - VALIDATE(vdr->mapping.nlq_method_idc, 0, AV_DOVI_NLQ_LINEAR_DZ); - } else { - vdr->mapping.nlq_method_idc = AV_DOVI_NLQ_NONE; - } - - vdr->mapping.num_x_partitions = get_ue_golomb_long(gb) + 1; - vdr->mapping.num_y_partitions = get_ue_golomb_long(gb) + 1; - /* End of rpu_data_header(), start of vdr_rpu_data_payload() */ - - for (int c = 0; c < 3; c++) { - AVDOVIReshapingCurve *curve = &vdr->mapping.curves[c]; - for (int i = 0; i < curve->num_pivots - 1; i++) { - int mapping_idc = get_ue_golomb_31(gb); - VALIDATE(mapping_idc, 0, 1); - curve->mapping_idc[i] = mapping_idc; - switch (mapping_idc) { - case AV_DOVI_MAPPING_POLYNOMIAL: { - int poly_order_minus1 = get_ue_golomb_31(gb); - VALIDATE(poly_order_minus1, 0, 1); - curve->poly_order[i] = poly_order_minus1 + 1; - if (poly_order_minus1 == 0) { - int linear_interp_flag = get_bits1(gb); - if (linear_interp_flag) { - /* lack of documentation/samples */ - avpriv_request_sample(s->logctx, "Dolby Vision " - "linear interpolation"); - ff_dovi_ctx_unref(s); - return AVERROR_PATCHWELCOME; - } - } - for (int k = 0; k <= curve->poly_order[i]; k++) - curve->poly_coef[i][k] = get_se_coef(gb, hdr); - break; - } - case AV_DOVI_MAPPING_MMR: { - int mmr_order_minus1 = get_bits(gb, 2); - VALIDATE(mmr_order_minus1, 0, 2); - curve->mmr_order[i] = mmr_order_minus1 + 1; - curve->mmr_constant[i] = get_se_coef(gb, hdr); - for (int j = 0; j < curve->mmr_order[i]; j++) { - for (int k = 0; k < 7; k++) - curve->mmr_coef[i][j][k] = get_se_coef(gb, hdr); - } - break; - } - } - } - } - - if (use_nlq) { - for (int c = 0; c < 3; c++) { - AVDOVINLQParams *nlq = &vdr->mapping.nlq[c]; - nlq->nlq_offset = get_bits(gb, hdr->el_bit_depth); - nlq->vdr_in_max = get_ue_coef(gb, hdr); - switch (vdr->mapping.nlq_method_idc) { - case AV_DOVI_NLQ_LINEAR_DZ: - nlq->linear_deadzone_slope = get_ue_coef(gb, hdr); - nlq->linear_deadzone_threshold = get_ue_coef(gb, hdr); - break; - } - } - } - } - - if (vdr_dm_metadata_present) { - AVDOVIColorMetadata *color; - int affected_dm_id = get_ue_golomb_31(gb); - int current_dm_id = get_ue_golomb_31(gb); - VALIDATE(affected_dm_id, 0, DOVI_MAX_DM_ID); - VALIDATE(current_dm_id, 0, DOVI_MAX_DM_ID); - if (!s->vdr[affected_dm_id]) { - s->vdr[affected_dm_id] = ff_refstruct_allocz(sizeof(DOVIVdr)); - if (!s->vdr[affected_dm_id]) - return AVERROR(ENOMEM); - } - - if (!s->vdr[current_dm_id]) { - av_log(s->logctx, AV_LOG_ERROR, "Unknown previous RPU DM ID: %u\n", - current_dm_id); - goto fail; - } - - /* Update current pointer based on current_dm_id */ - vdr = s->vdr[current_dm_id]; - s->color = &vdr->color; - - /* Update values of affected_dm_id */ - vdr = s->vdr[affected_dm_id]; - color = &vdr->color; - color->dm_metadata_id = affected_dm_id; - color->scene_refresh_flag = get_ue_golomb_31(gb); - for (int i = 0; i < 9; i++) - color->ycc_to_rgb_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 13); - for (int i = 0; i < 3; i++) { - int denom = profile == 4 ? (1 << 30) : (1 << 28); - unsigned offset = get_bits_long(gb, 32); - if (offset > INT_MAX) { - /* Ensure the result fits inside AVRational */ - offset >>= 1; - denom >>= 1; - } - color->ycc_to_rgb_offset[i] = av_make_q(offset, denom); - } - for (int i = 0; i < 9; i++) - color->rgb_to_lms_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 14); - - color->signal_eotf = get_bits(gb, 16); - color->signal_eotf_param0 = get_bits(gb, 16); - color->signal_eotf_param1 = get_bits(gb, 16); - color->signal_eotf_param2 = get_bits_long(gb, 32); - color->signal_bit_depth = get_bits(gb, 5); - VALIDATE(color->signal_bit_depth, 8, 16); - color->signal_color_space = get_bits(gb, 2); - color->signal_chroma_format = get_bits(gb, 2); - color->signal_full_range_flag = get_bits(gb, 2); - color->source_min_pq = get_bits(gb, 12); - color->source_max_pq = get_bits(gb, 12); - color->source_diagonal = get_bits(gb, 10); - } - - /* Parse extension blocks */ - s->num_ext_blocks = 0; - if ((ret = parse_ext_blocks(s, gb, 1)) < 0) { - ff_dovi_ctx_unref(s); - return ret; - } - - if (get_bits_left(gb) > 48 /* padding + CRC32 + terminator */) { - if ((ret = parse_ext_blocks(s, gb, 2)) < 0) { - ff_dovi_ctx_unref(s); - return ret; - } - } - - return 0; - -fail: - ff_dovi_ctx_unref(s); /* don't leak potentially invalid state */ - return AVERROR_INVALIDDATA; -} diff --git a/libavcodec/dovi_rpu.h b/libavcodec/dovi_rpu.h index a866bbfebe..0c12a3fee0 100644 --- a/libavcodec/dovi_rpu.h +++ b/libavcodec/dovi_rpu.h @@ -100,6 +100,20 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, */ int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame); +/*************************************************** + * The following section is for internal use only. * + ***************************************************/ + +typedef struct DOVIVdr { + AVDOVIDataMapping mapping; + AVDOVIColorMetadata color; +} DOVIVdr; + +enum { + RPU_COEFF_FIXED = 0, + RPU_COEFF_FLOAT = 1, +}; + /** * Internal helper function to guess the correct DV profile for HEVC. * diff --git a/libavcodec/dovi_rpudec.c b/libavcodec/dovi_rpudec.c new file mode 100644 index 0000000000..7c7eda9d09 --- /dev/null +++ b/libavcodec/dovi_rpudec.c @@ -0,0 +1,635 @@ +/* + * Dolby Vision RPU decoder + * + * Copyright (C) 2021 Jan Ekström + * Copyright (C) 2021-2024 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/mem.h" +#include "libavutil/crc.h" + +#include "avcodec.h" +#include "dovi_rpu.h" +#include "golomb.h" +#include "get_bits.h" +#include "refstruct.h" + +int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame) +{ + AVFrameSideData *sd; + AVBufferRef *buf; + AVDOVIMetadata *dovi; + size_t dovi_size, ext_sz; + + if (!s->mapping || !s->color) + return 0; /* incomplete dovi metadata */ + + dovi = av_dovi_metadata_alloc(&dovi_size); + if (!dovi) + return AVERROR(ENOMEM); + + buf = av_buffer_create((uint8_t *) dovi, dovi_size, NULL, NULL, 0); + if (!buf) { + av_free(dovi); + return AVERROR(ENOMEM); + } + + sd = av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_DOVI_METADATA, buf); + if (!sd) { + av_buffer_unref(&buf); + return AVERROR(ENOMEM); + } + + /* Copy only the parts of these structs known to us at compiler-time. */ +#define COPY(t, a, b, last) memcpy(a, b, offsetof(t, last) + sizeof((b)->last)) + COPY(AVDOVIRpuDataHeader, av_dovi_get_header(dovi), &s->header, disable_residual_flag); + COPY(AVDOVIDataMapping, av_dovi_get_mapping(dovi), s->mapping, nlq_pivots); + COPY(AVDOVIColorMetadata, av_dovi_get_color(dovi), s->color, source_diagonal); + ext_sz = FFMIN(sizeof(AVDOVIDmData), dovi->ext_block_size); + for (int i = 0; i < s->num_ext_blocks; i++) + memcpy(av_dovi_get_ext(dovi, i), &s->ext_blocks[i], ext_sz); + dovi->num_ext_blocks = s->num_ext_blocks; + return 0; +} + +static inline uint64_t get_ue_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr) +{ + uint64_t ipart; + union { uint32_t u32; float f32; } fpart; + + switch (hdr->coef_data_type) { + case RPU_COEFF_FIXED: + ipart = get_ue_golomb_long(gb); + fpart.u32 = get_bits_long(gb, hdr->coef_log2_denom); + return (ipart << hdr->coef_log2_denom) | fpart.u32; + + case RPU_COEFF_FLOAT: + fpart.u32 = get_bits_long(gb, 32); + return fpart.f32 * (1LL << hdr->coef_log2_denom); + } + + return 0; /* unreachable */ +} + +static inline int64_t get_se_coef(GetBitContext *gb, const AVDOVIRpuDataHeader *hdr) +{ + int64_t ipart; + union { uint32_t u32; float f32; } fpart; + + switch (hdr->coef_data_type) { + case RPU_COEFF_FIXED: + ipart = get_se_golomb_long(gb); + fpart.u32 = get_bits_long(gb, hdr->coef_log2_denom); + return ipart * (1LL << hdr->coef_log2_denom) | fpart.u32; + + case RPU_COEFF_FLOAT: + fpart.u32 = get_bits_long(gb, 32); + return fpart.f32 * (1LL << hdr->coef_log2_denom); + } + + return 0; /* unreachable */ +} + +static inline unsigned get_variable_bits(GetBitContext *gb, int n) +{ + unsigned int value = get_bits(gb, n); + int read_more = get_bits1(gb); + while (read_more) { + value = (value + 1) << n; + value |= get_bits(gb, n); + read_more = get_bits1(gb); + } + return value; +} + +#define VALIDATE(VAR, MIN, MAX) \ + do { \ + if (VAR < MIN || VAR > MAX) { \ + av_log(s->logctx, AV_LOG_ERROR, "RPU validation failed: " \ + #MIN" <= "#VAR" = %d <= "#MAX"\n", (int) VAR); \ + goto fail; \ + } \ + } while (0) + +static void parse_ext_v1(DOVIContext *s, GetBitContext *gb, AVDOVIDmData *dm) +{ + switch (dm->level) { + case 1: + dm->l1.min_pq = get_bits(gb, 12); + dm->l1.max_pq = get_bits(gb, 12); + dm->l1.avg_pq = get_bits(gb, 12); + break; + case 2: + dm->l2.target_max_pq = get_bits(gb, 12); + dm->l2.trim_slope = get_bits(gb, 12); + dm->l2.trim_offset = get_bits(gb, 12); + dm->l2.trim_power = get_bits(gb, 12); + dm->l2.trim_chroma_weight = get_bits(gb, 12); + dm->l2.trim_saturation_gain = get_bits(gb, 12); + dm->l2.ms_weight = get_bits(gb, 13) - 8192; + break; + case 4: + dm->l4.anchor_pq = get_bits(gb, 12); + dm->l4.anchor_power = get_bits(gb, 12); + break; + case 5: + dm->l5.left_offset = get_bits(gb, 13); + dm->l5.right_offset = get_bits(gb, 13); + dm->l5.top_offset = get_bits(gb, 13); + dm->l5.bottom_offset = get_bits(gb, 13); + break; + case 6: + dm->l6.max_luminance = get_bits(gb, 16); + dm->l6.min_luminance = get_bits(gb, 16); + dm->l6.max_cll = get_bits(gb, 16); + dm->l6.max_fall = get_bits(gb, 16); + break; + case 255: + dm->l255.dm_run_mode = get_bits(gb, 8); + dm->l255.dm_run_version = get_bits(gb, 8); + for (int i = 0; i < 4; i++) + dm->l255.dm_debug[i] = get_bits(gb, 8); + break; + default: + av_log(s->logctx, AV_LOG_WARNING, + "Unknown Dolby Vision DM v1 level: %u\n", dm->level); + } +} + +static AVCIExy get_cie_xy(GetBitContext *gb) +{ + AVCIExy xy; + const int denom = 32767; + xy.x = av_make_q(get_sbits(gb, 16), denom); + xy.y = av_make_q(get_sbits(gb, 16), denom); + return xy; +} + +static void parse_ext_v2(DOVIContext *s, GetBitContext *gb, AVDOVIDmData *dm, + int ext_block_length) +{ + switch (dm->level) { + case 3: + dm->l3.min_pq_offset = get_bits(gb, 12); + dm->l3.max_pq_offset = get_bits(gb, 12); + dm->l3.avg_pq_offset = get_bits(gb, 12); + break; + case 8: + dm->l8.target_display_index = get_bits(gb, 8); + dm->l8.trim_slope = get_bits(gb, 12); + dm->l8.trim_offset = get_bits(gb, 12); + dm->l8.trim_power = get_bits(gb, 12); + dm->l8.trim_chroma_weight = get_bits(gb, 12); + dm->l8.trim_saturation_gain = get_bits(gb, 12); + dm->l8.ms_weight = get_bits(gb, 12) - 8192; + if (ext_block_length < 12) + break; + dm->l8.target_mid_contrast = get_bits(gb, 12); + if (ext_block_length < 13) + break; + dm->l8.clip_trim = get_bits(gb, 12); + if (ext_block_length < 19) + break; + for (int i = 0; i < 6; i++) + dm->l8.saturation_vector_field[i] = get_bits(gb, 8); + if (ext_block_length < 25) + break; + for (int i = 0; i < 6; i++) + dm->l8.hue_vector_field[i] = get_bits(gb, 8); + break; + case 9: + dm->l9.source_primary_index = get_bits(gb, 8); + if (ext_block_length < 17) + break; + dm->l9.source_display_primaries.prim.r = get_cie_xy(gb); + dm->l9.source_display_primaries.prim.g = get_cie_xy(gb); + dm->l9.source_display_primaries.prim.b = get_cie_xy(gb); + dm->l9.source_display_primaries.wp = get_cie_xy(gb); + break; + case 10: + dm->l10.target_display_index = get_bits(gb, 8); + dm->l10.target_max_pq = get_bits(gb, 12); + dm->l10.target_min_pq = get_bits(gb, 12); + dm->l10.target_primary_index = get_bits(gb, 8); + if (ext_block_length < 21) + break; + dm->l10.target_display_primaries.prim.r = get_cie_xy(gb); + dm->l10.target_display_primaries.prim.g = get_cie_xy(gb); + dm->l10.target_display_primaries.prim.b = get_cie_xy(gb); + dm->l10.target_display_primaries.wp = get_cie_xy(gb); + break; + case 11: + dm->l11.content_type = get_bits(gb, 8); + dm->l11.whitepoint = get_bits(gb, 4); + dm->l11.reference_mode_flag = get_bits1(gb); + skip_bits(gb, 3); /* reserved */ + dm->l11.sharpness = get_bits(gb, 2); + dm->l11.noise_reduction = get_bits(gb, 2); + dm->l11.mpeg_noise_reduction = get_bits(gb, 2); + dm->l11.frame_rate_conversion = get_bits(gb, 2); + dm->l11.brightness = get_bits(gb, 2); + dm->l11.color = get_bits(gb, 2); + break; + case 254: + dm->l254.dm_mode = get_bits(gb, 8); + dm->l254.dm_version_index = get_bits(gb, 8); + break; + default: + av_log(s->logctx, AV_LOG_WARNING, + "Unknown Dolby Vision DM v2 level: %u\n", dm->level); + } +} + +static int parse_ext_blocks(DOVIContext *s, GetBitContext *gb, int ver) +{ + int num_ext_blocks, ext_block_length, start_pos, parsed_bits; + + num_ext_blocks = get_ue_golomb_31(gb); + align_get_bits(gb); + if (s->num_ext_blocks + num_ext_blocks > AV_DOVI_MAX_EXT_BLOCKS) + return AVERROR_INVALIDDATA; + + if (!s->ext_blocks) { + s->ext_blocks = ff_refstruct_allocz(sizeof(AVDOVIDmData) * AV_DOVI_MAX_EXT_BLOCKS); + if (!s->ext_blocks) + return AVERROR(ENOMEM); + } + + while (num_ext_blocks--) { + AVDOVIDmData *dm = &s->ext_blocks[s->num_ext_blocks++]; + ext_block_length = get_ue_golomb_31(gb); + dm->level = get_bits(gb, 8); + start_pos = get_bits_count(gb); + + switch (ver) { + case 1: parse_ext_v1(s, gb, dm); break; + case 2: parse_ext_v2(s, gb, dm, ext_block_length); break; + } + + parsed_bits = get_bits_count(gb) - start_pos; + if (parsed_bits > ext_block_length * 8) + return AVERROR_INVALIDDATA; + skip_bits(gb, ext_block_length * 8 - parsed_bits); + } + + return 0; +} + +int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, + int err_recognition) +{ + AVDOVIRpuDataHeader *hdr = &s->header; + GetBitContext *gb = &(GetBitContext){0}; + DOVIVdr *vdr; + int ret; + + uint8_t rpu_type; + uint8_t vdr_seq_info_present; + uint8_t vdr_dm_metadata_present; + uint8_t use_prev_vdr_rpu; + uint8_t use_nlq; + uint8_t profile; + + if (rpu_size < 5) + goto fail; + + /* Container */ + if (s->cfg.dv_profile == 10 /* dav1.10 */) { + /* DV inside AV1 re-uses an EMDF container skeleton, but with fixed + * values - so we can effectively treat this as a magic byte sequence. + * + * The exact fields are, as follows: + * emdf_version : f(2) = 0 + * key_id : f(3) = 6 + * emdf_payload_id : f(5) = 31 + * emdf_payload_id_ext : var(5) = 225 + * smploffste : f(1) = 0 + * duratione : f(1) = 0 + * groupide : f(1) = 0 + * codecdatae : f(1) = 0 + * discard_unknown_payload : f(1) = 1 + */ + const unsigned header_magic = 0x01be6841u; + unsigned emdf_header, emdf_payload_size, emdf_protection; + if ((ret = init_get_bits8(gb, rpu, rpu_size)) < 0) + return ret; + emdf_header = get_bits_long(gb, 27); + VALIDATE(emdf_header, header_magic, header_magic); + emdf_payload_size = get_variable_bits(gb, 8); + VALIDATE(emdf_payload_size, 6, 512); + if (emdf_payload_size * 8 > get_bits_left(gb)) + return AVERROR_INVALIDDATA; + + /* The payload is not byte-aligned (off by *one* bit, curse Dolby), + * so copy into a fresh buffer to preserve byte alignment of the + * RPU struct */ + av_fast_padded_malloc(&s->rpu_buf, &s->rpu_buf_sz, emdf_payload_size); + if (!s->rpu_buf) + return AVERROR(ENOMEM); + for (int i = 0; i < emdf_payload_size; i++) + s->rpu_buf[i] = get_bits(gb, 8); + rpu = s->rpu_buf; + rpu_size = emdf_payload_size; + + /* Validate EMDF footer */ + emdf_protection = get_bits(gb, 5 + 12); + VALIDATE(emdf_protection, 0x400, 0x400); + } else { + /* NAL RBSP with prefix and trailing zeroes */ + VALIDATE(rpu[0], 25, 25); /* NAL prefix */ + rpu++; + rpu_size--; + /* Strip trailing padding bytes */ + while (rpu_size && rpu[rpu_size - 1] == 0) + rpu_size--; + } + + if (!rpu_size || rpu[rpu_size - 1] != 0x80) + goto fail; + + if (err_recognition & AV_EF_CRCCHECK) { + uint32_t crc = av_bswap32(av_crc(av_crc_get_table(AV_CRC_32_IEEE), + -1, rpu, rpu_size - 1)); /* exclude 0x80 */ + if (crc) { + av_log(s->logctx, AV_LOG_ERROR, "RPU CRC mismatch: %X\n", crc); + if (err_recognition & AV_EF_EXPLODE) + goto fail; + } + } + + if ((ret = init_get_bits8(gb, rpu, rpu_size)) < 0) + return ret; + + /* RPU header */ + rpu_type = get_bits(gb, 6); + if (rpu_type != 2) { + av_log(s->logctx, AV_LOG_WARNING, "Unrecognized RPU type " + "%"PRIu8", ignoring\n", rpu_type); + return 0; + } + + hdr->rpu_type = rpu_type; + hdr->rpu_format = get_bits(gb, 11); + + /* Values specific to RPU type 2 */ + hdr->vdr_rpu_profile = get_bits(gb, 4); + hdr->vdr_rpu_level = get_bits(gb, 4); + + vdr_seq_info_present = get_bits1(gb); + if (vdr_seq_info_present) { + hdr->chroma_resampling_explicit_filter_flag = get_bits1(gb); + hdr->coef_data_type = get_bits(gb, 2); + VALIDATE(hdr->coef_data_type, RPU_COEFF_FIXED, RPU_COEFF_FLOAT); + switch (hdr->coef_data_type) { + case RPU_COEFF_FIXED: + hdr->coef_log2_denom = get_ue_golomb(gb); + VALIDATE(hdr->coef_log2_denom, 13, 32); + break; + case RPU_COEFF_FLOAT: + hdr->coef_log2_denom = 32; /* arbitrary, choose maximum precision */ + break; + } + + hdr->vdr_rpu_normalized_idc = get_bits(gb, 2); + hdr->bl_video_full_range_flag = get_bits1(gb); + + if ((hdr->rpu_format & 0x700) == 0) { + int bl_bit_depth_minus8 = get_ue_golomb_31(gb); + int el_bit_depth_minus8 = get_ue_golomb_31(gb); + int vdr_bit_depth_minus8 = get_ue_golomb_31(gb); + VALIDATE(bl_bit_depth_minus8, 0, 8); + VALIDATE(el_bit_depth_minus8, 0, 8); + VALIDATE(vdr_bit_depth_minus8, 0, 8); + hdr->bl_bit_depth = bl_bit_depth_minus8 + 8; + hdr->el_bit_depth = el_bit_depth_minus8 + 8; + hdr->vdr_bit_depth = vdr_bit_depth_minus8 + 8; + hdr->spatial_resampling_filter_flag = get_bits1(gb); + skip_bits(gb, 3); /* reserved_zero_3bits */ + hdr->el_spatial_resampling_filter_flag = get_bits1(gb); + hdr->disable_residual_flag = get_bits1(gb); + } + } else { + /* lack of documentation/samples */ + avpriv_request_sample(s->logctx, "Missing RPU VDR sequence info\n"); + ff_dovi_ctx_unref(s); + return AVERROR_PATCHWELCOME; + } + + vdr_dm_metadata_present = get_bits1(gb); + use_prev_vdr_rpu = get_bits1(gb); + use_nlq = (hdr->rpu_format & 0x700) == 0 && !hdr->disable_residual_flag; + + profile = s->cfg.dv_profile ? s->cfg.dv_profile : ff_dovi_guess_profile_hevc(hdr); + if (profile == 5 && use_nlq) { + av_log(s->logctx, AV_LOG_ERROR, "Profile 5 RPUs should not use NLQ\n"); + goto fail; + } + + if (use_prev_vdr_rpu) { + int prev_vdr_rpu_id = get_ue_golomb_31(gb); + VALIDATE(prev_vdr_rpu_id, 0, DOVI_MAX_DM_ID); + if (!s->vdr[prev_vdr_rpu_id]) { + av_log(s->logctx, AV_LOG_ERROR, "Unknown previous RPU ID: %u\n", + prev_vdr_rpu_id); + goto fail; + } + vdr = s->vdr[prev_vdr_rpu_id]; + s->mapping = &vdr->mapping; + } else { + int vdr_rpu_id = get_ue_golomb_31(gb); + VALIDATE(vdr_rpu_id, 0, DOVI_MAX_DM_ID); + if (!s->vdr[vdr_rpu_id]) { + s->vdr[vdr_rpu_id] = ff_refstruct_allocz(sizeof(DOVIVdr)); + if (!s->vdr[vdr_rpu_id]) + return AVERROR(ENOMEM); + } + + vdr = s->vdr[vdr_rpu_id]; + s->mapping = &vdr->mapping; + + vdr->mapping.vdr_rpu_id = vdr_rpu_id; + vdr->mapping.mapping_color_space = get_ue_golomb_31(gb); + vdr->mapping.mapping_chroma_format_idc = get_ue_golomb_31(gb); + + for (int c = 0; c < 3; c++) { + AVDOVIReshapingCurve *curve = &vdr->mapping.curves[c]; + int num_pivots_minus_2 = get_ue_golomb_31(gb); + int pivot = 0; + + VALIDATE(num_pivots_minus_2, 0, AV_DOVI_MAX_PIECES - 1); + curve->num_pivots = num_pivots_minus_2 + 2; + for (int i = 0; i < curve->num_pivots; i++) { + pivot += get_bits(gb, hdr->bl_bit_depth); + curve->pivots[i] = av_clip_uint16(pivot); + } + } + + if (use_nlq) { + int nlq_pivot = 0; + vdr->mapping.nlq_method_idc = get_bits(gb, 3); + + for (int i = 0; i < 2; i++) { + nlq_pivot += get_bits(gb, hdr->bl_bit_depth); + vdr->mapping.nlq_pivots[i] = av_clip_uint16(nlq_pivot); + } + + /** + * The patent mentions another legal value, NLQ_MU_LAW, but it's + * not documented anywhere how to parse or apply that type of NLQ. + */ + VALIDATE(vdr->mapping.nlq_method_idc, 0, AV_DOVI_NLQ_LINEAR_DZ); + } else { + vdr->mapping.nlq_method_idc = AV_DOVI_NLQ_NONE; + } + + vdr->mapping.num_x_partitions = get_ue_golomb_long(gb) + 1; + vdr->mapping.num_y_partitions = get_ue_golomb_long(gb) + 1; + /* End of rpu_data_header(), start of vdr_rpu_data_payload() */ + + for (int c = 0; c < 3; c++) { + AVDOVIReshapingCurve *curve = &vdr->mapping.curves[c]; + for (int i = 0; i < curve->num_pivots - 1; i++) { + int mapping_idc = get_ue_golomb_31(gb); + VALIDATE(mapping_idc, 0, 1); + curve->mapping_idc[i] = mapping_idc; + switch (mapping_idc) { + case AV_DOVI_MAPPING_POLYNOMIAL: { + int poly_order_minus1 = get_ue_golomb_31(gb); + VALIDATE(poly_order_minus1, 0, 1); + curve->poly_order[i] = poly_order_minus1 + 1; + if (poly_order_minus1 == 0) { + int linear_interp_flag = get_bits1(gb); + if (linear_interp_flag) { + /* lack of documentation/samples */ + avpriv_request_sample(s->logctx, "Dolby Vision " + "linear interpolation"); + ff_dovi_ctx_unref(s); + return AVERROR_PATCHWELCOME; + } + } + for (int k = 0; k <= curve->poly_order[i]; k++) + curve->poly_coef[i][k] = get_se_coef(gb, hdr); + break; + } + case AV_DOVI_MAPPING_MMR: { + int mmr_order_minus1 = get_bits(gb, 2); + VALIDATE(mmr_order_minus1, 0, 2); + curve->mmr_order[i] = mmr_order_minus1 + 1; + curve->mmr_constant[i] = get_se_coef(gb, hdr); + for (int j = 0; j < curve->mmr_order[i]; j++) { + for (int k = 0; k < 7; k++) + curve->mmr_coef[i][j][k] = get_se_coef(gb, hdr); + } + break; + } + } + } + } + + if (use_nlq) { + for (int c = 0; c < 3; c++) { + AVDOVINLQParams *nlq = &vdr->mapping.nlq[c]; + nlq->nlq_offset = get_bits(gb, hdr->el_bit_depth); + nlq->vdr_in_max = get_ue_coef(gb, hdr); + switch (vdr->mapping.nlq_method_idc) { + case AV_DOVI_NLQ_LINEAR_DZ: + nlq->linear_deadzone_slope = get_ue_coef(gb, hdr); + nlq->linear_deadzone_threshold = get_ue_coef(gb, hdr); + break; + } + } + } + } + + if (vdr_dm_metadata_present) { + AVDOVIColorMetadata *color; + int affected_dm_id = get_ue_golomb_31(gb); + int current_dm_id = get_ue_golomb_31(gb); + VALIDATE(affected_dm_id, 0, DOVI_MAX_DM_ID); + VALIDATE(current_dm_id, 0, DOVI_MAX_DM_ID); + if (!s->vdr[affected_dm_id]) { + s->vdr[affected_dm_id] = ff_refstruct_allocz(sizeof(DOVIVdr)); + if (!s->vdr[affected_dm_id]) + return AVERROR(ENOMEM); + } + + if (!s->vdr[current_dm_id]) { + av_log(s->logctx, AV_LOG_ERROR, "Unknown previous RPU DM ID: %u\n", + current_dm_id); + goto fail; + } + + /* Update current pointer based on current_dm_id */ + vdr = s->vdr[current_dm_id]; + s->color = &vdr->color; + + /* Update values of affected_dm_id */ + vdr = s->vdr[affected_dm_id]; + color = &vdr->color; + color->dm_metadata_id = affected_dm_id; + color->scene_refresh_flag = get_ue_golomb_31(gb); + for (int i = 0; i < 9; i++) + color->ycc_to_rgb_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 13); + for (int i = 0; i < 3; i++) { + int denom = profile == 4 ? (1 << 30) : (1 << 28); + unsigned offset = get_bits_long(gb, 32); + if (offset > INT_MAX) { + /* Ensure the result fits inside AVRational */ + offset >>= 1; + denom >>= 1; + } + color->ycc_to_rgb_offset[i] = av_make_q(offset, denom); + } + for (int i = 0; i < 9; i++) + color->rgb_to_lms_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 14); + + color->signal_eotf = get_bits(gb, 16); + color->signal_eotf_param0 = get_bits(gb, 16); + color->signal_eotf_param1 = get_bits(gb, 16); + color->signal_eotf_param2 = get_bits_long(gb, 32); + color->signal_bit_depth = get_bits(gb, 5); + VALIDATE(color->signal_bit_depth, 8, 16); + color->signal_color_space = get_bits(gb, 2); + color->signal_chroma_format = get_bits(gb, 2); + color->signal_full_range_flag = get_bits(gb, 2); + color->source_min_pq = get_bits(gb, 12); + color->source_max_pq = get_bits(gb, 12); + color->source_diagonal = get_bits(gb, 10); + } + + /* Parse extension blocks */ + s->num_ext_blocks = 0; + if ((ret = parse_ext_blocks(s, gb, 1)) < 0) { + ff_dovi_ctx_unref(s); + return ret; + } + + if (get_bits_left(gb) > 48 /* padding + CRC32 + terminator */) { + if ((ret = parse_ext_blocks(s, gb, 2)) < 0) { + ff_dovi_ctx_unref(s); + return ret; + } + } + + return 0; + +fail: + ff_dovi_ctx_unref(s); /* don't leak potentially invalid state */ + return AVERROR_INVALIDDATA; +} From patchwork Fri Apr 12 11:35:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 48027 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:670b:b0:1a9:af23:56c1 with SMTP id wh11csp203400pzb; Fri, 12 Apr 2024 04:38:30 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCWOH0EoCrW6IAjkEQpGNN2h/hPa7mB8kFRztrNEmZMVtbJip2uGfWHb6mL+Asxqg6oY2WGCv2qUmSMqeZ+BRPYozlB3uT5rPF20Og== X-Google-Smtp-Source: AGHT+IGeW4DIWP7V/iPS1cnSQS2f80NN/yOXlwtNkDr83UaIZbymSlEYO6DZJOy24wPpSDVZi5Xu X-Received: by 2002:a2e:7e0a:0:b0:2d8:39cf:5368 with SMTP id z10-20020a2e7e0a000000b002d839cf5368mr2101650ljc.29.1712921910187; Fri, 12 Apr 2024 04:38:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1712921910; cv=none; d=google.com; s=arc-20160816; b=TQe9O2/SpJ44d+tNbq2B9otrafVCkSBwWCilgV3FN72gtLL7E3pmOeXq/qQ4L3HDfR hO9QttlsDE8GGs/zv81ciLjW2ZJ/dQSbkjMqXEl9BSbLhxjXUsfJ0E7/5UAS4tO2Edu2 lX6kBvTf8uHGlW1S1kzj5HYzcobQ2mtlY1L9Xv3AjMIV1cvrj2vAqcAY8zmnfClRjng+ DRNd15XHfsC/sDHS8tVAQ9rt/jg17YRaP0nl0arOdEYjfAHHIn0QOglh+h+JSxLp9iFt lpprbW8NYzFnD9V/iMEVuLgrDiOhc8zWIqah8dUj/53SXyVEilmAazZf5wvxoJm8VHX3 7t3A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=iWbH16eFbLXNkjHqv229qZ+4HX6NSeX5YBE4Euiqfoo=; fh=xmAeKtysnShNOmkhiJmYkS30uw4Fu2hvBJ7qlIwukxQ=; b=z48GMp40IIRyIC/p4ai5WRIURspcbx7qPCCi5DNVyk8uNwg+Os040rL/yc3Si37DU6 YJRqLgeA41nKTbzI5p/PsC+KG17gCQV46h56Qiu4mtQEjcLHGKtrEKbQ8XigYPuHiART hdE04ZCKrr1LjejxLvgBmDu8H6WhAfmxo//fnCsQvWKuHE8sZoninIiJEdPRtSuHbNz/ upEYsLjm1Nvo+GtHuVqH2UBlbyU7TMSqGvrYX0i9g7eqTCnJT7F+XQFiEoBp1EMS/eKH L3Q+ZP09q9PyuFkmwk+0V8kepDgsd5+bqc4qSz0EvRhQEe0BeBv0/TJ8ZUeFNRBY8/oA +j9Q==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=runEExW5; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id i20-20020a170906265400b00a51b092ed1esi1608994ejc.447.2024.04.12.04.38.29; Fri, 12 Apr 2024 04:38:30 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=runEExW5; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 4C10D68D2EB; Fri, 12 Apr 2024 14:36:43 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 8CB8168D282 for ; Fri, 12 Apr 2024 14:36:28 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1712921784; bh=kzMzxPg2La4lQpaCiDZf16/uOBW7MakFmlcmUXida+8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=runEExW5FGcCUFPMns+pHFl/eYdC35xiBNIJ1F7p26aDjHMpKvCKoT+JjwJFe3xiA 3FbNVwjO8aT812sR0+yhFwvRW6STKjHlGdX4WVEDKbtECUuj6AOKp/Rxwvm/fAGNKU bI4nx+y6/45aj0PgifnwarxR25bt7lFrPrBbktmk= Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id 7EDB34344E; Fri, 12 Apr 2024 13:36:24 +0200 (CEST) From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Fri, 12 Apr 2024 13:35:21 +0200 Message-ID: <20240412113620.84013-8-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240412113620.84013-1-ffmpeg@haasn.xyz> References: <20240412113620.84013-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 07/13] avcodec/dovi_rpuenc: add ff_dovi_configure() X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: en+oRsUeLVGA From: Niklas Haas We need to set up the configuration struct appropriately based on the codec type, colorspace metadata, and presence/absence of an EL (though, we currently don't support an EL). When present, we use the signalled RPU data header to help infer (and validate) the right values. Behavior can be controlled by a new DOVIContext.enable flag. --- configure | 2 + libavcodec/Makefile | 1 + libavcodec/dovi_rpu.h | 24 ++++- libavcodec/dovi_rpuenc.c | 203 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 libavcodec/dovi_rpuenc.c diff --git a/configure b/configure index c1e1ece1e2..d25d0f6907 100755 --- a/configure +++ b/configure @@ -2551,6 +2551,7 @@ CONFIG_EXTRA=" dirac_parse dnn dovi_rpudec + dovi_rpuenc dvprofile evcparse exif @@ -2842,6 +2843,7 @@ cbs_vp9_select="cbs" deflate_wrapper_deps="zlib" dirac_parse_select="golomb" dovi_rpudec_select="golomb" +dovi_rpuenc_select="golomb" dnn_suggest="libtensorflow libopenvino libtorch" dnn_deps="avformat swscale" error_resilience_select="me_cmp" diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 45058eb8d2..6bddb6fb5e 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -86,6 +86,7 @@ OBJS-$(CONFIG_CBS_VP8) += cbs_vp8.o vp8data.o OBJS-$(CONFIG_CBS_VP9) += cbs_vp9.o OBJS-$(CONFIG_DEFLATE_WRAPPER) += zlib_wrapper.o OBJS-$(CONFIG_DOVI_RPUDEC) += dovi_rpu.o dovi_rpudec.o +OBJS-$(CONFIG_DOVI_RPUENC) += dovi_rpu.o dovi_rpuenc.o OBJS-$(CONFIG_ERROR_RESILIENCE) += error_resilience.o OBJS-$(CONFIG_EVCPARSE) += evc_parse.o evc_ps.o OBJS-$(CONFIG_EXIF) += exif.o tiff_common.o diff --git a/libavcodec/dovi_rpu.h b/libavcodec/dovi_rpu.h index 0c12a3fee0..3e80647422 100644 --- a/libavcodec/dovi_rpu.h +++ b/libavcodec/dovi_rpu.h @@ -26,14 +26,25 @@ #include "libavutil/dovi_meta.h" #include "libavutil/frame.h" +#include "avcodec.h" #define DOVI_MAX_DM_ID 15 typedef struct DOVIContext { void *logctx; + /** + * Enable tri-state. + * + * For encoding, FF_DOVI_AUTOMATIC enables Dolby Vision only if + * avctx->decoded_side_data contains an AVDOVIMetadata. + */ +#define FF_DOVI_AUTOMATIC -1 + int enable; + /** * Currently active dolby vision configuration, or {0} for none. - * Set by the user when decoding. + * Set by the user when decoding. Generated by ff_dovi_configure() + * when encoding. * * Note: sizeof(cfg) is not part of the libavutil ABI, so users should * never pass &cfg to any other library calls. This is included merely as @@ -100,6 +111,17 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, */ int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame); +/** + * Configure the encoder for Dolby Vision encoding. Generates a configuration + * record in s->cfg, and attaches it to avctx->coded_side_data. Sets the correct + * profile and compatibility ID based on the tagged AVCodecContext colorspace + * metadata, and the correct level based on the resolution and tagged framerate. + * + * Returns 0 or a negative error code. + */ +int ff_dovi_configure(DOVIContext *s, AVCodecContext *avctx); + + /*************************************************** * The following section is for internal use only. * ***************************************************/ diff --git a/libavcodec/dovi_rpuenc.c b/libavcodec/dovi_rpuenc.c new file mode 100644 index 0000000000..3ab4624a79 --- /dev/null +++ b/libavcodec/dovi_rpuenc.c @@ -0,0 +1,203 @@ +/* + * Dolby Vision RPU encoder + * + * Copyright (C) 2024 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/mem.h" + +#include "avcodec.h" +#include "dovi_rpu.h" + +static struct { + uint64_t pps; // maximum pixels per second + int width; // maximum width + int main; // maximum bitrate in main tier + int high; // maximum bitrate in high tier +} dv_levels[] = { + [1] = {1280*720*24, 1280, 20, 50}, + [2] = {1280*720*30, 1280, 20, 50}, + [3] = {1920*1080*24, 1920, 20, 70}, + [4] = {1920*1080*30, 2560, 20, 70}, + [5] = {1920*1080*60, 3840, 20, 70}, + [6] = {3840*2160*24, 3840, 25, 130}, + [7] = {3840*2160*30, 3840, 25, 130}, + [8] = {3840*2160*48, 3840, 40, 130}, + [9] = {3840*2160*60, 3840, 40, 130}, + [10] = {3840*2160*120, 3840, 60, 240}, + [11] = {3840*2160*120, 7680, 60, 240}, + [12] = {7680*4320*60, 7680, 120, 450}, + [13] = {7680*4320*120u, 7680, 240, 800}, +}; + +int ff_dovi_configure(DOVIContext *s, AVCodecContext *avctx) +{ + AVDOVIDecoderConfigurationRecord *cfg; + const AVDOVIRpuDataHeader *hdr = NULL; + const AVFrameSideData *sd; + int dv_profile, dv_level, bl_compat_id; + size_t cfg_size; + uint64_t pps; + + if (!s->enable) + goto skip; + + sd = av_frame_side_data_get(avctx->decoded_side_data, + avctx->nb_decoded_side_data, AV_FRAME_DATA_DOVI_METADATA); + + if (sd) + hdr = av_dovi_get_header((const AVDOVIMetadata *) sd->data); + + if (s->enable == FF_DOVI_AUTOMATIC && !hdr) + goto skip; + + switch (avctx->codec_id) { + case AV_CODEC_ID_AV1: dv_profile = 10; break; + case AV_CODEC_ID_H264: dv_profile = 9; break; + case AV_CODEC_ID_HEVC: dv_profile = hdr ? ff_dovi_guess_profile_hevc(hdr) : 8; break; + default: + /* No other encoder should be calling this! */ + av_assert0(0); + return AVERROR_BUG; + } + + if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) { + if (dv_profile == 9) { + if (avctx->pix_fmt != AV_PIX_FMT_YUV420P) + dv_profile = 0; + } else { + if (avctx->pix_fmt != AV_PIX_FMT_YUV420P10) + dv_profile = 0; + } + } + + switch (dv_profile) { + case 0: /* None */ + bl_compat_id = -1; + break; + case 4: /* HEVC with enhancement layer */ + case 7: + if (s->enable > 0) { + av_log(s->logctx, AV_LOG_ERROR, "Coding of Dolby Vision enhancement " + "layers is currently unsupported."); + return AVERROR_PATCHWELCOME; + } else { + goto skip; + } + case 5: /* HEVC with proprietary IPTPQc2 */ + bl_compat_id = 0; + break; + case 10: + /* FIXME: check for proper H.273 tags once those are added */ + if (hdr && hdr->bl_video_full_range_flag) { + /* AV1 with proprietary IPTPQc2 */ + bl_compat_id = 0; + break; + } + /* fall through */ + case 8: /* HEVC (or AV1) with BL compatibility */ + if (avctx->colorspace == AVCOL_SPC_BT2020_NCL && + avctx->color_primaries == AVCOL_PRI_BT2020 && + avctx->color_trc == AVCOL_TRC_SMPTE2084) { + bl_compat_id = 1; + } else if (avctx->colorspace == AVCOL_SPC_BT2020_NCL && + avctx->color_primaries == AVCOL_PRI_BT2020 && + avctx->color_trc == AVCOL_TRC_ARIB_STD_B67) { + bl_compat_id = 4; + } else if (avctx->colorspace == AVCOL_SPC_BT709 && + avctx->color_primaries == AVCOL_PRI_BT709 && + avctx->color_trc == AVCOL_TRC_BT709) { + bl_compat_id = 2; + } else { + /* Not a valid colorspace combination */ + bl_compat_id = -1; + } + } + + if (!dv_profile || bl_compat_id < 0) { + if (s->enable > 0) { + av_log(s->logctx, AV_LOG_ERROR, "Dolby Vision enabled, but could " + "not determine profile and compaatibility mode. Double-check " + "colorspace and format settings for compatibility?\n"); + return AVERROR(EINVAL); + } + goto skip; + } + + pps = avctx->width * avctx->height; + if (avctx->framerate.num) { + pps = pps * avctx->framerate.num / avctx->framerate.den; + } else { + pps *= 25; /* sanity fallback */ + } + + dv_level = 0; + for (int i = 1; i < FF_ARRAY_ELEMS(dv_levels); i++) { + if (pps > dv_levels[i].pps) + continue; + if (avctx->width > dv_levels[i].width) + continue; + /* In theory, we should also test the bitrate when known, and + * distinguish between main and high tier. In practice, just ignore + * the bitrate constraints and hope they work out. This would ideally + * be handled by either the encoder or muxer directly. */ + dv_level = i; + break; + } + + if (!dv_level) { + if (avctx->strict_std_compliance >= FF_COMPLIANCE_STRICT) { + av_log(s->logctx, AV_LOG_ERROR, "Coded PPS (%"PRIu64") and width (%d) " + "exceed Dolby Vision limitations\n", pps, avctx->width); + return AVERROR(EINVAL); + } else { + av_log(s->logctx, AV_LOG_WARNING, "Coded PPS (%"PRIu64") and width (%d) " + "exceed Dolby Vision limitations. Ignoring, resulting file " + "may be non-conforming.\n", pps, avctx->width); + dv_level = FF_ARRAY_ELEMS(dv_levels) - 1; + } + } + + cfg = av_dovi_alloc(&cfg_size); + if (!cfg) + return AVERROR(ENOMEM); + + if (!av_packet_side_data_add(&avctx->coded_side_data, &avctx->nb_coded_side_data, + AV_PKT_DATA_DOVI_CONF, cfg, cfg_size, 0)) { + av_free(cfg); + return AVERROR(ENOMEM); + } + + cfg->dv_version_major = 1; + cfg->dv_version_minor = 0; + cfg->dv_profile = dv_profile; + cfg->dv_level = dv_level; + cfg->rpu_present_flag = 1; + cfg->el_present_flag = 0; + cfg->bl_present_flag = 1; + cfg->dv_bl_signal_compatibility_id = bl_compat_id; + + s->cfg = *cfg; + return 0; + +skip: + s->cfg = (AVDOVIDecoderConfigurationRecord) {0}; + return 0; +} From patchwork Fri Apr 12 11:35:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 48026 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:670b:b0:1a9:af23:56c1 with SMTP id wh11csp203321pzb; Fri, 12 Apr 2024 04:38:22 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCXRSvlHd9ciXXUQRRDUh5PE8DVhfzIshBkj9l1LQ9n0zvDxw0Ntfcy6fEAiTRZjnSHDN1/cUj9OGSJ7lsDkWF704FWpW2AV+8AwGw== X-Google-Smtp-Source: AGHT+IGKzw+R2rBAJ+1mQ6TGC/fjc1Zy8wmyQ6U9uydwja+elmYLbhxPS14cyhd5En0MyMJV9YkN X-Received: by 2002:a50:d553:0:b0:56e:2c34:cfec with SMTP id f19-20020a50d553000000b0056e2c34cfecmr1585145edj.7.1712921902093; Fri, 12 Apr 2024 04:38:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1712921902; cv=none; d=google.com; s=arc-20160816; b=0XKRJmgLsYTYZe+uBbMbxTUaVraZI7FXmBrgXNDf7lUU0I+M2X3Vh09F6KcMBN27Yx N+vE5L9v1ozgXug8xpKsVmyb85hCZ1lPWaHgzlYCOSb5jI7LpWtzZvPefLGlkO8O7dlg agZh2a5D4voG+Q99ssIAKA1Lz2Oh6xIBrzveJwNe1gICh8jC4TLDeEALZ1xIxQD+1xB4 Jz7hfXdngl70dq/egyeJawVLpJgHakbi4iIOrQIJaPvCFJcQcOUHLU4LV9L8Kv9pRGMo RHNr9s7rJc/SpwFscZTmJMtmgKVQPbUE5k/TeC6yRKbkmEPZV9KGJViRIJGQH/udn0h9 t+cw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=wESPbSV6AFR8qOACHOM/C3osy2jMEGY66wgsCiH49i8=; fh=xmAeKtysnShNOmkhiJmYkS30uw4Fu2hvBJ7qlIwukxQ=; b=Wf8tuu3zSO0PH8A4fWn5Ht8otqN5APwEeH9+G3696HwP7QJ/tdUxcnTV/+TNoW+tQR SYAZBblD8rN360X4UHok1jCiIT3NnAvISlIiaIVdkKK3678iAXRilU53wa4Vra3ddO58 MI2jJH5rsmMj2kuAf2PyQOgHvqA6J310MQf9UxMF63HBsZ8bV6j6z8WE2EmU+zsW/hxf Kb0cVy9g9G81IqpbqLod3RV396suK+gD+Mxqt2UtdwbhMwPU/50hp4yPvkIdejXinDBC yU8tVJHcljpsPJr6I7AG0XBKr2tGGDuq3Gkl14mBYwhu1SJoECai7iwQBLSmhTsajOuD y/Hg==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=UyNFlIur; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id v3-20020a056402348300b0056e6a034b34si1699462edc.86.2024.04.12.04.38.21; Fri, 12 Apr 2024 04:38:22 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=UyNFlIur; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 39E5E68D2E6; Fri, 12 Apr 2024 14:36:42 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 88E2068D287 for ; Fri, 12 Apr 2024 14:36:28 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1712921784; bh=OF5K2+MnCdQNVC5/EpA/tzLhL5o6SxYeNjxqB/D2xyw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UyNFlIur6mg/mGwDR0bxy13UaFB0VeoG4b/EsAN7omCn/btTb4QHibOTbo6GV+CZ8 /V28NSW75O9yVaSIHRa62XTvSy6XyXN0fyJf52Hz61+arfji7o3jFNhxc5dt+QRtnr WGQisWv6KLbNp2LPVFM21M4lGDMpmh3O9poB83FQ= Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id B56DB43462; Fri, 12 Apr 2024 13:36:24 +0200 (CEST) From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Fri, 12 Apr 2024 13:35:22 +0200 Message-ID: <20240412113620.84013-9-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240412113620.84013-1-ffmpeg@haasn.xyz> References: <20240412113620.84013-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 08/13] avcodec/dovi_rpudec: make `enable` also affect decoding X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: qOzR0sBGYKpQ From: Niklas Haas This could be used by codecs to selectively disable parsing Dolby Vision RPUs, and is cheap to support. --- libavcodec/av1dec.c | 1 + libavcodec/dovi_rpu.h | 2 ++ libavcodec/dovi_rpudec.c | 6 ++++++ libavcodec/hevcdec.c | 1 + libavcodec/libdav1d.c | 1 + 5 files changed, 11 insertions(+) diff --git a/libavcodec/av1dec.c b/libavcodec/av1dec.c index 4c1405df77..20865b4f12 100644 --- a/libavcodec/av1dec.c +++ b/libavcodec/av1dec.c @@ -1551,6 +1551,7 @@ static void av1_decode_flush(AVCodecContext *avctx) static const AVOption av1_options[] = { { "operating_point", "Select an operating point of the scalable bitstream", OFFSET(operating_point), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, AV1_MAX_OPERATING_POINTS - 1, VD }, + { "dolbyvision", "Decode Dolby Vision RPUs", OFFSET(dovi.enable), AV_OPT_TYPE_BOOL, {.i64 = 1 }, 0, 1, VD }, { NULL } }; diff --git a/libavcodec/dovi_rpu.h b/libavcodec/dovi_rpu.h index 3e80647422..8f8905b96b 100644 --- a/libavcodec/dovi_rpu.h +++ b/libavcodec/dovi_rpu.h @@ -37,6 +37,8 @@ typedef struct DOVIContext { * * For encoding, FF_DOVI_AUTOMATIC enables Dolby Vision only if * avctx->decoded_side_data contains an AVDOVIMetadata. + * + * For decoding, FF_DOVI_AUTOMATIC has the same meaning as 1. */ #define FF_DOVI_AUTOMATIC -1 int enable; diff --git a/libavcodec/dovi_rpudec.c b/libavcodec/dovi_rpudec.c index 7c7eda9d09..978d5dfc2b 100644 --- a/libavcodec/dovi_rpudec.c +++ b/libavcodec/dovi_rpudec.c @@ -37,6 +37,9 @@ int ff_dovi_attach_side_data(DOVIContext *s, AVFrame *frame) AVDOVIMetadata *dovi; size_t dovi_size, ext_sz; + if (!s->enable) + return 0; + if (!s->mapping || !s->color) return 0; /* incomplete dovi metadata */ @@ -306,6 +309,9 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, uint8_t use_nlq; uint8_t profile; + if (!s->enable) + return 0; + if (rpu_size < 5) goto fail; diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c index 7825efe2e6..c622a48b94 100644 --- a/libavcodec/hevcdec.c +++ b/libavcodec/hevcdec.c @@ -3694,6 +3694,7 @@ static const AVOption options[] = { AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, PAR }, { "strict-displaywin", "stricly apply default display window size", OFFSET(apply_defdispwin), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, PAR }, + { "dolbyvision", "Decode Dolby Vision RPUs", OFFSET(dovi_ctx.enable), AV_OPT_TYPE_BOOL, {.i64 = 1 }, 0, 1, PAR }, { NULL }, }; diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c index 09fe767fb8..f9e1a181fc 100644 --- a/libavcodec/libdav1d.c +++ b/libavcodec/libdav1d.c @@ -674,6 +674,7 @@ static const AVOption libdav1d_options[] = { { "filmgrain", "Apply Film Grain", OFFSET(apply_grain), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VD | AV_OPT_FLAG_DEPRECATED }, { "oppoint", "Select an operating point of the scalable bitstream", OFFSET(operating_point), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 31, VD }, { "alllayers", "Output all spatial layers", OFFSET(all_layers), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VD }, + { "dolbyvision", "Decode Dolby Vision RPUs", OFFSET(dovi.enable), AV_OPT_TYPE_BOOL, {.i64 = 1 }, 0, 1, VD }, { NULL } }; From patchwork Fri Apr 12 11:35:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 48018 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:670b:b0:1a9:af23:56c1 with SMTP id wh11csp202733pzb; Fri, 12 Apr 2024 04:37:02 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCU8cOeFBhT9bXD+bufGaSdOtLrlKyBQ93NmhXTy03jM4LgVwUeu2LgxVWZTZD+W43SbmxO9KZ4AQYEsBuzD30N3LoI2VkMVUlz6gw== X-Google-Smtp-Source: AGHT+IGQjB3GRJQ70PpwEY415aiXTamurstK6TPY9+MEmkEyhISkfhWUzT9KwouRawtJWOj5fvU5 X-Received: by 2002:a17:907:97c6:b0:a51:caf7:ccc2 with SMTP id js6-20020a17090797c600b00a51caf7ccc2mr2363356ejc.34.1712921822239; Fri, 12 Apr 2024 04:37:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1712921822; cv=none; d=google.com; s=arc-20160816; b=B3s6y2M6RD4xfCzKVRg3OqIwPMDhZaEcpm34FknHukz5X0XjqZi8xWZB8hfggItEnC RaxowQ8RN6EgR1y9fr4ONI2EZY2Ub3GR4Gf94eldL/Ug3DswBfhRh1VebQWVOk13y6NE A8FHWCiBqubzSsk1v2Dtp4pfBfi47wdykrW294A3PqZ6lsQy0VENh3b9L1wLXHhgDT4D KLXSqhhjdoI4UyeBwTjT2Dmy7Mk1KG0RadmWTMYnqjrPZC7LR9vJOGQVMvQQSo+61wmu gjUANm9VqmHzKsAkLqNJE16DufjMqj6joen0yyZrjiJ/NCEDz7+j3IcMq43/mp60l0/W Gy0g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=ASzQIHVgzvzh5f3QewIFbhZzvWgfC7DvkUVKp4IL1Qc=; fh=xmAeKtysnShNOmkhiJmYkS30uw4Fu2hvBJ7qlIwukxQ=; b=Si3Snbp072/8z0b478rm/GzbaNAMgEiq31ertmryy+x/dqOjwphgH8Tz87tGQ/Ox1n 9kQeGUKpGnyqyMPAQaCUfxOLX2Ycux2f3HbuKTREcwgUvfAU0S4GVSLzUe1eZRoBT2fH jcFJq1wALwpxDMN8vvYJMhc7ZVmEDPR7NTGExZ9VthUtt3yGtoO6G1XD+khFN9PbvHGL 5xvBTtn482exjFAo6unUZgPeJosSqEU579XIAsaSDbfgtEsGo3hnBLLC8zApfu1iyM/r UFWMaKWai3fd1AuGN4/j86eip7pnYAvqMknwP4fo6QmuusGMw4qcPwwx84y4+qgKXVUT iwSw==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=FCA43IhS; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id ga37-20020a1709070c2500b00a52274aaf58si1348975ejc.938.2024.04.12.04.37.01; Fri, 12 Apr 2024 04:37:02 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=FCA43IhS; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 7E85568D27F; Fri, 12 Apr 2024 14:36:33 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id C1ED068CD7D for ; Fri, 12 Apr 2024 14:36:28 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1712921784; bh=LU9dW+CVgN7gjmRUVpYViJJKZGdyPO1OLl0sSKtWGko=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FCA43IhSba9q55ddmXhl9qsZLRrdzj0YQR2+FWoBOYUncKIfJmw/5FT1MH5GYt/KK y/FjPXW4/6vFq2hyczxhVWWHv055qD7JCHU9vKFy9e3w9vrkwWCLT35RekEqwSTpUm ZPEDfmPG9+gYsHxIgRf3nbr5jcBX8lUP4xuEXIGQ= Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id E8D9143504; Fri, 12 Apr 2024 13:36:24 +0200 (CEST) From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Fri, 12 Apr 2024 13:35:23 +0200 Message-ID: <20240412113620.84013-10-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240412113620.84013-1-ffmpeg@haasn.xyz> References: <20240412113620.84013-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 09/13] avcodec/dovi_rpuenc: add ff_dovi_rpu_generate() X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: 4Dlo0yrceWee From: Niklas Haas This function takes a decoded AVDOVIMetadata struct and turns it back into a binary RPU. Verified using existing tools, and matches the bitstream in official reference files. I decided to just roll the EMDF and NAL encapsulation into this function because the end user will need to do it otherwise anyways. --- libavcodec/dovi_rpu.h | 20 +- libavcodec/dovi_rpuenc.c | 544 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 562 insertions(+), 2 deletions(-) diff --git a/libavcodec/dovi_rpu.h b/libavcodec/dovi_rpu.h index 8f8905b96b..1b74548e89 100644 --- a/libavcodec/dovi_rpu.h +++ b/libavcodec/dovi_rpu.h @@ -55,20 +55,22 @@ typedef struct DOVIContext { AVDOVIDecoderConfigurationRecord cfg; /** - * Currently active RPU data header, updates on every dovi_rpu_parse(). + * Currently active RPU data header, updates on every ff_dovi_rpu_parse() + * or ff_dovi_rpu_generate(). */ AVDOVIRpuDataHeader header; /** * Currently active data mappings, or NULL. Points into memory owned by the * corresponding rpu/vdr_ref, which becomes invalid on the next call to - * dovi_rpu_parse. + * ff_dovi_rpu_parse() or ff_dovi_rpu_generate(). */ const AVDOVIDataMapping *mapping; const AVDOVIColorMetadata *color; /** * Currently active extension blocks, updates on every ff_dovi_rpu_parse() + * or ff_dovi_rpu_generate(). */ AVDOVIDmData *ext_blocks; int num_ext_blocks; @@ -138,6 +140,20 @@ enum { RPU_COEFF_FLOAT = 1, }; +/** + * Synthesize a Dolby Vision RPU reflecting the current state. Note that this + * assumes all previous calls to `ff_dovi_rpu_generate` have been appropriately + * signalled, i.e. it will not re-send already transmitted redundant data. + * + * Mutates the internal state of DOVIContext to reflect the change. + * Returns 0 or a negative error code. + * + * This generates a fully formed RPU ready for inclusion in the bitstream, + * including the EMDF header (profile 10) or NAL encapsulation (otherwise). + */ +int ff_dovi_rpu_generate(DOVIContext *s, const AVDOVIMetadata *metadata, + uint8_t **out_rpu, int *out_size); + /** * Internal helper function to guess the correct DV profile for HEVC. * diff --git a/libavcodec/dovi_rpuenc.c b/libavcodec/dovi_rpuenc.c index 3ab4624a79..8b99bf12d9 100644 --- a/libavcodec/dovi_rpuenc.c +++ b/libavcodec/dovi_rpuenc.c @@ -21,10 +21,15 @@ */ #include "libavutil/avassert.h" +#include "libavutil/crc.h" #include "libavutil/mem.h" #include "avcodec.h" #include "dovi_rpu.h" +#include "itut35.h" +#include "put_bits.h" +#include "put_golomb.h" +#include "refstruct.h" static struct { uint64_t pps; // maximum pixels per second @@ -201,3 +206,542 @@ skip: s->cfg = (AVDOVIDecoderConfigurationRecord) {0}; return 0; } + +static inline void put_ue_coef(PutBitContext *pb, const AVDOVIRpuDataHeader *hdr, + uint64_t coef) +{ + union { uint32_t u32; float f32; } fpart; + + switch (hdr->coef_data_type) { + case RPU_COEFF_FIXED: + set_ue_golomb(pb, coef >> hdr->coef_log2_denom); + put_bits64(pb, hdr->coef_log2_denom, + coef & ((1LL << hdr->coef_log2_denom) - 1)); + break; + case RPU_COEFF_FLOAT: + fpart.f32 = coef / (float) (1LL << hdr->coef_log2_denom); + put_bits64(pb, hdr->coef_log2_denom, fpart.u32); + break; + } +} + +static inline void put_se_coef(PutBitContext *pb, const AVDOVIRpuDataHeader *hdr, + uint64_t coef) +{ + union { uint32_t u32; float f32; } fpart; + + switch (hdr->coef_data_type) { + case RPU_COEFF_FIXED: + set_se_golomb(pb, coef >> hdr->coef_log2_denom); + put_bits64(pb, hdr->coef_log2_denom, + coef & ((1LL << hdr->coef_log2_denom) - 1)); + break; + case RPU_COEFF_FLOAT: + fpart.f32 = coef / (float) (1LL << hdr->coef_log2_denom); + put_bits64(pb, hdr->coef_log2_denom, fpart.u32); + break; + } +} + +static int av_q2den(AVRational q, int den) +{ + if (q.den == den) + return q.num; + q = av_mul_q(q, av_make_q(den, 1)); + return (q.num + (q.den >> 1)) / q.den; +} + +static void generate_ext_v1(PutBitContext *pb, const AVDOVIDmData *dm) +{ + int ext_block_length, start_pos, pad_bits; + + switch (dm->level) { + case 1: ext_block_length = 5; break; + case 2: ext_block_length = 11; break; + case 4: ext_block_length = 3; break; + case 5: ext_block_length = 7; break; + case 6: ext_block_length = 8; break; + case 255: ext_block_length = 6; break; + default: return; + } + + set_ue_golomb(pb, ext_block_length); + put_bits(pb, 8, dm->level); + start_pos = put_bits_count(pb); + + switch (dm->level) { + case 1: + put_bits(pb, 12, dm->l1.min_pq); + put_bits(pb, 12, dm->l1.max_pq); + put_bits(pb, 12, dm->l1.avg_pq); + break; + case 2: + put_bits(pb, 12, dm->l2.target_max_pq); + put_bits(pb, 12, dm->l2.trim_slope); + put_bits(pb, 12, dm->l2.trim_offset); + put_bits(pb, 12, dm->l2.trim_power); + put_bits(pb, 12, dm->l2.trim_chroma_weight); + put_bits(pb, 12, dm->l2.trim_saturation_gain); + put_bits(pb, 13, dm->l2.ms_weight + 8192); + break; + case 4: + put_bits(pb, 12, dm->l4.anchor_pq); + put_bits(pb, 12, dm->l4.anchor_power); + break; + case 5: + put_bits(pb, 13, dm->l5.left_offset); + put_bits(pb, 13, dm->l5.right_offset); + put_bits(pb, 13, dm->l5.top_offset); + put_bits(pb, 13, dm->l5.bottom_offset); + break; + case 6: + put_bits(pb, 16, dm->l6.max_luminance); + put_bits(pb, 16, dm->l6.min_luminance); + put_bits(pb, 16, dm->l6.max_cll); + put_bits(pb, 16, dm->l6.max_fall); + break; + case 255: + put_bits(pb, 8, dm->l255.dm_run_mode); + put_bits(pb, 8, dm->l255.dm_run_version); + for (int i = 0; i < 4; i++) + put_bits(pb, 8, dm->l255.dm_debug[i]); + break; + } + + pad_bits = ext_block_length * 8 - (put_bits_count(pb) - start_pos); + av_assert1(pad_bits >= 0); + put_bits(pb, pad_bits, 0); +} + +static void put_cie_xy(PutBitContext *pb, AVCIExy xy) +{ + const int denom = 32767; + put_sbits(pb, 16, av_q2den(xy.x, denom)); + put_sbits(pb, 16, av_q2den(xy.y, denom)); +} + +#define ANY6(arr) (arr[0] || arr[1] || arr[2] || arr[3] || arr[4] || arr[5]) +#define ANY_XY(xy) (xy.x.num || xy.y.num) +#define ANY_CSP(csp) (ANY_XY(csp.prim.r) || ANY_XY(csp.prim.g) || \ + ANY_XY(csp.prim.b) || ANY_XY(csp.wp)) + +static void generate_ext_v2(PutBitContext *pb, const AVDOVIDmData *dm) +{ + int ext_block_length, start_pos, pad_bits; + + switch (dm->level) { + case 3: ext_block_length = 5; break; + case 8: + if (ANY6(dm->l8.hue_vector_field)) { + ext_block_length = 25; + } else if (ANY6(dm->l8.saturation_vector_field)) { + ext_block_length = 19; + } else if (dm->l8.clip_trim) { + ext_block_length = 13; + } else if (dm->l8.target_mid_contrast) { + ext_block_length = 12; + } else { + ext_block_length = 10; + } + break; + case 9: + if (ANY_CSP(dm->l9.source_display_primaries)) { + ext_block_length = 17; + } else { + ext_block_length = 1; + } + break; + case 10: + if (ANY_CSP(dm->l10.target_display_primaries)) { + ext_block_length = 21; + } else { + ext_block_length = 5; + } + break; + case 11: ext_block_length = 4; break; + case 254: ext_block_length = 2; break; + default: return; + } + + set_ue_golomb(pb, ext_block_length); + put_bits(pb, 8, dm->level); + start_pos = put_bits_count(pb); + + switch (dm->level) { + case 3: + put_bits(pb, 12, dm->l3.min_pq_offset); + put_bits(pb, 12, dm->l3.max_pq_offset); + put_bits(pb, 12, dm->l3.avg_pq_offset); + break; + case 8: + put_bits(pb, 8, dm->l8.target_display_index); + put_bits(pb, 12, dm->l8.trim_slope); + put_bits(pb, 12, dm->l8.trim_offset); + put_bits(pb, 12, dm->l8.trim_power); + put_bits(pb, 12, dm->l8.trim_chroma_weight); + put_bits(pb, 12, dm->l8.trim_saturation_gain); + put_bits(pb, 12, dm->l8.ms_weight + 8192); + if (ext_block_length < 12) + break; + put_bits(pb, 12, dm->l8.target_mid_contrast); + if (ext_block_length < 13) + break; + put_bits(pb, 12, dm->l8.clip_trim); + if (ext_block_length < 19) + break; + for (int i = 0; i < 6; i++) + put_bits(pb, 8, dm->l8.saturation_vector_field[i]); + if (ext_block_length < 25) + break; + for (int i = 0; i < 6; i++) + put_bits(pb, 8, dm->l8.hue_vector_field[i]); + break; + case 9: + put_bits(pb, 8, dm->l9.source_primary_index); + if (ext_block_length < 17) + break; + put_cie_xy(pb, dm->l9.source_display_primaries.prim.r); + put_cie_xy(pb, dm->l9.source_display_primaries.prim.g); + put_cie_xy(pb, dm->l9.source_display_primaries.prim.b); + put_cie_xy(pb, dm->l9.source_display_primaries.wp); + break; + case 10: + put_bits(pb, 8, dm->l10.target_display_index); + put_bits(pb, 12, dm->l10.target_max_pq); + put_bits(pb, 12, dm->l10.target_min_pq); + put_bits(pb, 8, dm->l10.target_primary_index); + if (ext_block_length < 21) + break; + put_cie_xy(pb, dm->l10.target_display_primaries.prim.r); + put_cie_xy(pb, dm->l10.target_display_primaries.prim.g); + put_cie_xy(pb, dm->l10.target_display_primaries.prim.b); + put_cie_xy(pb, dm->l10.target_display_primaries.wp); + break; + case 11: + put_bits(pb, 8, dm->l11.content_type); + put_bits(pb, 4, dm->l11.whitepoint); + put_bits(pb, 1, dm->l11.reference_mode_flag); + put_bits(pb, 3, 0); /* reserved */ + put_bits(pb, 2, dm->l11.sharpness); + put_bits(pb, 2, dm->l11.noise_reduction); + put_bits(pb, 2, dm->l11.mpeg_noise_reduction); + put_bits(pb, 2, dm->l11.frame_rate_conversion); + put_bits(pb, 2, dm->l11.brightness); + put_bits(pb, 2, dm->l11.color); + break; + case 254: + put_bits(pb, 8, dm->l254.dm_mode); + put_bits(pb, 8, dm->l254.dm_version_index); + break; + } + + pad_bits = ext_block_length * 8 - (put_bits_count(pb) - start_pos); + av_assert1(pad_bits >= 0); + put_bits(pb, pad_bits, 0); +} + +int ff_dovi_rpu_generate(DOVIContext *s, const AVDOVIMetadata *metadata, + uint8_t **out_rpu, int *out_size) +{ + PutBitContext *pb = &(PutBitContext){0}; + const AVDOVIRpuDataHeader *hdr; + const AVDOVIDataMapping *mapping; + const AVDOVIColorMetadata *color; + int vdr_dm_metadata_changed, vdr_rpu_id, use_prev_vdr_rpu, profile, + buffer_size, rpu_size, pad, zero_run; + int num_ext_blocks_v1, num_ext_blocks_v2; + uint32_t crc; + uint8_t *dst; + if (!metadata) { + *out_rpu = NULL; + *out_size = 0; + return 0; + } + + hdr = av_dovi_get_header(metadata); + mapping = av_dovi_get_mapping(metadata); + color = av_dovi_get_color(metadata); + av_assert0(s->cfg.dv_profile); + + if (hdr->rpu_type != 2) { + av_log(s->logctx, AV_LOG_ERROR, "Unhandled RPU type %"PRIu8"\n", + hdr->rpu_type); + return AVERROR_INVALIDDATA; + } + + vdr_rpu_id = -1; + for (int i = 0; i <= DOVI_MAX_DM_ID; i++) { + if (s->vdr[i] && !memcmp(&s->vdr[i]->mapping, mapping, sizeof(*mapping))) { + vdr_rpu_id = i; + break; + } else if (vdr_rpu_id < 0 && (!s->vdr[i] || i == DOVI_MAX_DM_ID)) { + vdr_rpu_id = i; + } + } + + if (!s->vdr[vdr_rpu_id]) { + s->vdr[vdr_rpu_id] = ff_refstruct_allocz(sizeof(DOVIVdr)); + if (!s->vdr[vdr_rpu_id]) + return AVERROR(ENOMEM); + } + + if (!s->vdr[color->dm_metadata_id]) { + s->vdr[color->dm_metadata_id] = ff_refstruct_allocz(sizeof(DOVIVdr)); + if (!s->vdr[color->dm_metadata_id]) + return AVERROR(ENOMEM); + } + + num_ext_blocks_v1 = num_ext_blocks_v2 = 0; + for (int i = 0; i < metadata->num_ext_blocks; i++) { + const AVDOVIDmData *dm = av_dovi_get_ext(metadata, i); + switch (dm->level) { + case 1: + case 2: + case 4: + case 5: + case 6: + case 255: + num_ext_blocks_v1++; + break; + case 3: + case 8: + case 9: + case 10: + case 11: + case 254: + num_ext_blocks_v2++; + break; + default: + av_log(s->logctx, AV_LOG_ERROR, "Invalid ext block level %d\n", + dm->level); + return AVERROR_INVALIDDATA; + } + } + + vdr_dm_metadata_changed = !s->color || memcmp(s->color, color, sizeof(*color)); + use_prev_vdr_rpu = !memcmp(&s->vdr[vdr_rpu_id]->mapping, mapping, sizeof(*mapping)); + + buffer_size = 12 /* vdr seq info */ + 5 /* CRC32 + terminator */; + buffer_size += num_ext_blocks_v1 * 13; + buffer_size += num_ext_blocks_v2 * 28; + if (!use_prev_vdr_rpu) { + buffer_size += 160; + for (int c = 0; c < 3; c++) { + for (int i = 0; i < mapping->curves[c].num_pivots - 1; i++) { + switch (mapping->curves[c].mapping_idc[i]) { + case AV_DOVI_MAPPING_POLYNOMIAL: buffer_size += 26; break; + case AV_DOVI_MAPPING_MMR: buffer_size += 177; break; + } + } + } + } + if (vdr_dm_metadata_changed) + buffer_size += 67; + + av_fast_padded_malloc(&s->rpu_buf, &s->rpu_buf_sz, buffer_size); + if (!s->rpu_buf) + return AVERROR(ENOMEM); + init_put_bits(pb, s->rpu_buf, s->rpu_buf_sz); + + /* RPU header */ + put_bits(pb, 6, hdr->rpu_type); + put_bits(pb, 11, hdr->rpu_format); + put_bits(pb, 4, hdr->vdr_rpu_profile); + put_bits(pb, 4, hdr->vdr_rpu_level); + put_bits(pb, 1, 1); /* vdr_seq_info_present */ + put_bits(pb, 1, hdr->chroma_resampling_explicit_filter_flag); + put_bits(pb, 2, hdr->coef_data_type); + if (hdr->coef_data_type == RPU_COEFF_FIXED) + set_ue_golomb(pb, hdr->coef_log2_denom); + put_bits(pb, 2, hdr->vdr_rpu_normalized_idc); + put_bits(pb, 1, hdr->bl_video_full_range_flag); + if ((hdr->rpu_format & 0x700) == 0) { + set_ue_golomb(pb, hdr->bl_bit_depth - 8); + set_ue_golomb(pb, hdr->el_bit_depth - 8); + set_ue_golomb(pb, hdr->vdr_bit_depth - 8); + put_bits(pb, 1, hdr->spatial_resampling_filter_flag); + put_bits(pb, 3, 0); /* reserved_zero_3bits */ + put_bits(pb, 1, hdr->el_spatial_resampling_filter_flag); + put_bits(pb, 1, hdr->disable_residual_flag); + } + s->header = *hdr; + + put_bits(pb, 1, vdr_dm_metadata_changed); + put_bits(pb, 1, use_prev_vdr_rpu); + set_ue_golomb(pb, vdr_rpu_id); + s->mapping = &s->vdr[vdr_rpu_id]->mapping; + + if (!use_prev_vdr_rpu) { + set_ue_golomb(pb, mapping->mapping_color_space); + set_ue_golomb(pb, mapping->mapping_chroma_format_idc); + for (int c = 0; c < 3; c++) { + const AVDOVIReshapingCurve *curve = &mapping->curves[c]; + int prev = 0; + set_ue_golomb(pb, curve->num_pivots - 2); + for (int i = 0; i < curve->num_pivots; i++) { + put_bits(pb, hdr->bl_bit_depth, curve->pivots[i] - prev); + prev = curve->pivots[i]; + } + } + + if (mapping->nlq_method_idc != AV_DOVI_NLQ_NONE) { + put_bits(pb, 3, mapping->nlq_method_idc); + put_bits(pb, hdr->bl_bit_depth, mapping->nlq_pivots[0]); + put_bits(pb, hdr->bl_bit_depth, mapping->nlq_pivots[1] - mapping->nlq_pivots[0]); + } + + set_ue_golomb(pb, mapping->num_x_partitions - 1); + set_ue_golomb(pb, mapping->num_y_partitions - 1); + + for (int c = 0; c < 3; c++) { + const AVDOVIReshapingCurve *curve = &mapping->curves[c]; + for (int i = 0; i < curve->num_pivots - 1; i++) { + set_ue_golomb(pb, curve->mapping_idc[i]); + switch (curve->mapping_idc[i]) { + case AV_DOVI_MAPPING_POLYNOMIAL: { + set_ue_golomb(pb, curve->poly_order[i] - 1); + if (curve->poly_order[i] == 1) + put_bits(pb, 1, 0); /* linear_interp_flag */ + for (int k = 0; k <= curve->poly_order[i]; k++) + put_se_coef(pb, hdr, curve->poly_coef[i][k]); + break; + } + case AV_DOVI_MAPPING_MMR: { + put_bits(pb, 2, curve->mmr_order[i] - 1); + put_se_coef(pb, hdr, curve->mmr_constant[i]); + for (int j = 0; j < curve->mmr_order[i]; j++) { + for (int k = 0; k < 7; k++) + put_se_coef(pb, hdr, curve->mmr_coef[i][j][k]); + } + break; + } + } + } + } + + if (mapping->nlq_method_idc != AV_DOVI_NLQ_NONE) { + for (int c = 0; c < 3; c++) { + const AVDOVINLQParams *nlq = &mapping->nlq[c]; + put_bits(pb, hdr->el_bit_depth, nlq->nlq_offset); + put_ue_coef(pb, hdr, nlq->vdr_in_max); + switch (mapping->nlq_method_idc) { + case AV_DOVI_NLQ_LINEAR_DZ: + put_ue_coef(pb, hdr, nlq->linear_deadzone_slope); + put_ue_coef(pb, hdr, nlq->linear_deadzone_threshold); + break; + } + } + } + + memcpy(&s->vdr[vdr_rpu_id]->mapping, mapping, sizeof(*mapping)); + } + + if (vdr_dm_metadata_changed) { + const int denom = profile == 4 ? (1 << 30) : (1 << 28); + set_ue_golomb(pb, color->dm_metadata_id); /* affected_dm_id */ + set_ue_golomb(pb, color->dm_metadata_id); /* current_dm_id */ + set_ue_golomb(pb, color->scene_refresh_flag); + for (int i = 0; i < 9; i++) + put_sbits(pb, 16, av_q2den(color->ycc_to_rgb_matrix[i], 1 << 13)); + for (int i = 0; i < 3; i++) + put_bits32(pb, av_q2den(color->ycc_to_rgb_offset[i], denom)); + for (int i = 0; i < 9; i++) + put_sbits(pb, 16, av_q2den(color->rgb_to_lms_matrix[i], 1 << 14)); + put_bits(pb, 16, color->signal_eotf); + put_bits(pb, 16, color->signal_eotf_param0); + put_bits(pb, 16, color->signal_eotf_param1); + put_bits32(pb, color->signal_eotf_param2); + put_bits(pb, 5, color->signal_bit_depth); + put_bits(pb, 2, color->signal_color_space); + put_bits(pb, 2, color->signal_chroma_format); + put_bits(pb, 2, color->signal_full_range_flag); + put_bits(pb, 12, color->source_min_pq); + put_bits(pb, 12, color->source_max_pq); + put_bits(pb, 10, color->source_diagonal); + + memcpy(&s->vdr[color->dm_metadata_id]->color, color, sizeof(*color)); + s->color = &s->vdr[color->dm_metadata_id]->color; + } + + set_ue_golomb(pb, num_ext_blocks_v1); + align_put_bits(pb); + for (int i = 0; i < metadata->num_ext_blocks; i++) + generate_ext_v1(pb, av_dovi_get_ext(metadata, i)); + + if (num_ext_blocks_v2) { + set_ue_golomb(pb, num_ext_blocks_v2); + align_put_bits(pb); + for (int i = 0; i < metadata->num_ext_blocks; i++) + generate_ext_v2(pb, av_dovi_get_ext(metadata, i)); + } + + flush_put_bits(pb); + crc = av_bswap32(av_crc(av_crc_get_table(AV_CRC_32_IEEE), -1, + s->rpu_buf, put_bytes_output(pb))); + put_bits32(pb, crc); + put_bits(pb, 8, 0x80); /* terminator */ + flush_put_bits(pb); + + rpu_size = put_bytes_output(pb); + switch (s->cfg.dv_profile) { + case 10: + /* AV1 uses T.35 OBU with EMDF header */ + *out_rpu = av_malloc(rpu_size + 15); + if (!*out_rpu) + return AVERROR(ENOMEM); + init_put_bits(pb, *out_rpu, rpu_size + 15); + put_bits(pb, 8, ITU_T_T35_COUNTRY_CODE_US); + put_bits(pb, 16, ITU_T_T35_PROVIDER_CODE_DOLBY); + put_bits32(pb, 0x800); /* provider_oriented_code */ + put_bits(pb, 27, 0x01be6841u); /* fixed EMDF header, see above */ + if (rpu_size > 0xFF) { + av_assert2(rpu_size <= 0x10000); + put_bits(pb, 8, (rpu_size >> 8) - 1); + put_bits(pb, 1, 1); /* read_more */ + put_bits(pb, 8, rpu_size & 0xFF); + put_bits(pb, 1, 0); + } else { + put_bits(pb, 8, rpu_size); + put_bits(pb, 1, 0); + } + ff_copy_bits(pb, s->rpu_buf, rpu_size * 8); + put_bits(pb, 17, 0x400); /* emdf payload id + emdf_protection */ + + pad = pb->bit_left & 7; + put_bits(pb, pad, (1 << pad) - 1); /* pad to next byte with 1 bits */ + flush_put_bits(pb); + *out_size = put_bytes_output(pb); + return 0; + + case 5: + case 8: + *out_rpu = dst = av_malloc(1 + rpu_size * 3 / 2); /* worst case */ + if (!*out_rpu) + return AVERROR(ENOMEM); + *dst++ = 25; /* NAL prefix */ + zero_run = 0; + for (int i = 0; i < rpu_size; i++) { + if (zero_run < 2) { + if (s->rpu_buf[i] == 0) { + zero_run++; + } else { + zero_run = 0; + } + } else { + if ((s->rpu_buf[i] & ~3) == 0) { + /* emulation prevention */ + *dst++ = 3; + } + zero_run = s->rpu_buf[i] == 0; + } + *dst++ = s->rpu_buf[i]; + } + *out_size = dst - *out_rpu; + return 0; + + default: + /* Should be unreachable */ + av_assert0(0); + return AVERROR_BUG; + } +} From patchwork Fri Apr 12 11:35:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 48019 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:670b:b0:1a9:af23:56c1 with SMTP id wh11csp202798pzb; Fri, 12 Apr 2024 04:37:11 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCXD48RARggeKoCplV9U7mzLdy/8w79BPtwo+YY+sNxb7NQ/jvKswUHLaVG64dgko1zgsRNatx3P41GsG9iKr9D6taUdEnyvL6aRDw== X-Google-Smtp-Source: AGHT+IGVg4YBPwASRH9i+d2hWfOpXo3WunTJGqyrXw+QCMuD+IL2T/jaFdXkI/I5cdC/nFHuy6hG X-Received: by 2002:a17:906:6a09:b0:a52:42b:4d59 with SMTP id qw9-20020a1709066a0900b00a52042b4d59mr2418877ejc.26.1712921831649; Fri, 12 Apr 2024 04:37:11 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1712921831; cv=none; d=google.com; s=arc-20160816; b=DYUhE85walW3kTCv0RdeBK+1g/TupZOANVxPPER+lXRmXEq/kcSh1XBRabom0Mo+tD c2n/OzzmxmyRBvblbcoAPHoH5LIcqQ+LbUGx4gX1eNSfnZy+zQbbQoUW0aGveOqt5z3k WqOp+E74zDLvQyKWStFYaViE/o6OqAYRPwkx5lWg55wGaVadYP675fvES+ImdTY24+u4 1GMFuHMGLzn0w5X4eYIgm6CrL4Rj85xyiUINOUx778tdVEkxt7vLDlOIoPGzJfnocXTG Cm3QdI25kEytByphzbesnObS+5xX26pGysY9Lq0xKOpGyuaoo7XCilLzVIUf421fUF5B QowA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=JeJRRBqbeSjtqX46u+x1Mb4T9DvhI75j1WG4lGPR+sc=; fh=xmAeKtysnShNOmkhiJmYkS30uw4Fu2hvBJ7qlIwukxQ=; b=Nw3HEs7uVRxqclhohQ2nQ/e2/3Hb6tTdL30hwKW8MRXN7H6iGKlQSkoZ6ICR8hGudh 2u1aUO5JLnLLheMN3ztwGDNBbH6qcnxXN6dTrhfZk3gIstP0AVLSgnzQQEh/wXaVaVca AwZyDhiaZKBf9bPR9LREJLzJ8Nyv20LmW1mz8boxjP4/kTTNV7xhLe+mZUZctrEDYBIn 5tv/NiRWpD4ciWvhCeELMYtbEx4Wk3EgQpVmnPjhiwpKBzF4/vgWBv368M6jRKp8muzH gZ9VkIzIfLmLubfwN7JyOe5VsL61Ynf4U8D5nsmU5CFwjqhKrHKvqm5tGz79G0KiWR0T z0QQ==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b="dH5W/Nmf"; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id dk22-20020a170906f0d600b00a522e4f53edsi901791ejb.249.2024.04.12.04.37.11; Fri, 12 Apr 2024 04:37:11 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b="dH5W/Nmf"; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 4728468CD7D; Fri, 12 Apr 2024 14:36:34 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id CC71768D198 for ; Fri, 12 Apr 2024 14:36:28 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1712921785; bh=fdzzSnMNWSyP3hpqFbY7N9uiC16qCPuVLrtKJtiesX0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dH5W/NmfkLU1dh7OQ1V3nQjIqywUKPc3b+CcN1KqT/Q/aYOAJePDve7RkqwSEvFZI JBHBBy/JreUrZQDGcGKHD0WAnuzIXTukgJoAyGWklIfD2qHZ6E4kIKc3fkxc3hlFMr 1/Mxpj8068Gtv4/tMpuoN2/aBbFuayp5mzbIQxIg= Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id 285D84367B; Fri, 12 Apr 2024 13:36:25 +0200 (CEST) From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Fri, 12 Apr 2024 13:35:24 +0200 Message-ID: <20240412113620.84013-11-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240412113620.84013-1-ffmpeg@haasn.xyz> References: <20240412113620.84013-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 10/13] avformat/movenc: warn if dovi cfg ignored X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: 6b7zEGNWKami From: Niklas Haas Since this is guarded behind strict unofficial, we should warn if the user feeds a dolby vision stream to this muxer, as it will otherwise result in a broken file. --- libavformat/movenc.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 6ede5119f0..1a0502bbb1 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -2526,16 +2526,21 @@ static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex const AVPacketSideData *spherical_mapping = av_packet_side_data_get(track->st->codecpar->coded_side_data, track->st->codecpar->nb_coded_side_data, AV_PKT_DATA_SPHERICAL); - const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data, - track->st->codecpar->nb_coded_side_data, - AV_PKT_DATA_DOVI_CONF); - if (stereo_3d) mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data); if (spherical_mapping) mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data); - if (dovi) + } + + if (track->mode == MODE_MP4) { + const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data, + track->st->codecpar->nb_coded_side_data, + AV_PKT_DATA_DOVI_CONF); + if (dovi && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) { mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data); + } else if (dovi) { + av_log(mov->fc, AV_LOG_WARNING, "Not writing 'dvcC'/'dvvC' box. Requires -strict unofficial.\n"); + } } if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) { From patchwork Fri Apr 12 11:35:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 48023 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:670b:b0:1a9:af23:56c1 with SMTP id wh11csp203137pzb; Fri, 12 Apr 2024 04:37:54 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCWqtaEJSAVM4MPcX28QrhPQ98Ag1WuifLVEjm9HIrDwhexc5EGjXUAm7lnoDe7dXj1aAyqzGFal4XtBbeE6evYUIh0upD7yDY/93w== X-Google-Smtp-Source: AGHT+IFtwrrnXB9j+lANJZeYyJntZJ1oBDZfU9mQVvEc6ZWn3gl1SOqPcel9BAfhX3c51tFGFHP8 X-Received: by 2002:a17:907:97c6:b0:a51:caf7:ccc2 with SMTP id js6-20020a17090797c600b00a51caf7ccc2mr2364409ejc.34.1712921874143; Fri, 12 Apr 2024 04:37:54 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1712921874; cv=none; d=google.com; s=arc-20160816; b=0sqDUlAR2D0X6Byc8NtvZWO3LJkj7pCkWTVprVNzlnCM8vR2RPuvAeVyOUy0N4pjf/ Nf4G64fl8j5sa5vpgrsQBHyQSEbKXMGV7PyVlTc3P1S1fbFHmlLqYKMbsahEHT2D8Rpc 6fyZiti+AvY/VllBBYybMjAqgjx6zM3lSOY0VSCG7zB8RHWf1fbYhrSCDM3sEYjDybCv 4D5LzSxNqV3sYMMRl+8m5pTk+JDAPBwSf+xvx02SN1t0ut0U2KvssMme3eMjErJyJhE7 YmSpah2ZXhaFVmZBcT0taVNoThGjiAZ7+0UougW0L3IJKwKyQz9OQEwg5KVXQKfdDoTg JlJg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=hPzj/N26xRxvc23Kjcjc7JwJ/Z+ILZzfGfAiPDGmn+c=; fh=xmAeKtysnShNOmkhiJmYkS30uw4Fu2hvBJ7qlIwukxQ=; b=C/Yk2VrUZyHqZRuSJXXc9Ofq+mJqb+eCxm9cWyORaD+OwhbwCUKR6PNsanYuk3N0KA ikS3fDC5Ffyckz4TSnt1I05JYu/r+Bv2lL3vVguWmzIMJ5Vhg4aqFydmL69+IM6PO0IF S5lrePRNdn9ct7+qUZtr5rJqzRAFfDK5E+ZAFjfEItPbgKEcfDiKKcrtRI9oreQCpvAB 9d2toquHY8hzdi+5a91kHsE3lUISiXSRt0wACIGvQ0YWxYVYnNU4X75Ffh9jXw4xgqJF bhVNkyg+TnzAh4HghOf4ipvT6QH0vRrl8/TKs3R/D7zAE2NtUCntbJpyugOkYz9yAFnI D36g==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=WOCJNt8O; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id he43-20020a1709073dab00b00a52322da81esi656745ejc.13.2024.04.12.04.37.53; Fri, 12 Apr 2024 04:37:54 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=WOCJNt8O; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 21C4668D164; Fri, 12 Apr 2024 14:36:39 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 26C2668D258 for ; Fri, 12 Apr 2024 14:36:29 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1712921785; bh=EBHqSAg/ZkIrux7BWrquvVSxBZLMYoyjgIo5oieD1QU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WOCJNt8OeLYZcDpLsHzKXA+RrqPE8yW401mcMgb6djp5GAWreLZ6kAjWj2MsL3j4/ YuJiv4mrRu6M+EzEF9hcc84jycpGags7Dd+R4grSk8NprJVXYJ6aWfd0nBdAU68TlT aljcVwfOkOP5+266XmelyjRQCWIQQJHjqXJyG+a0= Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id 5DBC343682; Fri, 12 Apr 2024 13:36:25 +0200 (CEST) From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Fri, 12 Apr 2024 13:35:25 +0200 Message-ID: <20240412113620.84013-12-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240412113620.84013-1-ffmpeg@haasn.xyz> References: <20240412113620.84013-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 11/13] avcodec/libaomenc: implement dolby vision coding X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: cM4n/u717G0N From: Niklas Haas --- configure | 2 +- libavcodec/libaomenc.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/configure b/configure index d25d0f6907..bf63c831af 100755 --- a/configure +++ b/configure @@ -3485,7 +3485,7 @@ prores_videotoolbox_encoder_deps="pthreads" prores_videotoolbox_encoder_select="videotoolbox_encoder" libaom_av1_decoder_deps="libaom" libaom_av1_encoder_deps="libaom" -libaom_av1_encoder_select="extract_extradata_bsf" +libaom_av1_encoder_select="extract_extradata_bsf dovi_rpuenc" libaribb24_decoder_deps="libaribb24" libaribcaption_decoder_deps="libaribcaption" libcelt_decoder_deps="libcelt" diff --git a/libavcodec/libaomenc.c b/libavcodec/libaomenc.c index 4a71bba9c9..b43a902a38 100644 --- a/libavcodec/libaomenc.c +++ b/libavcodec/libaomenc.c @@ -43,6 +43,7 @@ #include "avcodec.h" #include "bsf.h" #include "codec_internal.h" +#include "dovi_rpu.h" #include "encode.h" #include "internal.h" #include "libaom.h" @@ -70,6 +71,7 @@ struct FrameListData { typedef struct AOMEncoderContext { AVClass *class; AVBSFContext *bsf; + DOVIContext dovi; struct aom_codec_ctx encoder; struct aom_image rawimg; struct aom_fixed_buf twopass_stats; @@ -421,6 +423,7 @@ static av_cold int aom_free(AVCodecContext *avctx) av_freep(&avctx->stats_out); free_frame_list(ctx->coded_frame_list); av_bsf_free(&ctx->bsf); + ff_dovi_ctx_unref(&ctx->dovi); return 0; } @@ -989,6 +992,10 @@ static av_cold int aom_init(AVCodecContext *avctx, if (!cpb_props) return AVERROR(ENOMEM); + ctx->dovi.logctx = avctx; + if ((res = ff_dovi_configure(&ctx->dovi, avctx)) < 0) + return res; + if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { const AVBitStreamFilter *filter = av_bsf_get_by_name("extract_extradata"); int ret; @@ -1242,6 +1249,7 @@ static int aom_encode(AVCodecContext *avctx, AVPacket *pkt, unsigned long duration = 0; int res, coded_size; aom_enc_frame_flags_t flags = 0; + AVFrameSideData *sd; if (frame) { rawimg = &ctx->rawimg; @@ -1279,6 +1287,24 @@ FF_ENABLE_DEPRECATION_WARNINGS break; } + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DOVI_METADATA); + if (ctx->dovi.cfg.dv_profile && sd) { + const AVDOVIMetadata *metadata = (const AVDOVIMetadata *)sd->data; + uint8_t *t35; + int size; + if ((res = ff_dovi_rpu_generate(&ctx->dovi, metadata, &t35, &size)) < 0) + return res; + res = aom_img_add_metadata(rawimg, OBU_METADATA_TYPE_ITUT_T35, + t35, size, AOM_MIF_ANY_FRAME); + av_free(t35); + if (res != AOM_CODEC_OK) + return AVERROR(ENOMEM); + } else if (ctx->dovi.cfg.dv_profile) { + av_log(avctx, AV_LOG_ERROR, "Dolby Vision enabled, but received frame " + "without AV_FRAME_DATA_DOVI_METADATA\n"); + return AVERROR_INVALIDDATA; + } + if (frame->pict_type == AV_PICTURE_TYPE_I) flags |= AOM_EFLAG_FORCE_KF; } @@ -1459,6 +1485,8 @@ static const AVOption options[] = { { "ssim", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AOM_TUNE_SSIM}, 0, 0, VE, .unit = "tune"}, FF_AV1_PROFILE_OPTS { "still-picture", "Encode in single frame mode (typically used for still AVIF images).", OFFSET(still_picture), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, VE }, + { "dolbyvision", "Enable Dolby Vision RPU coding", OFFSET(dovi.enable), AV_OPT_TYPE_BOOL, {.i64 = FF_DOVI_AUTOMATIC }, -1, 1, VE, .unit = "dovi" }, + { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DOVI_AUTOMATIC}, .flags = VE, .unit = "dovi" }, { "enable-rect-partitions", "Enable rectangular partitions", OFFSET(enable_rect_partitions), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, { "enable-1to4-partitions", "Enable 1:4/4:1 partitions", OFFSET(enable_1to4_partitions), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, { "enable-ab-partitions", "Enable ab shape partitions", OFFSET(enable_ab_partitions), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, From patchwork Fri Apr 12 11:35:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 48020 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:670b:b0:1a9:af23:56c1 with SMTP id wh11csp202877pzb; Fri, 12 Apr 2024 04:37:20 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCVCx5EmyYk43YjkCGeUY7n00wtjld9lTnzG0bJ8Kh5fsya9GH192uPl4XLuhAuHUuavRTR4AIFTt/TOmJasvmhbD3QKB74lCpduyQ== X-Google-Smtp-Source: AGHT+IHn1QULgS9Oj0V4SPyWVKqSww/8iRIUGXDaexFVPWKxMGVZ1MVeqL9zwJZoMFnZr1VCBh/g X-Received: by 2002:a17:906:1c99:b0:a52:2c4f:7957 with SMTP id g25-20020a1709061c9900b00a522c4f7957mr1902334ejh.66.1712921839830; Fri, 12 Apr 2024 04:37:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1712921839; cv=none; d=google.com; s=arc-20160816; b=GQC0aDrfyvVeqVZ6EsJIe+LAaJr6BEuu1+LB78QJbcUqigWqYbmrfWAqv7UqqyfGPe 9HwXVKaeIPVDkNmlnAn0lm/ZVVAbr2+YHBOrpyQj+dRD/02d9BSgVBRgLV7WojvuPoLn +1rGocdkkrDSkx6gXcbp96Ph23PHmUs6c+NqoA171xQD+By7CcVcsy7P86y/KSe5uFFr YuODDkIa8g3hzt/mbO6Oou/uOHiej4Zr7L+EY7NrDISu1QWbGbu9WmBf/tNW/qZqaOX7 b0RCe9+u2T4qbvj22fnf4Huu/v7n3GcSyv9zNwmjzFMXABdZrduN4YsCdRlO52sDY+yY 5jOA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=0A/HZQMJDSAAHACeypQ2oFnG5Wts+3O5dMRG6EAybQU=; fh=xmAeKtysnShNOmkhiJmYkS30uw4Fu2hvBJ7qlIwukxQ=; b=Z5VumTH5RJLSqIFlw+d0YSw6YhNp6uQYdQG2aIx6oBTygpGA0SJFSdz03O9z9G1Stx 8d3XQDspD2tU7ivyKX3em3OzUUe+ohnkNvb4gbkOjZ+w0fi4bKk2ZSjiM6z6Q2D8AORV IjWhQsg1MR4RkedFFpkj2Tj6eTe6KNIPh7CiicT6J2loCR72n4B1Uu023f0EkKV20OAX 3OSB68XxWrMa/HmHyBh+7lfb/i2fvm99pL8ONYFfY5bHdxa/R83+7OFWQtI4n4FVa/4w eotC6rSst79YGWYIcQrMpDgNWs2eFSE6NY0R9JFuNBYPDuO9Ciq3vek3oszUyqWRXHSX UU4Q==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=i4uHXC+b; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id gf1-20020a170906e20100b00a43db2d8b90si1655331ejb.325.2024.04.12.04.37.19; Fri, 12 Apr 2024 04:37:19 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=i4uHXC+b; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 402D668D229; Fri, 12 Apr 2024 14:36:35 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id E58E368D229 for ; Fri, 12 Apr 2024 14:36:28 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1712921785; bh=w3pv8gWU6av4+5l8YNlchcuNsRw7IJ+K+h87z2ojNHQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=i4uHXC+bnefgUpPVulcx/SEnPqXY6q68c89kJWpVnz8tsEl4K+aEF9qzYaX++4b3C j5pNsjstAvZyfq192L9HkwuJ36zdIGpyjSnLjhMHePZbxTiXJ/YvjeKf2aBS4CWfnB qM71HRLLw0oqcV/3k5ulNMdJZf546JP5dsZSfm30= Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id 9108743756; Fri, 12 Apr 2024 13:36:25 +0200 (CEST) From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Fri, 12 Apr 2024 13:35:26 +0200 Message-ID: <20240412113620.84013-13-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240412113620.84013-1-ffmpeg@haasn.xyz> References: <20240412113620.84013-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 12/13] avcodec/libx265: implement dolby vision coding X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: 73VmBgvkb4AN From: Niklas Haas libx265 supports these natively, we just need to attach the generated NALs to the x265picture, as well as setting the appropriate DV profile. --- configure | 2 +- libavcodec/libx265.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/configure b/configure index bf63c831af..cce37bb32e 100755 --- a/configure +++ b/configure @@ -3553,7 +3553,7 @@ libx264_encoder_select="atsc_a53 golomb" libx264rgb_encoder_deps="libx264" libx264rgb_encoder_select="libx264_encoder" libx265_encoder_deps="libx265" -libx265_encoder_select="atsc_a53" +libx265_encoder_select="atsc_a53 dovi_rpueenc" libxavs_encoder_deps="libxavs" libxavs2_encoder_deps="libxavs2" libxevd_decoder_deps="libxevd" diff --git a/libavcodec/libx265.c b/libavcodec/libx265.c index 0645cd2045..c4ceffff5d 100644 --- a/libavcodec/libx265.c +++ b/libavcodec/libx265.c @@ -36,6 +36,7 @@ #include "libavutil/pixdesc.h" #include "avcodec.h" #include "codec_internal.h" +#include "dovi_rpu.h" #include "encode.h" #include "packet_internal.h" #include "atsc_a53.h" @@ -78,6 +79,8 @@ typedef struct libx265Context { * encounter a frame with ROI side data. */ int roi_warned; + + DOVIContext dovi; } libx265Context; static int is_keyframe(NalUnitType naltype) @@ -143,6 +146,8 @@ static av_cold int libx265_encode_close(AVCodecContext *avctx) if (ctx->encoder) ctx->api->encoder_close(ctx->encoder); + ff_dovi_ctx_unref(&ctx->dovi); + return 0; } @@ -526,6 +531,14 @@ FF_ENABLE_DEPRECATION_WARNINGS } } +#if X265_BUILD >= 167 + ctx->dovi.logctx = avctx; + if ((ret = ff_dovi_configure(&ctx->dovi, avctx)) < 0) + return ret; + ctx->params->dolbyProfile = ctx->dovi.cfg.dv_profile * 10 + + ctx->dovi.cfg.dv_bl_signal_compatibility_id; +#endif + ctx->encoder = ctx->api->encoder_open(ctx->params); if (!ctx->encoder) { av_log(avctx, AV_LOG_ERROR, "Cannot open libx265 encoder.\n"); @@ -629,6 +642,10 @@ static void free_picture(libx265Context *ctx, x265_picture *pic) for (int i = 0; i < sei->numPayloads; i++) av_free(sei->payloads[i].payload); +#if X265_BUILD >= 167 + av_free(pic->rpu.payload); +#endif + if (pic->userData) { int idx = (int)(intptr_t)pic->userData - 1; rd_release(ctx, idx); @@ -660,6 +677,7 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, sei->numPayloads = 0; if (pic) { + AVFrameSideData *sd; ReorderedData *rd; int rd_idx; @@ -760,6 +778,24 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, sei->numPayloads++; } } + +#if X265_BUILD >= 167 + sd = av_frame_get_side_data(pic, AV_FRAME_DATA_DOVI_METADATA); + if (ctx->dovi.cfg.dv_profile && sd) { + const AVDOVIMetadata *metadata = (const AVDOVIMetadata *)sd->data; + ret = ff_dovi_rpu_generate(&ctx->dovi, metadata, &x265pic.rpu.payload, + &x265pic.rpu.payloadSize); + if (ret < 0) { + free_picture(ctx, &x265pic); + return ret; + } + } else if (ctx->dovi.cfg.dv_profile) { + av_log(avctx, AV_LOG_ERROR, "Dolby Vision enabled, but received frame " + "without AV_FRAME_DATA_DOVI_METADATA"); + free_picture(ctx, &x265pic); + return AVERROR_INVALIDDATA; + } +#endif } ret = ctx->api->encoder_encode(ctx->encoder, &nal, &nnal, @@ -914,6 +950,10 @@ static const AVOption options[] = { { "udu_sei", "Use user data unregistered SEI if available", OFFSET(udu_sei), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "a53cc", "Use A53 Closed Captions (if available)", OFFSET(a53_cc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, { "x265-params", "set the x265 configuration using a :-separated list of key=value parameters", OFFSET(x265_opts), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE }, +#if X265_BUILD >= 167 + { "dolbyvision", "Enable Dolby Vision RPU coding", OFFSET(dovi.enable), AV_OPT_TYPE_BOOL, {.i64 = FF_DOVI_AUTOMATIC }, -1, 1, VE, .unit = "dovi" }, + { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DOVI_AUTOMATIC}, .flags = VE, .unit = "dovi" }, +#endif { NULL } }; From patchwork Fri Apr 12 11:35:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 48022 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:670b:b0:1a9:af23:56c1 with SMTP id wh11csp202993pzb; Fri, 12 Apr 2024 04:37:37 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCXZcEyebx10yYs+7Qkyl3ullOI47wOU1NCrRvkhv2kw92yvsWEP/Tw+TfSe296JWlbN5zW3+1MmAqhpf2pqFJTNSDnCewqzH+gSYw== X-Google-Smtp-Source: AGHT+IFjCkrkkNSZSkIekgno7vKBT8pN6TouSjct4G7PDZILKSkNTE76i1F8Sk00ax7PLPLgWBlX X-Received: by 2002:a17:907:38e:b0:a51:c975:f02a with SMTP id ss14-20020a170907038e00b00a51c975f02amr1428951ejb.65.1712921856850; Fri, 12 Apr 2024 04:37:36 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1712921856; cv=none; d=google.com; s=arc-20160816; b=jxCqKDn99zLL5mNgv1/JoYyR/0UEFm5vJuuTarsLqydgLBvil36AQ7FjkbGazTU7jx WZsPUg4c6XHfOsG1moamaPgwb2N6TO4hYnHBXXNoqgc0lRsNE+cTl1rY9o8LGX5ngpEB GOS+fOHMH9uTTnDX2VN692FzSjnJNzc48x7/emKqviMk0p5pLF62IPp5Jaf1kWFFgCKI WZfcsr0mWjma7XnyFNNkfW2gnYOdJcTHNM9olkU2pxOC2tPMQsLCU61lIxN4tp3L2kFh g3i5qrnNvSAFF5h+VfW6ITO3RKSLOxEY6PL7ogPXfRZxR7WNt4AMCBzWCfFQInMeIHuP aQ5g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=iZmVlDBMDDbBvSX31M4KXprsJqxGU+Lam9Dmo0nDrCA=; fh=xmAeKtysnShNOmkhiJmYkS30uw4Fu2hvBJ7qlIwukxQ=; b=eKqCE1iVyXo2JuU1qF/zFmbicddHIgoo4KYCMN2/c3ifrGzNrUFsiqoipt1vDesYa0 TbMGvpa2vhKYPsqOD0wNOYvcifCLlxCsQ+UK84uVT2CTbnWqa5R8ekZS49qD9VNckskm 9DtY1+62+9ljeRLqQ6eeCSQNmvVYwA0fOc0j1u8fMf+fQaF5ARi1s6Bvu69UK8NHrmdG tcuIc7WdFUEVIK1YXIeIXoX/jfWe9hUWMBITlSFNGLx+rXJA179Nt7BopaXm6SwtJ26a 1AhKd2unIIjWmJ1Sz08bsMvqkBycrTJ+o94Y/uAAn520UtFQKwqWu7CNZEaOGYhfBClG A8BA==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b="pz/MXJBf"; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id f12-20020a170906048c00b00a520ce94de8si1616722eja.1009.2024.04.12.04.37.36; Fri, 12 Apr 2024 04:37:36 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b="pz/MXJBf"; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 2202868D287; Fri, 12 Apr 2024 14:36:37 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id E629868D234 for ; Fri, 12 Apr 2024 14:36:28 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1712921785; bh=CpL0WlAqi0neNTEj7lJ8GJ9gQSfydRjXBq2vmg6NM60=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pz/MXJBfKJD85LrmeVCsfWLon4HS08n2U/OJdfdUhFyK2brlXR1zbMVHBneUZ4vQt Ws0B3mhdyDS+IvpaY1AAZJQH02jr/BFUM1X47Kmi6Le93c72qPDl6WA2cJrvwLzDH+ Ntbnu8ck0SK6nONEK9sY9SlcaLUUkOsOCqbTsdGI= Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id C87AA43961; Fri, 12 Apr 2024 13:36:25 +0200 (CEST) From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Fri, 12 Apr 2024 13:35:27 +0200 Message-ID: <20240412113620.84013-14-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240412113620.84013-1-ffmpeg@haasn.xyz> References: <20240412113620.84013-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 13/13] avcodec/libsvtav1: implement dolby vision coding X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: nuqeJ0svlWLx From: Niklas Haas --- configure | 1 + libavcodec/libsvtav1.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/configure b/configure index cce37bb32e..6fbd0e44ff 100755 --- a/configure +++ b/configure @@ -3534,6 +3534,7 @@ libspeex_decoder_deps="libspeex" libspeex_encoder_deps="libspeex" libspeex_encoder_select="audio_frame_queue" libsvtav1_encoder_deps="libsvtav1" +libsvtav1_encoder_select="dovi_rpueenc" libtheora_encoder_deps="libtheora" libtwolame_encoder_deps="libtwolame" libuavs3d_decoder_deps="libuavs3d" diff --git a/libavcodec/libsvtav1.c b/libavcodec/libsvtav1.c index 6ff893cf10..9bc165f0cf 100644 --- a/libavcodec/libsvtav1.c +++ b/libavcodec/libsvtav1.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "libavutil/common.h" #include "libavutil/frame.h" @@ -35,6 +36,7 @@ #include "libavutil/avassert.h" #include "codec_internal.h" +#include "dovi_rpu.h" #include "encode.h" #include "packet_internal.h" #include "avcodec.h" @@ -62,6 +64,8 @@ typedef struct SvtContext { EOS_STATUS eos_flag; + DOVIContext dovi; + // User options. AVDictionary *svtav1_opts; int enc_mode; @@ -418,6 +422,7 @@ static int read_in_data(EbSvtAv1EncConfiguration *param, const AVFrame *frame, in_data->cr_stride = AV_CEIL_RSHIFT(frame->linesize[2], bytes_shift); header_ptr->n_filled_len = frame_size; + svt_metadata_array_free(&header_ptr->metadata); return 0; } @@ -451,6 +456,11 @@ static av_cold int eb_enc_init(AVCodecContext *avctx) return svt_print_error(avctx, svt_ret, "Error initializing encoder"); } + svt_enc->dovi.logctx = avctx; + ret = ff_dovi_configure(&svt_enc->dovi, avctx); + if (ret < 0) + return ret; + if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { EbBufferHeaderType *headerPtr = NULL; @@ -486,6 +496,7 @@ static int eb_send_frame(AVCodecContext *avctx, const AVFrame *frame) { SvtContext *svt_enc = avctx->priv_data; EbBufferHeaderType *headerPtr = svt_enc->in_buf; + AVFrameSideData *sd; EbErrorType svt_ret; int ret; @@ -525,6 +536,24 @@ static int eb_send_frame(AVCodecContext *avctx, const AVFrame *frame) if (avctx->gop_size == 1) headerPtr->pic_type = EB_AV1_KEY_PICTURE; + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DOVI_METADATA); + if (svt_enc->dovi.cfg.dv_profile && sd) { + const AVDOVIMetadata *metadata = (const AVDOVIMetadata *)sd->data; + uint8_t *t35; + int size; + if ((ret = ff_dovi_rpu_generate(&svt_enc->dovi, metadata, &t35, &size)) < 0) + return ret; + ret = svt_add_metadata(headerPtr, EB_AV1_METADATA_TYPE_ITUT_T35, t35, size); + av_free(t35); + if (ret < 0) + return AVERROR(ENOMEM); + } else if (svt_enc->dovi.cfg.dv_profile) { + av_log(avctx, AV_LOG_ERROR, "Dolby Vision enabled, but received frame " + "without AV_FRAME_DATA_DOVI_METADATA\n"); + return AVERROR_INVALIDDATA; + } + + svt_ret = svt_av1_enc_send_picture(svt_enc->svt_handle, headerPtr); if (svt_ret != EB_ErrorNone) return svt_print_error(avctx, svt_ret, "Error sending a frame to encoder"); @@ -649,11 +678,13 @@ static av_cold int eb_enc_close(AVCodecContext *avctx) } if (svt_enc->in_buf) { av_free(svt_enc->in_buf->p_buffer); + svt_metadata_array_free(&svt_enc->in_buf->metadata); av_freep(&svt_enc->in_buf); } av_buffer_pool_uninit(&svt_enc->pool); av_frame_free(&svt_enc->frame); + ff_dovi_ctx_unref(&svt_enc->dovi); return 0; } @@ -700,6 +731,9 @@ static const AVOption options[] = { AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 63, VE }, { "svtav1-params", "Set the SVT-AV1 configuration using a :-separated list of key=value parameters", OFFSET(svtav1_opts), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE }, + { "dolbyvision", "Enable Dolby Vision RPU coding", OFFSET(dovi.enable), AV_OPT_TYPE_BOOL, {.i64 = FF_DOVI_AUTOMATIC }, -1, 1, VE, .unit = "dovi" }, + { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DOVI_AUTOMATIC}, .flags = VE, .unit = "dovi" }, + {NULL}, };