[FFmpeg-devel] [PATCH 1/5] cbs: Add some common code for read/write of miscellaneous user data
Aman Gupta
ffmpeg at tmm1.net
Sat Jul 27 04:21:49 EEST 2019
On Sun, Mar 25, 2018 at 10:41 AM Mark Thompson <sw at jkqxz.net> wrote:
> Supports closed captions, active format and bar data as defined by
> SCTE 128 part 1 or A/53 part 4, suitable for use with both MPEG-2
> and H.264.
> ---
> libavcodec/cbs_misc.c | 216
> ++++++++++++++++++++++++++++++++++
> libavcodec/cbs_misc.h | 109 +++++++++++++++++
> libavcodec/cbs_misc_syntax_template.c | 150 +++++++++++++++++++++++
> 3 files changed, 475 insertions(+)
> create mode 100644 libavcodec/cbs_misc.c
> create mode 100644 libavcodec/cbs_misc.h
> create mode 100644 libavcodec/cbs_misc_syntax_template.c
>
> diff --git a/libavcodec/cbs_misc.c b/libavcodec/cbs_misc.c
> new file mode 100644
> index 0000000000..cdf01fe229
> --- /dev/null
> +++ b/libavcodec/cbs_misc.c
> @@ -0,0 +1,216 @@
> +/*
> + * 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 "libavutil/attributes.h"
> +#include "libavutil/avassert.h"
> +
> +#include "cbs.h"
> +#include "cbs_internal.h"
> +#include "cbs_misc.h"
> +
> +#define CHECK(call) do { \
> + err = (call); \
> + if (err < 0) \
> + return err; \
> + } while (0)
> +
> +#define FUNC_NAME(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name
> +#define FUNC_MISC(rw, name) FUNC_NAME(rw, misc, name)
> +#define FUNC(name) FUNC_MISC(READWRITE, name)
> +
> +
> +#define READWRITE read
> +#define RWContext GetBitContext
> +
> +#define xui(width, name, var) do { \
> + uint32_t value = 0; \
> + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \
> + &value, 0, MAX_UINT_BITS(width))); \
> + var = value; \
> + } while (0)
> +
> +#define ui(width, name) \
> + xui(width, name, current->name)
> +
> +#define fixed(width, name, expected) do { \
> + av_unused uint32_t value; \
> + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, &value, \
> + expected, expected)); \
> + } while (0)
> +
> +#include "cbs_misc_syntax_template.c"
> +
> +#undef READWRITE
> +#undef RWContext
> +#undef xui
> +#undef ui
> +#undef fixed
> +
> +
> +#define READWRITE write
> +#define RWContext PutBitContext
> +
> +#define xui(width, name, var) do { \
> + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \
> + var, 0, MAX_UINT_BITS(width))); \
> + } while (0)
> +
> +#define ui(width, name) \
> + xui(width, name, current->name)
> +
> +#define fixed(width, name, value) do { \
> + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, value, \
> + value, value)); \
> + } while (0)
> +
> +#include "cbs_misc_syntax_template.c"
> +
> +#undef READWRITE
> +#undef RWContext
> +#undef xui
> +#undef ui
> +#undef fixed
> +
> +
> +int ff_cbs_read_a53_user_data(CodedBitstreamContext *ctx,
> + A53UserData *data,
> + const uint8_t *read_buffer, size_t length)
> +{
> + GetBitContext gbc;
> + int err;
> +
> + err = init_get_bits(&gbc, read_buffer, 8 * length);
> + if (err < 0)
> + return err;
> +
> + return cbs_misc_read_a53_user_data(ctx, &gbc, data);
> +}
> +
> +int ff_cbs_write_a53_user_data(CodedBitstreamContext *ctx,
> + uint8_t *write_buffer, size_t *length,
> + A53UserData *data)
> +{
> + PutBitContext pbc;
> + int err;
> +
> + init_put_bits(&pbc, write_buffer, *length);
> +
> + err = cbs_misc_write_a53_user_data(ctx, &pbc, data);
> + if (err < 0) {
> + // Includes AVERROR(ENOSPC).
> + return err;
> + }
> +
> + // That output must be aligned.
> + av_assert0(put_bits_count(&pbc) % 8 == 0);
> +
> + *length = put_bits_count(&pbc) / 8;
> +
> + flush_put_bits(&pbc);
> +
> + return 0;
> +}
> +
> +int ff_cbs_read_a53_cc_side_data(CodedBitstreamContext *ctx,
> + A53UserData *data,
> + const uint8_t *side_data,
> + size_t side_data_size)
> +{
> + GetBitContext gbc;
> + CEA708CCData *cc;
> + int err, i, cc_count;
> +
> + if (side_data_size % 3) {
> + av_log(ctx->log_ctx, AV_LOG_ERROR, "A53 CC side data length must "
> + "be a multiple of 3 (got %zu).\n", side_data_size);
> + return AVERROR(EINVAL);
> + }
> + cc_count = side_data_size / 3;
> + if (cc_count > 31) {
> + av_log(ctx->log_ctx, AV_LOG_ERROR, "A53 CC can only fit 31
> packets "
> + "in a single user data block (got %d).\n", cc_count);
> + return AVERROR(EINVAL);
> + }
> +
> + *data = (A53UserData) {
> + .user_identifier = A53_USER_IDENTIFIER_ATSC,
> +
> + .atsc = {
> + .user_data_type_code = A53_USER_DATA_TYPE_CODE_CC_DATA,
> +
> + .cc_data = {
> + .process_em_data_flag = 0,
> + .process_cc_data_flag = 1,
> + .additional_data_flag = 0,
> +
> + .em_data = 0,
> +
> + .cc_count = cc_count,
> + },
> + },
> + };
> + cc = &data->atsc.cc_data;
> +
> + err = init_get_bits(&gbc, side_data, 8 * side_data_size);
> + if (err < 0)
> + return err;
> +
> + for (i = 0; i < cc->cc_count; i++) {
> + err = cbs_misc_read_cea708_cc_data_packet(ctx, &gbc,
> + &cc->cc_data_pkts[i]);
> + if (err < 0)
> + return err;
> + }
> +
> + return 0;
> +}
> +
> +int ff_cbs_write_a53_cc_side_data(CodedBitstreamContext *ctx,
> + uint8_t **side_data,
> + size_t *side_data_size,
> + A53UserData *data)
> +{
> + PutBitContext pbc;
> + CEA708CCData *cc;
> + int err, i;
> +
> + if (data->user_identifier != A53_USER_IDENTIFIER_ATSC ||
> + data->atsc.user_data_type_code != A53_USER_DATA_TYPE_CODE_CC_DATA)
> + return AVERROR(EINVAL);
> +
> + cc = &data->atsc.cc_data;
> +
> + err = av_reallocp(side_data, *side_data_size + 3 * cc->cc_count);
> + if (err < 0)
> + return err;
> +
> + init_put_bits(&pbc, *side_data + *side_data_size, 3 * cc->cc_count);
> +
> + for (i = 0; i < cc->cc_count; i++) {
> + err = cbs_misc_write_cea708_cc_data_packet(ctx, &pbc,
> + &cc->cc_data_pkts[i]);
> + if (err < 0) {
> + av_freep(side_data);
> + return err;
> + }
> + }
> +
> + *side_data_size += 3 * cc->cc_count;
>
Missing flush_put_bits() here.
> +
> + return 0;
> +}
> diff --git a/libavcodec/cbs_misc.h b/libavcodec/cbs_misc.h
> new file mode 100644
> index 0000000000..0d7ab2c8e7
> --- /dev/null
> +++ b/libavcodec/cbs_misc.h
> @@ -0,0 +1,109 @@
> +/*
> + * 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
> + */
> +
> +#ifndef AVCODEC_CBS_MISC_H
> +#define AVCODEC_CBS_MISC_H
> +
> +#include <stddef.h>
> +#include <stdint.h>
> +
> +#include "libavutil/common.h"
> +
> +
> +enum {
> + A53_USER_IDENTIFIER_ATSC = MKBETAG('G', 'A', '9', '4'),
> + A53_USER_IDENTIFIER_AFD = MKBETAG('D', 'T', 'G', '1'),
> +};
> +
> +enum {
> + A53_USER_DATA_TYPE_CODE_CC_DATA = 0x03,
> + A53_USER_DATA_TYPE_CODE_BAR_DATA = 0x06,
> +};
> +
> +typedef struct A53BarData {
> + uint8_t top_bar_flag;
> + uint8_t bottom_bar_flag;
> + uint8_t left_bar_flag;
> + uint8_t right_bar_flag;
> +
> + uint16_t line_number_end_of_top_bar;
> + uint16_t line_number_end_of_bottom_bar;
> + uint16_t line_number_end_of_left_bar;
> + uint16_t line_number_end_of_right_bar;
> +} A53BarData;
> +
> +typedef struct CEA708CCDataPacket {
> + uint8_t cc_valid;
> + uint8_t cc_type;
> + uint8_t cc_data_1;
> + uint8_t cc_data_2;
> +} CEA708CCDataPacket;
> +
> +typedef struct CEA708CCData {
> + uint8_t process_em_data_flag;
> + uint8_t process_cc_data_flag;
> + uint8_t additional_data_flag;
> +
> + uint8_t em_data;
> +
> + uint8_t cc_count;
> + CEA708CCDataPacket cc_data_pkts[31];
> +} CEA708CCData;
> +
> +typedef struct A53ATSCUserData {
> + uint8_t user_data_type_code;
> + union {
> + CEA708CCData cc_data;
> + A53BarData bar_data;
> + };
> +} A53ATSCUserData;
> +
> +typedef struct A53AFDData {
> + uint8_t active_format_flag;
> + uint8_t active_format;
> +} A53AFDData;
> +
> +typedef struct A53UserData {
> + uint32_t user_identifier;
> + union {
> + A53ATSCUserData atsc;
> + A53AFDData afd;
> + };
> +} A53UserData;
> +
> +
> +int ff_cbs_read_a53_user_data(CodedBitstreamContext *ctx,
> + A53UserData *data,
> + const uint8_t *read_buffer, size_t length);
> +
> +int ff_cbs_write_a53_user_data(CodedBitstreamContext *ctx,
> + uint8_t *write_buffer, size_t *length,
> + A53UserData *data);
> +
> +int ff_cbs_read_a53_cc_side_data(CodedBitstreamContext *ctx,
> + A53UserData *data,
> + const uint8_t *side_data,
> + size_t side_data_size);
> +
> +int ff_cbs_write_a53_cc_side_data(CodedBitstreamContext *ctx,
> + uint8_t **side_data,
> + size_t *side_data_length,
> + A53UserData *data);
> +
> +
> +#endif /* AVCODEC_CBS_MISC_H */
> diff --git a/libavcodec/cbs_misc_syntax_template.c
> b/libavcodec/cbs_misc_syntax_template.c
> new file mode 100644
> index 0000000000..7b98c7cc85
> --- /dev/null
> +++ b/libavcodec/cbs_misc_syntax_template.c
> @@ -0,0 +1,150 @@
> +/*
> + * 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
> + */
> +
> +static int FUNC(a53_bar_data)(CodedBitstreamContext *ctx, RWContext *rw,
> + A53BarData *current)
> +{
> + int err;
> +
> + ui(1, top_bar_flag);
> + ui(1, bottom_bar_flag);
> + ui(1, left_bar_flag);
> + ui(1, right_bar_flag);
> + fixed(4, reserved, 0xf);
> +
> + if (current->top_bar_flag) {
> + fixed(2, one_bits, 3);
> + ui(14, line_number_end_of_top_bar);
> + }
> + if (current->bottom_bar_flag) {
> + fixed(2, one_bits, 3);
> + ui(14, line_number_end_of_bottom_bar);
> + }
> + if (current->left_bar_flag) {
> + fixed(2, one_bits, 3);
> + ui(14, line_number_end_of_left_bar);
> + }
> + if (current->right_bar_flag) {
> + fixed(2, one_bits, 3);
> + ui(14, line_number_end_of_right_bar);
> + }
> +
> + return 0;
> +}
> +
> +static int FUNC(cea708_cc_data_packet)(CodedBitstreamContext *ctx,
> + RWContext *rw,
> + CEA708CCDataPacket *current)
> +{
> + int err;
> +
> + fixed(5, marker_bits, 0x1f);
> + ui(1, cc_valid);
> + ui(2, cc_type);
> +
> + ui(8, cc_data_1);
> + ui(8, cc_data_2);
> +
> + return 0;
> +}
> +
> +static int FUNC(cea708_cc_data)(CodedBitstreamContext *ctx, RWContext *rw,
> + CEA708CCData *current)
> +{
> + int err, i;
> +
> + ui(1, process_em_data_flag);
> + ui(1, process_cc_data_flag);
> + ui(1, additional_data_flag);
> +
> + ui(5, cc_count);
> +
> + ui(8, em_data);
> +
> + for (i = 0; i < current->cc_count; i++) {
> + CHECK(FUNC(cea708_cc_data_packet)(ctx, rw,
> + ¤t->cc_data_pkts[i]));
> + }
> +
> + fixed(8, marker_bits, 0xff);
> +
> + if (current->additional_data_flag) {
> + // Ignored.
> + }
> +
> + return 0;
> +}
> +
> +static int FUNC(a53_atsc_user_data)(CodedBitstreamContext *ctx, RWContext
> *rw,
> + A53ATSCUserData *current)
> +{
> + int err;
> +
> + ui(8, user_data_type_code);
> +
> + switch (current->user_data_type_code) {
> + case A53_USER_DATA_TYPE_CODE_CC_DATA:
> + return FUNC(cea708_cc_data)(ctx, rw, ¤t->cc_data);
> + case A53_USER_DATA_TYPE_CODE_BAR_DATA:
> + return FUNC(a53_bar_data)(ctx, rw, ¤t->bar_data);
> + default:
> + av_log(ctx->log_ctx, AV_LOG_WARNING,
> + "Unknown ATSC user data found: type code %#02x.\n",
> + current->user_data_type_code);
> + }
> +
> + return 0;
> +}
> +
> +static int FUNC(a53_afd_data)(CodedBitstreamContext *ctx, RWContext *rw,
> + A53AFDData *current)
> +{
> + int err;
> +
> + fixed(1, zero_bit, 0);
> + ui(1, active_format_flag);
> + fixed(6, alignment_bits, 1);
> +
> + if (current->active_format_flag) {
> + fixed(4, reserved, 0xf);
> + ui(4, active_format);
> + }
> +
> + return 0;
> +}
> +
> +static int FUNC(a53_user_data)(CodedBitstreamContext *ctx, RWContext *rw,
> + A53UserData *current)
> +{
> + int err;
> +
> + ui(32, user_identifier);
> +
> + switch (current->user_identifier) {
> + case A53_USER_IDENTIFIER_ATSC:
> + return FUNC(a53_atsc_user_data)(ctx, rw, ¤t->atsc);
> + case A53_USER_IDENTIFIER_AFD:
> + return FUNC(a53_afd_data)(ctx, rw, ¤t->afd);
> + default:
> + av_log(ctx->log_ctx, AV_LOG_WARNING,
> + "Unknown registered user data found: identifier %#08x.\n",
> + current->user_identifier);
> + }
> +
> + return 0;
> +}
> --
> 2.16.1
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
More information about the ffmpeg-devel
mailing list