From patchwork Fri Feb 15 00:12:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Carl Eugen Hoyos X-Patchwork-Id: 12077 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id D043E4484F9 for ; Fri, 15 Feb 2019 02:13:01 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id B3E5F68A5A4; Fri, 15 Feb 2019 02:13:01 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-it1-f174.google.com (mail-it1-f174.google.com [209.85.166.174]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id AA7ED68A500 for ; Fri, 15 Feb 2019 02:12:54 +0200 (EET) Received: by mail-it1-f174.google.com with SMTP id v72so19280654itc.0 for ; Thu, 14 Feb 2019 16:12:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:in-reply-to:references:from:date:message-id:subject:to; bh=lcL54iadDDRJxVS3rygSuAcCzmQYcy4hDDsGq/47xKc=; b=qJ+LIwBfFJRUJGHBuVWd09pLAyMP5fBWhlz+aiN7xcrNTFlS8b/0SwkkOQSr1Lr6Zf pk7MjfWucXmbT33q3q34gsK2L/72Np6A554JOck3oAUo315fPR7Quw4YSiq60EuEgaK2 0R9aAF8A5VuUTVJMYQ+JDAR1wzeg1kWp85+gcQPGCxx3V65d6ZuMEmuX4jA52yDcrbdi bDoR3s8ves7QmYuFip/OaHIwyF/OV3RrjiPQwQ8xPNY95hfGyumLR8rlJaBL9cGWDZxw Pjq5x4MQuuLy878kQb7AObsq4rv5O/HZFIPjMHC+cAxL8zDGNT4Ka8sW/8wOVcnwkYeT B4OQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to; bh=lcL54iadDDRJxVS3rygSuAcCzmQYcy4hDDsGq/47xKc=; b=BnzOPwX89lyhkwAe9lNT4LHcYfpYf5/0fDgOLvty3m3iMmeT0FSJ4YqoeQOx8Y+Y88 GugsR6kXf5IymES3f/tqoAEtZKNHHovynSknGbYLgraCwB5rK2rk3s/pSVKZOdjwSE2J my/Kiu74kz0W5F9wHxqQ9BtJLMphG3E/8qv8jh3WkWDbd8BB+wAmG000wnb1xT0EuXE2 dprWRnndUBeOeVPQ6zxxyyO5lVNoLSL2q2KSVMa503y75bkAlDU9v5piWAfE/CK1pTC/ nai7GEq5HP0SlRLVF1UCd1MB7/Y/31m1YckQmu+5ZxdAPuHi/bGZfiFFYmRzaHmb9I+v LXzA== X-Gm-Message-State: AHQUAubKJ817gRZw7o0VTgmacNFx4KCWC+AzQUeKTnMeUBGWv1WaYYIF D9gXrI2EU1GPh6+fsEpamZz1PcEX1eKOdvRoXsJseg== X-Google-Smtp-Source: AHgI3IYW0GhurTcU9V98ydpyozqhpZtIf5Dpn/HbcuCUov04SRdd2L76qN9VOGD+L/rsf1hSDWUzdjGIhW689FinvyE= X-Received: by 2002:a5d:9455:: with SMTP id x21mr4410375ior.250.1550189573169; Thu, 14 Feb 2019 16:12:53 -0800 (PST) MIME-Version: 1.0 Received: by 2002:a02:940e:0:0:0:0:0 with HTTP; Thu, 14 Feb 2019 16:12:52 -0800 (PST) In-Reply-To: References: From: Carl Eugen Hoyos Date: Fri, 15 Feb 2019 01:12:52 +0100 Message-ID: To: FFmpeg development discussions and patches Subject: Re: [FFmpeg-devel] [PATCH]lavf/spdifenc: Use a more flexible buffer model for TrueHD/MAT X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" 2019-02-15 0:23 GMT+01:00, Hendrik Leppkes : > On Thu, Feb 14, 2019 at 8:11 PM Carl Eugen Hoyos wrote: >> >> Hi! >> >> I created attached patch with a lot of help from Hendrik, fixes ticket >> #7731. >> > > Som general comments, since I can't replay inline in this mail client: > > - The pseudo-timestamps are unsigned 16-bit, personally I would make > all types that reference them uint16_t and rely on unsigned overflow > behavior, which is fully valid and specified - no need to handle > negatives manually, etc. I had already changed this (only for the actual timestamp difference), thank you! > - The distance between frames can be incredibly large in some streams, > I've seen it be larger then one whole MAT frame, and the output works > reliably (MAT start/middle/end codes need to be placed within the > padding space, of course). That is not supported yet, could you provide such a problematic sample? (Including the output if possible) New patch attached, Carl Eugen From 25fa80c8dfa6dd9ef4271abac94620458044a507 Mon Sep 17 00:00:00 2001 From: Carl Eugen Hoyos Date: Fri, 15 Feb 2019 01:11:52 +0100 Subject: [PATCH] lavf/spdifenc: Use a more flexible buffer model for TrueHD/MAT. Allows muxing large frames. Fixes ticket #7731. --- libavformat/spdifenc.c | 147 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 113 insertions(+), 34 deletions(-) diff --git a/libavformat/spdifenc.c b/libavformat/spdifenc.c index 9514ff8..71708cf 100644 --- a/libavformat/spdifenc.c +++ b/libavformat/spdifenc.c @@ -76,6 +76,14 @@ typedef struct IEC61937Context { int dtshd_skip; ///< counter used for skipping DTS-HD frames + int last_ts; ///< timestamp of the last TrueHD frame to calculate spacing + int remaining; ///< bytes to the next mat code + uint8_t *buf; ///< pointer into the mat frame + uint8_t *last_frame; ///< buffer for remaining bytes of incompletely written frame + int last_frame_size; + int space; ///< current delta of expected and actual frame spacing + int ratebits; ///< TrueHD ratebits, needed to calculate frame spacing + /* AVOptions: */ int dtshd_rate; int dtshd_fallback; @@ -382,56 +390,118 @@ static int spdif_header_aac(AVFormatContext *s, AVPacket *pkt) /* - * It seems Dolby TrueHD frames have to be encapsulated in MAT frames before + * Dolby TrueHD frames have to be encapsulated in MAT frames before * they can be encapsulated in IEC 61937. - * Here we encapsulate 24 TrueHD frames in a single MAT frame, padding them - * to achieve constant rate. - * The actual format of a MAT frame is unknown, but the below seems to work. - * However, it seems it is not actually necessary for the 24 TrueHD frames to - * be in an exact alignment with the MAT frame. + * A specific alignment is required to fulfill buffering requirements + * in some cases, while the average frame distance has to be constant + * actual frame distances vary depending on timestamps and frame sizes. */ #define MAT_FRAME_SIZE 61424 #define TRUEHD_FRAME_OFFSET 2560 -#define MAT_MIDDLE_CODE_OFFSET -4 +#define MAT_HALF_FRAME 30688 +static const char mat_start_code[20] = { 0x07, 0x9E, 0x00, 0x03, 0x84, 0x01, 0x01, 0x01, 0x80, 0x00, 0x56, 0xA5, 0x3B, 0xF4, 0x81 , 0x83, 0x49, 0x80, 0x77, 0xE0 }; +static const char mat_middle_code[12] = { 0xC3, 0xC1, 0x42, 0x49, 0x3B, 0xFA, 0x82, 0x83, 0x49, 0x80, 0x77, 0xE0 }; +static const char mat_end_code[16] = { 0xC3, 0xC2, 0xC0, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x11 }; static int spdif_header_truehd(AVFormatContext *s, AVPacket *pkt) { IEC61937Context *ctx = s->priv_data; - int mat_code_length = 0; - static const char mat_end_code[16] = { 0xC3, 0xC2, 0xC0, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x11 }; - - if (!ctx->hd_buf_count) { - static const char mat_start_code[20] = { 0x07, 0x9E, 0x00, 0x03, 0x84, 0x01, 0x01, 0x01, 0x80, 0x00, 0x56, 0xA5, 0x3B, 0xF4, 0x81, 0x83, 0x49, 0x80, 0x77, 0xE0 }; - mat_code_length = sizeof(mat_start_code) + BURST_HEADER_SIZE; - memcpy(ctx->hd_buf, mat_start_code, sizeof(mat_start_code)); - - } else if (ctx->hd_buf_count == 12) { - static const char mat_middle_code[12] = { 0xC3, 0xC1, 0x42, 0x49, 0x3B, 0xFA, 0x82, 0x83, 0x49, 0x80, 0x77, 0xE0 }; - mat_code_length = sizeof(mat_middle_code) + MAT_MIDDLE_CODE_OFFSET; - memcpy(&ctx->hd_buf[12 * TRUEHD_FRAME_OFFSET - BURST_HEADER_SIZE + MAT_MIDDLE_CODE_OFFSET], - mat_middle_code, sizeof(mat_middle_code)); - } - if (pkt->size > TRUEHD_FRAME_OFFSET - mat_code_length) { - /* if such frames exist, we'd need some more complex logic to - * distribute the TrueHD frames in the MAT frame */ - avpriv_request_sample(s, "Too large TrueHD frame of %d bytes", - pkt->size); - return AVERROR_PATCHWELCOME; + if (pkt->size < 8 || pkt->size >= MAT_HALF_FRAME / 2) { + av_log(s, AV_LOG_ERROR, "Invalid frame size: %d\n", pkt->size); + return AVERROR(EINVAL); + } + if (ctx->last_ts == -1) + if (AV_RB32(&pkt->data[4]) == 0xf8726fba) { + ctx->ratebits = pkt->data[8] >> 4; + } else { + ctx->pkt_offset = 0; + return 0; + } + if (ctx->last_ts >= 0) { + uint16_t distance = AV_RB16(&pkt->data[2]) - ctx->last_ts; + distance *= 64 >> ctx->ratebits; + if (distance > MAT_HALF_FRAME / 4) { + av_log(s, AV_LOG_ERROR, "Invalid frame distance %d, using %d\n", distance, TRUEHD_FRAME_OFFSET); + distance = TRUEHD_FRAME_OFFSET; + } + ctx->space += distance; + } + if (FFABS(ctx->space) >= MAT_HALF_FRAME / 4) { + av_log(s, AV_LOG_ERROR, "Invalid spacing: %d, resetting\n", ctx->space); + ctx->space = -pkt->size; + } + ctx->last_ts = AV_RB16(&pkt->data[2]); + if (ctx->buf == ctx->hd_buf) { + // write mat_start_code at start of output packet + memcpy(ctx->buf, mat_start_code, sizeof(mat_start_code)); + ctx->buf += sizeof(mat_start_code); + memcpy(ctx->buf, ctx->last_frame, ctx->last_frame_size); + ctx->buf += ctx->last_frame_size; + ctx->remaining = MAT_HALF_FRAME - ctx->last_frame_size; + ctx->space -= ctx->last_frame_size + sizeof(mat_start_code); + ctx->last_frame_size = 0; } - memcpy(&ctx->hd_buf[ctx->hd_buf_count * TRUEHD_FRAME_OFFSET - BURST_HEADER_SIZE + mat_code_length], - pkt->data, pkt->size); - memset(&ctx->hd_buf[ctx->hd_buf_count * TRUEHD_FRAME_OFFSET - BURST_HEADER_SIZE + mat_code_length + pkt->size], - 0, TRUEHD_FRAME_OFFSET - pkt->size - mat_code_length); + if (ctx->space > 0) { + int min = FFMIN(ctx->remaining, ctx->space); + memset(ctx->buf, 0, min); + ctx->buf += min; + ctx->remaining -= min; + ctx->space -= min; + } - if (++ctx->hd_buf_count < 24){ + if (pkt->size <= ctx->remaining) { + memcpy(ctx->buf, pkt->data, pkt->size); + ctx->remaining -= pkt->size; + ctx->space -= pkt->size; + ctx->buf += pkt->size; ctx->pkt_offset = 0; return 0; } - memcpy(&ctx->hd_buf[MAT_FRAME_SIZE - sizeof(mat_end_code)], mat_end_code, sizeof(mat_end_code)); - ctx->hd_buf_count = 0; + memcpy(ctx->buf, pkt->data, ctx->remaining); + ctx->buf += ctx->remaining; // ctx->remaining is still needed after a mat_code was written below + ctx->space -= ctx->remaining; + + if (ctx->buf == ctx->hd_buf + MAT_HALF_FRAME + sizeof(mat_start_code)) { + // write mat_middle_code always at the exact same position + memcpy(ctx->buf, mat_middle_code, sizeof(mat_middle_code)); + ctx->buf += sizeof(mat_middle_code); + ctx->space -= sizeof(mat_middle_code); + if (ctx->space > 0 && !ctx->remaining) { + memset(ctx->buf, 0, ctx->space); + memcpy(ctx->buf + ctx->space, pkt->data, pkt->size); + ctx->buf += ctx->space + pkt->size; + ctx->remaining = MAT_HALF_FRAME - ctx->space - pkt->size; + ctx->space = -pkt->size; + } else { + memcpy(ctx->buf, pkt->data + ctx->remaining, pkt->size - ctx->remaining); + ctx->buf += pkt->size - ctx->remaining; + ctx->space -= pkt->size - ctx->remaining; + ctx->remaining = MAT_HALF_FRAME - pkt->size + ctx->remaining; + } + return 0; + } + av_assert0(ctx->buf == ctx->hd_buf + MAT_FRAME_SIZE - sizeof(mat_end_code)); + // write mat_end_code exactly at the end of the mat frame + memcpy(ctx->buf, mat_end_code, sizeof(mat_end_code)); + ctx->buf = ctx->hd_buf; + ctx->space -= sizeof(mat_end_code) + 16; // preamble and padding + if (ctx->space > 0) { + int min = FFMIN(ctx->space, sizeof(mat_start_code)); + ctx->last_frame_size = pkt->size - ctx->remaining + ctx->space - min; + if (ctx->last_frame_size >= MAT_HALF_FRAME / 4) { + av_log(s, AV_LOG_ERROR, "Invalid remaining number of bytes: %d\n", ctx->last_frame_size); + return AVERROR(EINVAL); + } + memset(ctx->last_frame, 0, ctx->space - min); + memcpy(ctx->last_frame + ctx->space - min, pkt->data + ctx->remaining, ctx->last_frame_size - ctx->space + min); + } else { + ctx->last_frame_size = pkt->size - ctx->remaining; + memcpy(ctx->last_frame, pkt->data + ctx->remaining, ctx->last_frame_size); + } + ctx->remaining = 0; ctx->data_type = IEC61937_TRUEHD; ctx->pkt_offset = 61440; ctx->out_buf = ctx->hd_buf; @@ -465,9 +535,17 @@ static int spdif_write_header(AVFormatContext *s) case AV_CODEC_ID_TRUEHD: case AV_CODEC_ID_MLP: ctx->header_info = spdif_header_truehd; + ctx->space = sizeof(mat_start_code); + ctx->buf = ctx->hd_buf = av_malloc(MAT_FRAME_SIZE); if (!ctx->hd_buf) return AVERROR(ENOMEM); + ctx->last_frame = av_malloc(MAT_FRAME_SIZE); + if (!ctx->last_frame) { + av_freep(&ctx->hd_buf); + return AVERROR(ENOMEM); + } + ctx->last_ts = -1; break; default: avpriv_report_missing_feature(s, "Codec %d", @@ -482,6 +560,7 @@ static int spdif_write_trailer(AVFormatContext *s) IEC61937Context *ctx = s->priv_data; av_freep(&ctx->buffer); av_freep(&ctx->hd_buf); + av_freep(&ctx->last_frame); return 0; } -- 1.7.10.4