From patchwork Sun Apr 12 19:56:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anssi Hannula X-Patchwork-Id: 18897 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 E433044AA83 for ; Sun, 12 Apr 2020 22:57:04 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id C5B2C68B5EC; Sun, 12 Apr 2020 22:57:04 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from sinikuusama2.dnainternet.net (sinikuusama2.dnainternet.net [83.102.40.152]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 53E1968B1AE for ; Sun, 12 Apr 2020 22:56:57 +0300 (EEST) Received: from localhost (localhost [127.0.0.1]) by sinikuusama2.dnainternet.net (Postfix) with ESMTP id 8A81413682; Sun, 12 Apr 2020 22:56:56 +0300 (EEST) X-Virus-Scanned: DNA Internet at dnainternet.net X-Spam-Flag: NO X-Spam-Score: 0.252 X-Spam-Level: X-Spam-Status: No, score=0.252 tagged_above=-9999 required=6 tests=[HEADER_FROM_DIFFERENT_DOMAINS=0.25, SPF_HELO_NONE=0.001, SPF_NONE=0.001] autolearn=disabled Received: from sinikuusama2.dnainternet.net ([83.102.40.152]) by localhost (sinikuusama2.dnainternet.net [127.0.0.1]) (DNA Internet, port 10041) with ESMTP id LVUBdHiFLNu8; Sun, 12 Apr 2020 22:56:55 +0300 (EEST) Received: from luumupuu2.dnainternet.net (luumupuu2.dnainternet.net [83.102.40.55]) by sinikuusama2.dnainternet.net (Postfix) with ESMTP id DC80A135D3; Sun, 12 Apr 2020 22:56:55 +0300 (EEST) Received: from mail.onse.fi (88-148-249-225.rev.dnainternet.fi [88.148.249.225]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by luumupuu2.dnainternet.net (Postfix) with ESMTPS id 7819589; Sun, 12 Apr 2020 22:56:53 +0300 (EEST) Received: by mail.onse.fi (Postfix, from userid 1000) id F1726406A2; Sun, 12 Apr 2020 22:56:52 +0300 (EEST) From: Anssi Hannula To: ffmpeg-devel@ffmpeg.org Date: Sun, 12 Apr 2020 22:56:26 +0300 Message-Id: <20200412195626.9090-1-anssi.hannula@iki.fi> X-Mailer: git-send-email 2.25.2 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH] avformat/spdifenc: handle long TrueHD input_timing gaps 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 Cc: Carl Eugen Hoyos Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Some TrueHD streams contain frames that have very long gaps in input_timing fields, while output_timing remains constant-rate. These are likely due to encoding discontinuities of some sort as the TrueHD substream terminator marker is observed before the gap. Such frames trigger a sanity check in the current code - however, such gaps are valid. The gaps require us to insert many IEC 61937 bursts worth of MAT padding into the output. To facilitate that, add a mechanism in spdif_write_packet() to allow writing out multiple bursts per AVPacket, and use that in spdif_header_truehd() to write out any full bursts that do not yet contain any actual audio data from the current AVPacket. Modify the sanity check to allow up to 50 MAT frames full of padding. Fixes: incredibles2-truehd-bitstreaming.thd --- I'll apply this soon unless there are comments. libavformat/spdifenc.c | 48 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/libavformat/spdifenc.c b/libavformat/spdifenc.c index 0288872fd3..7041ecf2c8 100644 --- a/libavformat/spdifenc.c +++ b/libavformat/spdifenc.c @@ -68,6 +68,7 @@ typedef struct IEC61937Context { int use_preamble; ///< preamble enabled (disabled for exactly pre-padded DTS) int extra_bswap; ///< extra bswap for payload (for LE DTS => standard BE DTS) + int more_bursts_needed; ///< more bursts needed for the same AVPacket uint8_t *hd_buf[2]; ///< allocated buffers to concatenate hd audio frames int hd_buf_size; ///< size of the hd audio buffer (eac3, dts4) @@ -80,6 +81,7 @@ typedef struct IEC61937Context { uint16_t truehd_prev_time; ///< input_timing from the last frame int truehd_prev_size; ///< previous frame size in bytes, including any MAT codes int truehd_samples_per_frame; ///< samples per frame for padding calculation + int truehd_padding_remaining; ///< amount of padding still needed before data /* AVOptions: */ int dtshd_rate; @@ -450,7 +452,12 @@ static int spdif_header_truehd(AVFormatContext *s, AVPacket *pkt) return AVERROR_INVALIDDATA; input_timing = AV_RB16(pkt->data + 2); - if (ctx->truehd_prev_size) { + + if (ctx->truehd_padding_remaining) { + /* padding was calculated on previous call and some still remains */ + padding_remaining = ctx->truehd_padding_remaining; + + } else if (ctx->truehd_prev_size) { uint16_t delta_samples = input_timing - ctx->truehd_prev_time; /* * One multiple-of-48kHz frame is 1/1200 sec and the IEC 61937 rate @@ -470,8 +477,8 @@ static int spdif_header_truehd(AVFormatContext *s, AVPacket *pkt) delta_samples, delta_bytes); /* sanity check */ - if (padding_remaining < 0 || padding_remaining >= MAT_FRAME_SIZE / 2) { - avpriv_request_sample(s, "Unusual frame timing: %"PRIu16" => %"PRIu16", %d samples/frame", + if (padding_remaining < 0 || padding_remaining >= MAT_PKT_OFFSET * 50) { + avpriv_request_sample(s, "Unusual frame timing (%"PRIu16" => %"PRIu16", %d samples/frame)", ctx->truehd_prev_time, input_timing, ctx->truehd_samples_per_frame); padding_remaining = 0; } @@ -520,6 +527,15 @@ static int spdif_header_truehd(AVFormatContext *s, AVPacket *pkt) /* count the remainder of the code as part of frame size */ if (code_len_remaining) total_frame_size += code_len_remaining; + + if (have_pkt && padding_remaining) { + /* + * We already have a full burst but padding still remains, + * write out the current burst and ask us to be called again + * via ctx->more_bursts_needed to avoid filling our buffers. + */ + break; + } } if (padding_remaining) { @@ -547,9 +563,14 @@ static int spdif_header_truehd(AVFormatContext *s, AVPacket *pkt) ctx->truehd_prev_size = total_frame_size; ctx->truehd_prev_time = input_timing; + ctx->truehd_padding_remaining = padding_remaining; - av_log(s, AV_LOG_TRACE, "TrueHD frame inserted, total size %d, buffer position %d\n", - total_frame_size, ctx->hd_buf_filled); + if (padding_remaining) + av_log(s, AV_LOG_TRACE, "TrueHD frame not yet inserted, %d bytes more padding needed\n", + padding_remaining); + else + av_log(s, AV_LOG_TRACE, "TrueHD frame inserted, total size %d, buffer position %d\n", + total_frame_size, ctx->hd_buf_filled); if (!have_pkt) { ctx->pkt_offset = 0; @@ -560,6 +581,8 @@ static int spdif_header_truehd(AVFormatContext *s, AVPacket *pkt) ctx->pkt_offset = MAT_PKT_OFFSET; ctx->out_bytes = MAT_FRAME_SIZE; ctx->length_code = MAT_FRAME_SIZE; + if (padding_remaining) + ctx->more_bursts_needed = 1; return 0; } @@ -619,7 +642,7 @@ static av_always_inline void spdif_put_16(IEC61937Context *ctx, avio_wl16(pb, val); } -static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt) +static int spdif_write_burst(AVFormatContext *s, AVPacket *pkt) { IEC61937Context *ctx = s->priv_data; int ret, padding; @@ -629,6 +652,7 @@ static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt) ctx->length_code = FFALIGN(pkt->size, 2) << 3; ctx->use_preamble = 1; ctx->extra_bswap = 0; + ctx->more_bursts_needed = 0; ret = ctx->header_info(s, pkt); if (ret < 0) @@ -671,6 +695,18 @@ static int spdif_write_packet(struct AVFormatContext *s, AVPacket *pkt) return 0; } +static int spdif_write_packet(AVFormatContext *s, AVPacket *pkt) +{ + IEC61937Context *ctx = s->priv_data; + int ret = 0; + + ctx->more_bursts_needed = 1; + while (ctx->more_bursts_needed && ret == 0) + ret = spdif_write_burst(s, pkt); + + return ret; +} + AVOutputFormat ff_spdif_muxer = { .name = "spdif", .long_name = NULL_IF_CONFIG_SMALL("IEC 61937 (used on S/PDIF - IEC958)"),