[FFmpeg-devel] [PATCH] avcodec: add truehd_core bitstream filter
James Almer
jamrial at gmail.com
Wed Nov 21 04:29:04 EET 2018
On 11/20/2018 3:17 PM, Paul B Mahol wrote:
> Signed-off-by: Paul B Mahol <onemda at gmail.com>
> ---
> doc/bitstream_filters.texi | 4 +
> libavcodec/Makefile | 1 +
> libavcodec/bitstream_filters.c | 1 +
> libavcodec/truehd_core_bsf.c | 182 +++++++++++++++++++++++++++++++++
> 4 files changed, 188 insertions(+)
> create mode 100644 libavcodec/truehd_core_bsf.c
>
> 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.
>
> + at 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..bcced2e371 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
> 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..0449719185
> --- /dev/null
> +++ b/libavcodec/truehd_core_bsf.c
> @@ -0,0 +1,182 @@
> +/*
> + * 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"
Missing deps in configure or Makefile for mlp parser and whatever else
is needed.
> +
> +typedef struct AccessUnit {
> + uint8_t bits[4];
> + uint16_t offset;
> + uint16_t optional;
> +} AccessUnit;
> +
> +typedef struct TrueHDCoreContext {
> + const AVClass *class;
> +
> + AccessUnit units[4];
If this is going to be overwritten on every frame and old state doesn't
matter, then allocate it on stack.
> +
> + MLPHeaderInfo hdr;
> +} TrueHDCoreContext;
> +
> +static int truehd_core_filter(AVBSFContext *ctx, AVPacket *out)
> +{
> + TrueHDCoreContext *s = ctx->priv_data;
> + GetBitContext gbc;
> + 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;
> +
> + ret = init_get_bits8(&gbc, in->data, 4);
No need for init_get_bits8() if it's going to be 4 bytes. Use
init_get_bits() and skip all the pointless overflow checks.
> + 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;
> + }
> +
> + start = get_bits_count(&gbc);
> + for (i = 0; i < s->hdr.num_substreams; i++) {
> + for (int j = 0; j < 4; j++)
> + s->units[i].bits[j] = get_bits1(&gbc);
> +
> + s->units[i].offset = get_bits(&gbc, 12) * 2;
> + if (i < FFMIN(s->hdr.num_substreams, 3)) {
> + last_offset = s->units[i].offset;
> + substream_bits += 16;
> + }
> +
> + if (s->units[i].bits[0]) {
> + s->units[i].optional = get_bits(&gbc, 16);
> + if (i < FFMIN(s->hdr.num_substreams, 3))
> + substream_bits += 16;
> + }
> + }
> + end = get_bits_count(&gbc);
> +
> + ret = av_packet_copy_props(out, in);
Move this to the end. See below.
> + if (ret < 0)
> + goto fail;
> +
> + size = ((end + 7) >> 3) + 4 + last_offset;
> + if (size >= 0 && size <= in->size)
> + out_size = size;
> + ret = av_grow_packet(out, out_size);
out is clear/unallocated , so use av_new_packet() instead, and put it...
> + if (ret < 0)
> + goto fail;
> +
> + if (out_size < in_size) {
> + int bpos = 0, reduce = (end - start - substream_bits) >> 4;
> + uint16_t parity_nibble = 0;
> + uint16_t auheader;
> +
...here.
> + 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 |= (s->units[i].bits[0] << 15);
> + substr_hdr |= (s->units[i].bits[1] << 14);
> + substr_hdr |= (s->units[i].bits[2] << 13);
> + substr_hdr |= (s->units[i].bits[3] << 12);
> + substr_hdr |= (s->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 (s->units[i].bits[0]) {
> + AV_WB16(out->data + have_header * 28 + 4 + bpos, s->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);
Put the av_packet_copy_props() call here.
> + } else {
> + memcpy(out->data, in->data, out_size);
av_packet_move_ref(out, in);
out->size = out_size;
There's no need to allocate and copy data and props when the output
packet is going to be the same as the input.
> + }
> +
> + av_packet_free(&in);
> +
> + return 0;
> +fail:
> + av_packet_unref(out);
> + av_packet_free(&in);
> + return ret;
Combine this for both failure and success cases. Check for ret < 0 to
call av_packet_unref(out), and return ret regardless of value.
> +}
> +
> +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,
> +};
>
More information about the ffmpeg-devel
mailing list