From patchwork Tue Apr 28 06:15:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Pack X-Patchwork-Id: 19317 Delivered-To: andriy.gelman@gmail.com Received: by 2002:a25:3c87:0:0:0:0:0 with SMTP id j129csp3806280yba; Mon, 27 Apr 2020 23:21:27 -0700 (PDT) X-Google-Smtp-Source: APiQypLQafIKQ/b3Oi4t1OPrgPvHQKLtfZVLnzUJ8lIy5eTmhUn9AVgP8VkNeb3TJEJExV4iAWhG X-Received: by 2002:a1c:44b:: with SMTP id 72mr2667731wme.58.1588054887230; Mon, 27 Apr 2020 23:21:27 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1588054887; cv=none; d=google.com; s=arc-20160816; b=Ht9Qr+bTmq1ZWtF5l+offUeYrcIsroh3hKNwTfk5tznLs2iJpkZdoQAcCjFdYGw/uu AslFlv/fZTijhP+JnrUoPDOObochVqHb0bGSK4lBAZio3zuAuJabtSMytNTkIBB3h34U TxfRV2+g1wg1+7hQDFqdePCYIN4j8wgI95lNFNA8Tv+EzC3FMVpf/kWPfqQXcBjYv9mJ RXsnNLDKpN6f/UJFo7NvjEwAJx5ruLoTrDXOnjC89+M6yJHqbL/+UDhSOYClCTdMSmWH 4PfWwsa6s1hv/IJIBcWuN3ZGSp1EymOA6AaelpsoqcQli0wIxD31ddtAXbmbDeFDoMcg 2ugw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject:to :message-id:date:from:mime-version:dkim-signature:delivered-to; bh=H5CVE9IuB9RpW5gkPvqcEBjYFkLkQtWKvqIgndwIZA0=; b=onXa2WGrPyhCAdrVy488MZI+QML0G99TVO5RQ0wDXVBnaODUVRebMhIf0fhOjZSw8B /0xraJU7MpUW5tC5USMI9Dd+Vaqgwd+RUh5i3+k0wdvKIIZbh+fJFZaUIR6IwY1gvDGq yA5A0krTpeVlCoHpjFs/AmY3gswl8+ymHJ2qN+VRBANKqgJQLG7P6L+Gxw5l1hjwyrTE zsrWod3TlAQaHbXAgIMvxwMg+4SWgTXwU8IqYD4JHcv2cu1tgzcg9bnNODYHs96kHbwa FhK9QB6RdtVsZWYZUFVa0Yr51HYVdg+O0p3p34VvZhuZ5fFhprEr6CoB/Rd2ZeHw4Vt6 dERw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=duN0z9rC; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id r15si1372792wmh.113.2020.04.27.23.21.26; Mon, 27 Apr 2020 23:21:27 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20161025 header.b=duN0z9rC; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 0598D68BD59; Tue, 28 Apr 2020 09:21:24 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lf1-f42.google.com (mail-lf1-f42.google.com [209.85.167.42]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 25D3968BCF5 for ; Tue, 28 Apr 2020 09:21:16 +0300 (EEST) Received: by mail-lf1-f42.google.com with SMTP id g10so15809088lfj.13 for ; Mon, 27 Apr 2020 23:21:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:from:date:message-id:subject:to; bh=JLyMzheniubam1i2uzpLhlM2YqX0Ywy0u9f8/1H5EGg=; b=duN0z9rC9enQsjYzKAXUDup6z0ZeXflIBHR+7CpETTXBU1ZeY0XyIa3Bc24PZXXqyv TQQgOMpL89VALG0AI6UhtVehUqSGvyBoMgLYZGibQPKxmkDlSu4EDlwoHtvFqrvjFn9t NnF5/tMFBhs1AGNrV0SsY787eKU2y7UFzzUkiamhiS83At0jjBIbJrtiq1javKU3+uZO /8VADUgrKzclVlQAPJY0iq6o79pIS5+wy+3gaCxOtLU8+4N1zTXerpvauVHxfayEKkWe Gl1jP9Nfvc5t/Wku0TD8rjWYM/1qiHoDemTB8euUgIlW+vcC4GfZ2QsutA3YJ5KUXNcF jzRQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=JLyMzheniubam1i2uzpLhlM2YqX0Ywy0u9f8/1H5EGg=; b=mmE6D7687yIX3rg4hmiqL08ixCC/M6hFJdKireETo7AteTKXRku9U6QNk75NkxrfaP QzL8D6GUXmFDyfwP1a/8QhSBu1kzGcK8xlxtni2vdZzE5o1CvC7dtXWNSU51N3IVMPrT fy1K4cxQdM0PllzciajJlIVG4ZWJpLJDXC+rgxmGOBtjKqkyDH0k8zJ2VX15axNTH/tR OoXmgzWSO+PysVKcLJlB+VXE6dpieDdyLlEcP+ztZweUkHlQLtlm7TG648aTIoB+Uoxc IM8SNflaxc8W/89wXEjAFeQFNqwKh8PP2qUsTStfwHi1J5k5tB7bCKPL5gSCtLWkzDeW vSzg== X-Gm-Message-State: AGi0PuYrdw2c68US3FdLOxYbDUT9x7qeLk3WnJcHP+BkCIRbB112Coqa seqQd+kNE2Ac7ZCBdW9kCJPSI52ycVCZtPRMvdiE9WoK X-Received: by 2002:a19:e049:: with SMTP id g9mr18344441lfj.198.1588054529210; Mon, 27 Apr 2020 23:15:29 -0700 (PDT) MIME-Version: 1.0 From: Roger Pack Date: Tue, 28 Apr 2020 00:15:19 -0600 Message-ID: To: FFmpeg development discussions and patches Subject: [FFmpeg-devel] [PATCH 1/3] closed caption decoder: accept and decode a new codec type of 'raw 608 byte pairs' 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 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: nKIdB7G/mJWr Content-Length: 15526 I needed this in order to be able to parse raw analog TV closed caption byte pairs (analog line 21 CC's). Signed-off-by: rogerdpack --- configure | 1 + libavcodec/Makefile | 2 +- libavcodec/allcodecs.c | 1 + libavcodec/ccaption_dec.c | 117 ++++++++++++++++++++++++++------------ libavcodec/codec_desc.c | 7 +++ libavcodec/codec_id.h | 1 + libavcodec/version.h | 4 +- 7 files changed, 93 insertions(+), 40 deletions(-) diff --git a/configure b/configure index 080d93a129..8a0a6cce7c 100755 --- a/configure +++ b/configure @@ -2681,6 +2681,7 @@ bink_decoder_select="blockdsp hpeldsp" binkaudio_dct_decoder_select="mdct rdft dct sinewin wma_freqs" binkaudio_rdft_decoder_select="mdct rdft sinewin wma_freqs" cavs_decoder_select="blockdsp golomb h264chroma idctdsp qpeldsp videodsp" +ccaption_raw_608_decoder_select="ccaption_decoder" clearvideo_decoder_select="idctdsp" cllc_decoder_select="bswapdsp" comfortnoise_encoder_select="lpc" diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 28076c2c83..006eb40107 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -246,6 +246,7 @@ OBJS-$(CONFIG_C93_DECODER) += c93.o OBJS-$(CONFIG_CAVS_DECODER) += cavs.o cavsdec.o cavsdsp.o \ cavsdata.o OBJS-$(CONFIG_CCAPTION_DECODER) += ccaption_dec.o ass.o +OBJS-$(CONFIG_CCAPTION_RAW_608_DECODER) += ccaption_dec.o ass.o OBJS-$(CONFIG_CDGRAPHICS_DECODER) += cdgraphics.o OBJS-$(CONFIG_CDTOONS_DECODER) += cdtoons.o OBJS-$(CONFIG_CDXL_DECODER) += cdxl.o @@ -463,7 +464,6 @@ OBJS-$(CONFIG_MP3ON4FLOAT_DECODER) += mpegaudiodec_float.o mpeg4audio.o OBJS-$(CONFIG_MPC7_DECODER) += mpc7.o mpc.o OBJS-$(CONFIG_MPC8_DECODER) += mpc8.o mpc.o OBJS-$(CONFIG_MPEGVIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o -OBJS-$(CONFIG_MPEG1VIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o OBJS-$(CONFIG_MPEG1VIDEO_ENCODER) += mpeg12enc.o mpeg12.o OBJS-$(CONFIG_MPEG1_CUVID_DECODER) += cuviddec.o OBJS-$(CONFIG_MPEG1_V4L2M2M_DECODER) += v4l2_m2m_dec.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 54d40ebdbc..b78f58cb4c 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -645,6 +645,7 @@ extern AVCodec ff_ssa_decoder; extern AVCodec ff_ass_encoder; extern AVCodec ff_ass_decoder; extern AVCodec ff_ccaption_decoder; +extern AVCodec ff_ccaption_raw_608_decoder; extern AVCodec ff_dvbsub_encoder; extern AVCodec ff_dvbsub_decoder; extern AVCodec ff_dvdsub_encoder; diff --git a/libavcodec/ccaption_dec.c b/libavcodec/ccaption_dec.c index bf3563a0bc..07091f4572 100644 --- a/libavcodec/ccaption_dec.c +++ b/libavcodec/ccaption_dec.c @@ -341,43 +341,53 @@ static void write_char(CCaptionSubContext *ctx, struct Screen *screen, char ch) } /** - * This function after validating parity bit, also remove it from data pair. - * The first byte doesn't pass parity, we replace it with a solid blank - * and process the pair. - * If the second byte doesn't pass parity, it returns INVALIDDATA - * user can ignore the whole pair and pass the other pair. + * This function accepts a byte pair [EIA 608 first byte, EIA 608 second byte] + * checks both for parity and strips parity on success. + * If the first byte doesn't pass parity, replace it with a solid blank + * and process the pair anyway. + * Returns failure for parity failure or "no data" (padding bytes). + */ +static int validate_eia_608_byte_pair(uint8_t *cc_data_pair) { + if (!av_parity(cc_data_pair[1])) { + return AVERROR_INVALIDDATA; + } + if (!av_parity(cc_data_pair[0])) { + cc_data_pair[0]=0x7F; // solid blank + } + if ((cc_data_pair[0] & 0x7F) == 0 && (cc_data_pair[1] & 0x7F) == 0) { + return AVERROR_INVALIDDATA; // padding bytes + } + /* remove parity bit */ + cc_data_pair[0] &= 0x7F; + cc_data_pair[1] &= 0x7F; + return 0; +} + +/** + * This function accepts "cc_data_pair" = [708 header byte, EIA 608 first byte, EIA 608 second byte] + * This function after validating parity bits, also removes parity bits them from 608 data pair. */ static int validate_cc_data_pair(uint8_t *cc_data_pair) { + int ret; uint8_t cc_valid = (*cc_data_pair & 4) >>2; uint8_t cc_type = *cc_data_pair & 3; if (!cc_valid) return AVERROR_INVALIDDATA; - // if EIA-608 data then verify parity. - if (cc_type==0 || cc_type==1) { - if (!av_parity(cc_data_pair[2])) { - return AVERROR_INVALIDDATA; - } - if (!av_parity(cc_data_pair[1])) { - cc_data_pair[1]=0x7F; - } - } - - //Skip non-data - if ((cc_data_pair[0] == 0xFA || cc_data_pair[0] == 0xFC || cc_data_pair[0] == 0xFD) - && (cc_data_pair[1] & 0x7F) == 0 && (cc_data_pair[2] & 0x7F) == 0) - return AVERROR_PATCHWELCOME; - - //skip 708 data + // skip 708 data, we only support "608 over 708" not native 708 if (cc_type == 3 || cc_type == 2) + { return AVERROR_PATCHWELCOME; + } - /* remove parity bit */ - cc_data_pair[1] &= 0x7F; - cc_data_pair[2] &= 0x7F; - + // Must be EIA-608 data, verify parity. + if (cc_type==0 || cc_type==1) { + if (ret = validate_eia_608_byte_pair(cc_data_pair + 1)) { + return ret; + } + } return 0; } @@ -756,6 +766,8 @@ static int decode(AVCodecContext *avctx, void *data, int *got_sub, AVPacket *avp int len = avpkt->size; int ret = 0; int i; + int stride; + int raw_608 = avctx->codec_id == AV_CODEC_ID_EIA_608_RAW_BYTE_PAIRS; av_fast_padded_malloc(&ctx->pktbuf, &ctx->pktbuf_size, len); if (!ctx->pktbuf) { @@ -764,16 +776,27 @@ static int decode(AVCodecContext *avctx, void *data, int *got_sub, AVPacket *avp } memcpy(ctx->pktbuf, avpkt->data, len); bptr = ctx->pktbuf; - - for (i = 0; i < len; i += 3) { - uint8_t cc_type = *(bptr + i) & 3; - if (validate_cc_data_pair(bptr + i)) - continue; - /* ignoring data field 1 */ - if(cc_type == 1) - continue; - else - process_cc608(ctx, start_time, *(bptr + i + 1) & 0x7f, *(bptr + i + 2) & 0x7f); + if (raw_608) { + stride = 2; // expect 2 byte "per packet" + } + for (i = 0; i < len; i += stride) { + if (raw_608) { + if (validate_eia_608_byte_pair(bptr)) { + continue; + } + process_cc608(ctx, start_time, *(bptr + i), *(bptr + i + 1)); + } else { + // look for 608 over 708 bytes + uint8_t cc_type = *(bptr + i) & 3; + if (validate_cc_data_pair(bptr + i)) + continue; + /* ignore NTSC_CC_FIELD_2 (cc_type 1) for now */ + if (cc_type == 1) + continue; + else { + process_cc608(ctx, start_time, *(bptr + i + 1), *(bptr + i + 2)); + } + } if (!ctx->buffer_changed) continue; @@ -781,7 +804,7 @@ static int decode(AVCodecContext *avctx, void *data, int *got_sub, AVPacket *avp if (*ctx->buffer.str || ctx->real_time) { - ff_dlog(ctx, "cdp writing data (%s)\n",ctx->buffer.str); + ff_dlog(ctx, "writing data (%s)\n",ctx->buffer.str); ret = ff_ass_add_rect(sub, ctx->buffer.str, ctx->readorder++, 0, NULL, NULL); if (ret < 0) return ret; @@ -829,9 +852,16 @@ static const AVClass ccaption_dec_class = { .version = LIBAVUTIL_VERSION_INT, }; +static const AVClass ccaption_raw_608_dec_class = { + .class_name = "Closed caption Decoder Raw 608", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVCodec ff_ccaption_decoder = { .name = "cc_dec", - .long_name = NULL_IF_CONFIG_SMALL("Closed Caption (EIA-608 / CEA-708)"), + .long_name = NULL_IF_CONFIG_SMALL("Closed Caption (EIA-608 over CEA-708)"), .type = AVMEDIA_TYPE_SUBTITLE, .id = AV_CODEC_ID_EIA_608, .priv_data_size = sizeof(CCaptionSubContext), @@ -841,3 +871,16 @@ AVCodec ff_ccaption_decoder = { .decode = decode, .priv_class = &ccaption_dec_class, }; + +AVCodec ff_ccaption_raw_608_decoder = { + .name = "cc_raw_608_dec", + .long_name = NULL_IF_CONFIG_SMALL("Closed Caption (EIA-608 raw byte pairs)"), + .type = AVMEDIA_TYPE_SUBTITLE, + .id = AV_CODEC_ID_EIA_608_RAW_BYTE_PAIRS, + .priv_data_size = sizeof(CCaptionSubContext), + .init = init_decoder, + .close = close_decoder, + .flush = flush_decoder, + .decode = decode, + .priv_class = &ccaption_raw_608_dec_class, +}; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 93433b5a27..c706a5ba08 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -3173,6 +3173,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("MicroDVD subtitle"), .props = AV_CODEC_PROP_TEXT_SUB, }, + { + .id = AV_CODEC_ID_EIA_608_RAW_BYTE_PAIRS, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "eia_608_raw_byte_pairs", + .long_name = NULL_IF_CONFIG_SMALL("EIA-608 closed captions raw byte pairs"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, { .id = AV_CODEC_ID_EIA_608, .type = AVMEDIA_TYPE_SUBTITLE, diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index e7d6e059db..805e18758b 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -513,6 +513,7 @@ enum AVCodecID { AV_CODEC_ID_MICRODVD = 0x17800, AV_CODEC_ID_EIA_608, + AV_CODEC_ID_EIA_608_RAW_BYTE_PAIRS, AV_CODEC_ID_JACOSUB, AV_CODEC_ID_SAMI, AV_CODEC_ID_REALTEXT, diff --git a/libavcodec/version.h b/libavcodec/version.h index 3de16c884c..552129e0a3 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -28,8 +28,8 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 58 -#define LIBAVCODEC_VERSION_MINOR 82 -#define LIBAVCODEC_VERSION_MICRO 100 +#define LIBAVCODEC_VERSION_MINOR 83 +#define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ -- 2.17.1