[FFmpeg-devel] [PATCH 1/4] cbs: Add some common code for read/write of miscellaneous user data
Aman Gupta
ffmpeg at tmm1.net
Wed Sep 11 21:56:07 EEST 2019
From: Mark Thompson <sw at jkqxz.net>
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 | 217 ++++++++++++++++++++++++++
libavcodec/cbs_misc.h | 109 +++++++++++++
libavcodec/cbs_misc_syntax_template.c | 150 ++++++++++++++++++
3 files changed, 476 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..d0ced562f5
--- /dev/null
+++ b/libavcodec/cbs_misc.c
@@ -0,0 +1,217 @@
+/*
+ * 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, NULL, \
+ &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, NULL, \
+ &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, NULL, \
+ 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, NULL, \
+ 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;
+ }
+ }
+
+ flush_put_bits(&pbc);
+ *side_data_size += 3 * cc->cc_count;
+
+ 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.20.1
More information about the ffmpeg-devel
mailing list