On Sun, Mar 25, 2018 at 10:41 AM Mark Thompson <s...@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 > _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".