From patchwork Thu Feb 14 19:11:02 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: 12073 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 3ECB94482C0 for ; Thu, 14 Feb 2019 21:11:12 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 1D48F68A5A4; Thu, 14 Feb 2019 21:11:12 +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 127DA68A425 for ; Thu, 14 Feb 2019 21:11:05 +0200 (EET) Received: by mail-it1-f174.google.com with SMTP id r11so17817423itc.2 for ; Thu, 14 Feb 2019 11:11:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:from:date:message-id:subject:to; bh=B1tvR2SzWtKY3ObpZoTP2lz9btTpyMwpwHS38tAtvjQ=; b=OQiE8sIWRoL17xFScWGacrRIhFsVun0KHo9Hf3Faj3Cxda8T8cm6TCnaFzrS6aEo9T zqxuC3Ek00t4PblBpZb4QrEgmCwPynZgWMk8DCJ0IdGm8yVvx9FV2G2iUKn980x/DXrR gBbKlTgNi1EjE/kEqgasnhw735JZx7zOhjm9OAGxfxXl+n2DmOw4OIpx56cNy1gf+Gik ny3Zxp35DslCzUO7v0L2bs5aXxQNWV1eWiFRmgjhYWp/ekhN1io/erSI0UOgWkrX49p8 CUIEHTtI+SNW3oi/lw4aIZrO+mqbMSP3sThIzJzRVIAosa00cK0vH1eWzbJoeaQHOuND FwTw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=B1tvR2SzWtKY3ObpZoTP2lz9btTpyMwpwHS38tAtvjQ=; b=lQKwFAgpZj615qqHfhcriNzTSZ6+nWBjF4fX5dfrHX5VwvU1s0fPw1x9McE8TOSxpj 8dz+0TDXIe6ONClven0fyRBftJ7tBGJx+sP53tzi7q35Hws0QtkcxTszTKLiOkrupjTo E9QxG5vNUcfVnTH58dmksWr+O5IUWADwOB0gBLjNO+f4ovzjPLvw4GL+0B19eaTCjkWx 30nZWBxvJ8Z0rc2KN7sAe6nkxShCYVpQb7Qdpgcvc1tYg1O14pz7SE6FUkH21Iz93d1J HjRkUZWymIgcGYrj6gmEeU9c+J4Pf5LZSDjofeH20QrzgwQjMACYA+XpQ0MsP0CMhpcT zHTA== X-Gm-Message-State: AHQUAua3KJoIeaSeNrBB4LrqXxGUY/Bniux/h3J589eOV1dt4vG5BJA4 RutQuktk+MU5e2gk/FIHrjsJ1Igd1HNV8X5eUeUdDA== X-Google-Smtp-Source: AHgI3IYbkCDvwzX2Hk4ObmT8pTpva6b9mJmI+XiVTXBA8l4jO8bN1rqDlzsdEV9V0sTXv2AdIm8w7bfjzOMJZaqIUmk= X-Received: by 2002:a5d:9685:: with SMTP id m5mr3590279ion.55.1550171463286; Thu, 14 Feb 2019 11:11:03 -0800 (PST) MIME-Version: 1.0 Received: by 2002:a02:940e:0:0:0:0:0 with HTTP; Thu, 14 Feb 2019 11:11:02 -0800 (PST) From: Carl Eugen Hoyos Date: Thu, 14 Feb 2019 20:11:02 +0100 Message-ID: To: FFmpeg development discussions and patches Subject: [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" Hi! I created attached patch with a lot of help from Hendrik, fixes ticket #7731. Please review, Carl Eugen From ce97425171b06b353cf9ec71e9ff6c7e7ec49422 Mon Sep 17 00:00:00 2001 From: Carl Eugen Hoyos Date: Thu, 14 Feb 2019 20:07:53 +0100 Subject: [PATCH] lavf/spdifenc: Use a more flexible buffer model for TrueHD/MAT. Allows muxing large frames. Fixes ticket #7731. --- libavformat/spdifenc.c | 138 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 104 insertions(+), 34 deletions(-) diff --git a/libavformat/spdifenc.c b/libavformat/spdifenc.c index 9514ff8..59d0c27 100644 --- a/libavformat/spdifenc.c +++ b/libavformat/spdifenc.c @@ -76,6 +76,13 @@ 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 + /* AVOptions: */ int dtshd_rate; int dtshd_fallback; @@ -382,56 +389,110 @@ 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 && AV_RB16(&pkt->data[4]) != SYNCWORD1) { + ctx->pkt_offset = 0; + return 0; + } + if (ctx->last_ts >= 0) { + int distance = (AV_RB16(&pkt->data[2]) - ctx->last_ts); + if (distance < 0) + distance = 65536 + AV_RB16(&pkt->data[2]) - ctx->last_ts; + distance *= 64; //FIXME + 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; + } + 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; + } + } + + if (ctx->buf != ctx->hd_buf + MAT_FRAME_SIZE - sizeof(mat_end_code)) + return 0; + // 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; + 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 +526,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 +551,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