Message ID | 20180325174137.14749-1-sw@jkqxz.net |
---|---|
State | New |
Headers | show |
On Sun, Mar 25, 2018 at 10:41 AM Mark Thompson <sw@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@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel >
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; + + 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; +}