From patchwork Wed Nov 21 09:35:30 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 11103 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 988A644C6E1 for ; Wed, 21 Nov 2018 11:35:42 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 19DF968090B; Wed, 21 Nov 2018 11:35:43 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm1-f65.google.com (mail-wm1-f65.google.com [209.85.128.65]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id E7E9F68083A for ; Wed, 21 Nov 2018 11:35:36 +0200 (EET) Received: by mail-wm1-f65.google.com with SMTP id 125so4811318wmh.0 for ; Wed, 21 Nov 2018 01:35:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=ciF0OHUr1ljkV1KF1i1L39H26/3JGy+7e0w1dLQgYcc=; b=u6FbkQO9L2TAV4a52iE6S1ptPA5Kg/+2D9iaE+nad6+s690JS7LUPeRCbG54H6JDyx Mb3CC6QsN8zrGhq9fAwfLbpDBmT2kav/fyOa0U03EYoU0s3H2qPaavEdvi+3YP0YtSTV ZcfBd0f3m10UhFToRhqExRsvbgemIyC/4eQT1kO72UTKpngb6dN5BPIQxmHiNX/TBs22 A7FPI+v/vnqZyxHmu6Kzi6Dl2UnurBSEPCVCt5y6d4OcZxiXxyyrkyarvKOx/71tp7tS EjVAK1oogTPfwwUaiMqP4uKbwi7eLb1YeB1gfPeSBoam92r3fovSrXbYywX2T5943YPT EpVA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=ciF0OHUr1ljkV1KF1i1L39H26/3JGy+7e0w1dLQgYcc=; b=qgoMQRF+0y54FKXODnI3ilqf6ydsQr0bEoM4qjBfLGzr7JeGvcu9qwrdoRpjiG2/JV SQ+E6ByH7P0ifGwGAgL7CWzZ6NpKIHrKGSWgf7IzLZxtljrOthmzUVyVcpOLTWualDBi dn3qUSXa+lsCi2k+iaxzHpkMyoNuw5VYd78t1Nwas0UaQgzSR0XVAF6guFWVtjFkORME 3xbcVFWCd7zb2RNIfTe/WPvXPxDMtsOAqS2B7vhEFJZsvH74+zRXa9RY968BU9YrVjWU 0dw5SfdGnpc+gsanTe4sgAB1pD0/9ZXrq60YQSY6xmqySU1euS52qLhvdC45Xc/yqQnp m4og== X-Gm-Message-State: AA+aEWYrpOKjGOcOJOC+lGrzQvFCRjjYG4BgzXCNeTsvSo5qHylJEiyh A/mYRHcA1HeiVv/8FgT10P40mmVI X-Google-Smtp-Source: AFSGD/U7Q72ziiuIO5qdEIn4gCcaibgqFydhDU8fCFiIDeAYN7JzOKmO5xVblWMWtjBlOaV1VVYp3g== X-Received: by 2002:a1c:9e90:: with SMTP id h138mr1518682wme.17.1542792938630; Wed, 21 Nov 2018 01:35:38 -0800 (PST) Received: from localhost.localdomain ([94.250.174.60]) by smtp.gmail.com with ESMTPSA id q12sm21612211wrx.31.2018.11.21.01.35.37 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 21 Nov 2018 01:35:38 -0800 (PST) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Wed, 21 Nov 2018 10:35:30 +0100 Message-Id: <20181121093530.31659-1-onemda@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181120181702.17988-1-onemda@gmail.com> References: <20181120181702.17988-1-onemda@gmail.com> Subject: [FFmpeg-devel] [PATCH] avcodec: add truehd_core bitstream filter 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 MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Paul B Mahol --- configure | 1 + doc/bitstream_filters.texi | 4 + libavcodec/Makefile | 1 + libavcodec/bitstream_filters.c | 1 + libavcodec/truehd_core_bsf.c | 184 +++++++++++++++++++++++++++++++++ 5 files changed, 191 insertions(+) create mode 100644 libavcodec/truehd_core_bsf.c diff --git a/configure b/configure index b4f944cfb0..faea24347e 100755 --- a/configure +++ b/configure @@ -3046,6 +3046,7 @@ hevc_metadata_bsf_select="cbs_h265" mjpeg2jpeg_bsf_select="jpegtables" mpeg2_metadata_bsf_select="cbs_mpeg2" trace_headers_bsf_select="cbs" +truehd_core_bsf_select="mlp_parser" vp9_metadata_bsf_select="cbs_vp9" # external libraries diff --git a/doc/bitstream_filters.texi b/doc/bitstream_filters.texi index 655a2c1e63..15c578aa8a 100644 --- a/doc/bitstream_filters.texi +++ b/doc/bitstream_filters.texi @@ -634,6 +634,10 @@ This can be useful for debugging low-level stream issues. Supports H.264, H.265, MPEG-2 and VP9. +@section truehd_core + +Extract the core from a TrueHD stream, dropping ATMOS data. + @section vp9_metadata Modify metadata embedded in a VP9 stream. diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 716f26d191..2840a8069f 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1085,6 +1085,7 @@ OBJS-$(CONFIG_PRORES_METADATA_BSF) += prores_metadata_bsf.o OBJS-$(CONFIG_REMOVE_EXTRADATA_BSF) += remove_extradata_bsf.o OBJS-$(CONFIG_TEXT2MOVSUB_BSF) += movsub_bsf.o OBJS-$(CONFIG_TRACE_HEADERS_BSF) += trace_headers_bsf.o +OBJS-$(CONFIG_TRUEHD_CORE_BSF) += truehd_core_bsf.o mlp_parser.o mlp.o OBJS-$(CONFIG_VP9_METADATA_BSF) += vp9_metadata_bsf.o OBJS-$(CONFIG_VP9_RAW_REORDER_BSF) += vp9_raw_reorder_bsf.o OBJS-$(CONFIG_VP9_SUPERFRAME_BSF) += vp9_superframe_bsf.o diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c index 2a8598bac2..2c999d3c1d 100644 --- a/libavcodec/bitstream_filters.c +++ b/libavcodec/bitstream_filters.c @@ -51,6 +51,7 @@ extern const AVBitStreamFilter ff_prores_metadata_bsf; extern const AVBitStreamFilter ff_remove_extradata_bsf; extern const AVBitStreamFilter ff_text2movsub_bsf; extern const AVBitStreamFilter ff_trace_headers_bsf; +extern const AVBitStreamFilter ff_truehd_core_bsf; extern const AVBitStreamFilter ff_vp9_metadata_bsf; extern const AVBitStreamFilter ff_vp9_raw_reorder_bsf; extern const AVBitStreamFilter ff_vp9_superframe_bsf; diff --git a/libavcodec/truehd_core_bsf.c b/libavcodec/truehd_core_bsf.c new file mode 100644 index 0000000000..be021af8e8 --- /dev/null +++ b/libavcodec/truehd_core_bsf.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2018 Paul B Mahol + * + * 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 "avcodec.h" +#include "bsf.h" +#include "get_bits.h" +#include "mlp_parser.h" +#include "mlp.h" + +typedef struct AccessUnit { + uint8_t bits[4]; + uint16_t offset; + uint16_t optional; +} AccessUnit; + +typedef struct TrueHDCoreContext { + const AVClass *class; + + MLPHeaderInfo hdr; +} TrueHDCoreContext; + +static int truehd_core_filter(AVBSFContext *ctx, AVPacket *out) +{ + TrueHDCoreContext *s = ctx->priv_data; + GetBitContext gbc; + AccessUnit units[MAX_SUBSTREAMS]; + AVPacket *in; + int ret, i, size, last_offset = 0; + int in_size, out_size; + int have_header = 0; + int substream_bits = 0; + int start, end; + uint16_t dts; + + ret = ff_bsf_get_packet(ctx, &in); + if (ret < 0) + return ret; + + if (in->size < 4) + goto fail; + + ret = init_get_bits(&gbc, in->data, 32); + if (ret < 0) + goto fail; + + skip_bits(&gbc, 4); + in_size = get_bits(&gbc, 12) * 2; + if (in_size < 4 || in_size > in->size) + goto fail; + + out_size = in_size; + dts = get_bits(&gbc, 16); + + ret = init_get_bits8(&gbc, in->data + 4, in->size - 4); + if (ret < 0) + goto fail; + + if (show_bits_long(&gbc, 32) == 0xf8726fba) { + if ((ret = ff_mlp_read_major_sync(ctx, &s->hdr, &gbc)) != 0) + goto fail; + have_header = 1; + } + + if (s->hdr.num_substreams > MAX_SUBSTREAMS) + goto fail; + + start = get_bits_count(&gbc); + for (i = 0; i < s->hdr.num_substreams; i++) { + for (int j = 0; j < 4; j++) + units[i].bits[j] = get_bits1(&gbc); + + units[i].offset = get_bits(&gbc, 12) * 2; + if (i < FFMIN(s->hdr.num_substreams, 3)) { + last_offset = units[i].offset; + substream_bits += 16; + } + + if (units[i].bits[0]) { + units[i].optional = get_bits(&gbc, 16); + if (i < FFMIN(s->hdr.num_substreams, 3)) + substream_bits += 16; + } + } + end = get_bits_count(&gbc); + + size = ((end + 7) >> 3) + 4 + last_offset; + if (size >= 0 && size <= in->size) + out_size = size; + if (out_size < in_size) { + int bpos = 0, reduce = (end - start - substream_bits) >> 4; + uint16_t parity_nibble = 0; + uint16_t auheader; + + ret = av_new_packet(out, out_size); + if (ret < 0) + goto fail; + + AV_WB16(out->data + 2, dts); + parity_nibble = dts; + out->size -= reduce * 2; + parity_nibble ^= out->size / 2; + + if (have_header) { + memcpy(out->data + 4, in->data + 4, 28); + out->data[16 + 4] = (out->data[16 + 4] & 0x0f) | (FFMIN(s->hdr.num_substreams, 3) << 4); + out->data[25 + 4] = out->data[25 + 4] & 0xfe; + out->data[26 + 4] = 0xff; + out->data[27 + 4] = 0xff; + AV_WL16(out->data + 4 + 26, ff_mlp_checksum16(out->data + 4, 26)); + } + + for (i = 0; i < FFMIN(s->hdr.num_substreams, 3); i++) { + uint16_t substr_hdr = 0; + + substr_hdr |= (units[i].bits[0] << 15); + substr_hdr |= (units[i].bits[1] << 14); + substr_hdr |= (units[i].bits[2] << 13); + substr_hdr |= (units[i].bits[3] << 12); + substr_hdr |= (units[i].offset / 2) & 0x0FFF; + + AV_WB16(out->data + have_header * 28 + 4 + bpos, substr_hdr); + + parity_nibble ^= out->data[have_header * 28 + 4 + bpos++]; + parity_nibble ^= out->data[have_header * 28 + 4 + bpos++]; + + if (units[i].bits[0]) { + AV_WB16(out->data + have_header * 28 + 4 + bpos, units[i].optional); + + parity_nibble ^= out->data[have_header * 28 + 4 + bpos++]; + parity_nibble ^= out->data[have_header * 28 + 4 + bpos++]; + } + } + + parity_nibble ^= parity_nibble >> 8; + parity_nibble ^= parity_nibble >> 4; + parity_nibble &= 0xF; + + memcpy(out->data + have_header * 28 + 4 + bpos, + in->data + 4 + (end >> 3), + out_size - (4 + (end >> 3))); + auheader = (parity_nibble ^ 0xF) << 12; + auheader |= (out->size / 2) & 0x0fff; + AV_WB16(out->data, auheader); + + ret = av_packet_copy_props(out, in); + } else { + av_packet_move_ref(out, in); + } + +fail: + if (ret < 0) + av_packet_unref(out); + av_packet_free(&in); + + return ret; +} + +static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_TRUEHD, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_truehd_core_bsf = { + .name = "truehd_core", + .priv_data_size = sizeof(TrueHDCoreContext), + .filter = truehd_core_filter, + .codec_ids = codec_ids, +};