From patchwork Wed Sep 11 18:56:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aman Karmani X-Patchwork-Id: 15025 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 48C5544843B for ; Wed, 11 Sep 2019 21:56:25 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 29619687F9B; Wed, 11 Sep 2019 21:56:25 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-oi1-f177.google.com (mail-oi1-f177.google.com [209.85.167.177]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id C7E62680D0F for ; Wed, 11 Sep 2019 21:56:18 +0300 (EEST) Received: by mail-oi1-f177.google.com with SMTP id a127so15062261oii.2 for ; Wed, 11 Sep 2019 11:56:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tmm1-net.20150623.gappssmtp.com; s=20150623; h=sender:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=Kgyszdr5ElDJhiFy6ibC0SC5DPIEqnocl6Yzg2B2U5I=; b=mUE9FN/A0YuuNkaMaAcuD91AlVS2bwI8t/drsmgUQLOvT5mTfN22AuQLNlhx4p7rrw O5jtcmlgfquYFY+PN7GjQF1gj4qrigBCgbLlb+Meabdmkdj9SP1WYEr6scx5/I4LXAXx sLP45DY0hWb2wMivcmHqCOTkw3RU4ZoyPA3I+HkTpeFkeU0JUX4+3nf0YmXJudhZrIOA Ka9If6A7orJ87W+V+0+fRT3qu4weSEINy48NSJI96piRAasIclrOX50pIL1cmVWFltAI aRStrBOv0HCUUe86klOUqnAvdrqWuRGqlVYALfOR0SzE1jMRmN8fzui8fhMCp3KIKEhm j2jg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :mime-version:content-transfer-encoding; bh=Kgyszdr5ElDJhiFy6ibC0SC5DPIEqnocl6Yzg2B2U5I=; b=se/kl7JfNIjTbgPJv7nJsknummWsgmHoEpTuQbFQbCmHEQ74qkuAyj/ADQvpblLTCT uCAIkRQq1MHA34boLMrxZ3+KiNxWO+AuPoUiAjUt25485GHkoql79w3SZzVauMFm6JbB e+SrBsnw6qTdGaAf51p7RGeVjmeySUNRrFBVofr11+kxrbxXjsAkUhjzDixvtkN81Ln6 uIhrAKACdO2BEkWkc548iv7kxISvjCNJ2JUwmxg33UEl5tM9nZ2ZU3J207yiZs5Ps3Bu oJjEy6x60Z+z72tSqm3nCcX+vmLIvoJeBjYM0WVt54PF52dXsX241G9/y/Zp3As88QiO kA+Q== X-Gm-Message-State: APjAAAWIB+H+uEnYQk+NDTyifkxBjeniWC4bM/FE+cLFq4sTgShZK9MB zwZtolYPAr3gJ1wQpvmVXLtM5/ChPaKgdg== X-Google-Smtp-Source: APXvYqyRdh1Oxb5y3EidlNZC/0C2+2fkhQoXRYrcfc6iz3EJMPawbXC0JmCisfwTxC6ULIEDQvygBA== X-Received: by 2002:aca:cf13:: with SMTP id f19mr5600559oig.154.1568228176732; Wed, 11 Sep 2019 11:56:16 -0700 (PDT) Received: from tmm1-imac.lan (ip184-189-221-177.sb.sd.cox.net. [184.189.221.177]) by smtp.gmail.com with ESMTPSA id 34sm1487924otf.55.2019.09.11.11.56.15 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 11 Sep 2019 11:56:15 -0700 (PDT) From: Aman Gupta To: ffmpeg-devel@ffmpeg.org Date: Wed, 11 Sep 2019 11:56:07 -0700 Message-Id: <20190911185610.87081-1-ffmpeg@tmm1.net> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 1/4] cbs: Add some common code for read/write of miscellaneous user data X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: sw@jkqxz.net, andreas.rheinhardt@gmail.com Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" From: Mark Thompson 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 +#include + +#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; +}