From patchwork Tue Jan 31 16:00:06 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Petri Hintukainen X-Patchwork-Id: 2380 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.89.21 with SMTP id n21csp2008211vsb; Tue, 31 Jan 2017 08:07:52 -0800 (PST) X-Received: by 10.223.148.230 with SMTP id 93mr24752468wrr.13.1485878872116; Tue, 31 Jan 2017 08:07:52 -0800 (PST) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id 196si17783869wmg.65.2017.01.31.08.07.51; Tue, 31 Jan 2017 08:07:52 -0800 (PST) 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; 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=NONE 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 6274B68A3A5; Tue, 31 Jan 2017 18:07:45 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lf0-f68.google.com (mail-lf0-f68.google.com [209.85.215.68]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 006D3689F89 for ; Tue, 31 Jan 2017 18:07:38 +0200 (EET) Received: by mail-lf0-f68.google.com with SMTP id q89so34320988lfi.1 for ; Tue, 31 Jan 2017 08:07:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:subject:from:reply-to:to:date:in-reply-to:references :mime-version; bh=TiErY5aKrJPQHTyZsYob32e+OiF7XFebl6gY3yMHEEg=; b=hPI49qGLSba1wxEI2CG5JHlv/iExeTRiWGFICkDSK5nwtcZiSLtzKTTlDBLxCQrMFZ 9a9xUI0CxQgWlinLP/MoGYPqrjBCVEyAymzosoKW7xYWGiRi5+o7PErDpPAbqkjx5Pl+ gghPkPyvakuV8aKIbXtdYoGC9uZ0k9+hJ+kV/RJUr4U0hc6A0rozyuDPl3Uklo4oLQu1 /w0cTeJeYSjyfsyIuTHoeUWglGnXGVgxwAf9T5pmmcczsijMEKtLmxCuAbwyj3i5JO8S ImAAENgn+qMou2L1dwHPBel6pEl3uao3FQ1Mwj2qpn3diwsRNPR49ll/Xu+Uq2a9cacA EFMA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:subject:from:reply-to:to:date :in-reply-to:references:mime-version; bh=TiErY5aKrJPQHTyZsYob32e+OiF7XFebl6gY3yMHEEg=; b=KCcWyLDAO97J0H8Njx6dxVrEZSDkQE4D2AbD9SbLPdVj4T6GanLyQ4MCJly99xbR7t J/AeIOP1hLLISuFKMMZHUdmg2lJ97sSv2kE1I0P+0R/1Slo3lmqSatqtcthisd9Yx/j5 QHeucx2vBt0nRXr0ZSFv063WBEn3/eiH0AH/Y3vbSRwnNm/a2mvwBPNp5O2jpqpqriIT ASt5O/ReRmSVpXusx+EcrJIFqUv18fLAzkbjo/dat9U2Lc3uvfZRk9ABBWsWtuSP5TYL NPnbaC1R9Dhzwc1r2yboTThzeInLT0nPEEcY+Tan+/jjc5B83KJQwE1CCM6DMaLuuOp6 Ralw== X-Gm-Message-State: AIkVDXIzTFydyQixcGxgf0vII8YccmhtsUrXp62Oqr8D/I4YWCvvPw3RAiVj+jGTEFkwgg== X-Received: by 10.46.1.201 with SMTP id f70mr2671655lji.21.1485878417993; Tue, 31 Jan 2017 08:00:17 -0800 (PST) Received: from ph-ux360 ([2001:2003:f37c:d600:fd4d:690:ac21:8309]) by smtp.googlemail.com with ESMTPSA id m18sm4672198lfe.45.2017.01.31.08.00.16 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 31 Jan 2017 08:00:17 -0800 (PST) Message-ID: <1485878406.3882.2.camel@gmail.com> From: Petri Hintukainen To: ffmpeg-devel@ffmpeg.org Date: Tue, 31 Jan 2017 18:00:06 +0200 In-Reply-To: <20170131142217.23731-1-onemda@gmail.com> References: <20170131142217.23731-1-onemda@gmail.com> X-Mailer: Evolution 3.22.3-0ubuntu0.1 Mime-Version: 1.0 Subject: Re: [FFmpeg-devel] [PATCH] avcodec: add HDMV Text Subtitle decoder 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" Hello, I think I posted HDMV text subtitle decoder patch year+ ago. But I can't find it from list archives (?). I'll attach the original patch for reference / documentation of the format. There's also more complete implementation (text styles, positioning, ...) in libbluray: http://git.videolan.org/?p=libbluray.git;a=blob;f=sr c/libbluray/decoders/textst_decode.c . ti, 2017-01-31 kello 15:22 +0100, Paul B Mahol kirjoitti: > Signed-off-by: Paul B Mahol > --- >  libavcodec/Makefile        |   2 + >  libavcodec/allcodecs.c     |   2 + >  libavcodec/textst_parser.c |  49 ++++++++++++++++++++ >  libavcodec/textstdec.c     | 108 > +++++++++++++++++++++++++++++++++++++++++++++ >  libavformat/utils.c        |   1 + >  5 files changed, 162 insertions(+) >  create mode 100644 libavcodec/textst_parser.c >  create mode 100644 libavcodec/textstdec.c > > diff --git a/libavcodec/Makefile b/libavcodec/Makefile > index 43a6add..edadb0f 100644 > --- a/libavcodec/Makefile > +++ b/libavcodec/Makefile > @@ -539,6 +539,7 @@ OBJS-$(CONFIG_SVQ1_ENCODER)            += > svq1enc.o svq1.o  h263data.o  \ >  OBJS-$(CONFIG_SVQ3_DECODER)            += svq3.o svq13.o mpegutils.o > h264data.o >  OBJS-$(CONFIG_TEXT_DECODER)            += textdec.o ass.o >  OBJS-$(CONFIG_TEXT_ENCODER)            += srtenc.o ass_split.o > +OBJS-$(CONFIG_TEXTST_DECODER)          += textstdec.o ass.o >  OBJS-$(CONFIG_TAK_DECODER)             += takdec.o tak.o takdsp.o >  OBJS-$(CONFIG_TARGA_DECODER)           += targa.o >  OBJS-$(CONFIG_TARGA_ENCODER)           += targaenc.o rle.o > @@ -945,6 +946,7 @@ OBJS-$(CONFIG_RV30_PARSER)             += > rv34_parser.o >  OBJS-$(CONFIG_RV40_PARSER)             += rv34_parser.o >  OBJS-$(CONFIG_SIPR_PARSER)             += sipr_parser.o >  OBJS-$(CONFIG_TAK_PARSER)              += tak_parser.o tak.o > +OBJS-$(CONFIG_TEXTST_PARSER)           += textst_parser.o >  OBJS-$(CONFIG_VC1_PARSER)              += vc1_parser.o vc1.o > vc1data.o  \ >                                            simple_idct.o wmv2data.o >  OBJS-$(CONFIG_VP3_PARSER)              += vp3_parser.o > diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c > index f92b2b7..9a90533 100644 > --- a/libavcodec/allcodecs.c > +++ b/libavcodec/allcodecs.c > @@ -581,6 +581,7 @@ void avcodec_register_all(void) >      REGISTER_DECODER(SUBVIEWER,         subviewer); >      REGISTER_DECODER(SUBVIEWER1,        subviewer1); >      REGISTER_ENCDEC (TEXT,              text); > +    REGISTER_DECODER(TEXTST,            textst); >      REGISTER_DECODER(VPLAYER,           vplayer); >      REGISTER_ENCDEC (WEBVTT,            webvtt); >      REGISTER_ENCDEC (XSUB,              xsub); > @@ -704,6 +705,7 @@ void avcodec_register_all(void) >      REGISTER_PARSER(RV40,               rv40); >      REGISTER_PARSER(SIPR,               sipr); >      REGISTER_PARSER(TAK,                tak); > +    REGISTER_PARSER(TEXTST,             textst); >      REGISTER_PARSER(VC1,                vc1); >      REGISTER_PARSER(VORBIS,             vorbis); >      REGISTER_PARSER(VP3,                vp3); > diff --git a/libavcodec/textst_parser.c b/libavcodec/textst_parser.c > new file mode 100644 > index 0000000..5079a96 > --- /dev/null > +++ b/libavcodec/textst_parser.c > @@ -0,0 +1,49 @@ > +/* > + * 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 > + */ > + > +/** > + * @file > + * HDMV TextST subtitle parser > + */ > + > +#include "libavutil/intreadwrite.h" > +#include "parser.h" > + > +static int textst_parse(AVCodecParserContext *s1, AVCodecContext > *avctx, > +                        const uint8_t **poutbuf, int *poutbuf_size, > +                        const uint8_t *buf, int buf_size) > +{ > +    if (buf_size > 13) { > +        int64_t end; > + > +        s1->pts = ((int64_t)(buf[3] & 1) << 32) | AV_RB32(&buf[4]); I think there's no pts in dialog style segment. I don't know if style segment is present when subtitles are muxed to matroska, but it is present in the original .m2ts file. > +        end = ((int64_t)(buf[8] & 1) << 32) | AV_RB32(&buf[9]); > +        s1->duration = (end - s1->pts); > +    } > + > +    /* always return the full packet. this parser isn't doing any > splitting or > +       combining, only packet analysis */ > +    *poutbuf      = buf; > +    *poutbuf_size = buf_size; > +    return buf_size; > +} > + > +AVCodecParser ff_textst_parser = { > +    .codec_ids      = { AV_CODEC_ID_HDMV_TEXT_SUBTITLE }, > +    .parser_parse   = textst_parse, > +}; > diff --git a/libavcodec/textstdec.c b/libavcodec/textstdec.c > new file mode 100644 > index 0000000..a259d2d > --- /dev/null > +++ b/libavcodec/textstdec.c > @@ -0,0 +1,108 @@ > +/* > + * HDMV TextST decoder > + * Copyright (c) 2017 Paul B Mahol > + * > + * 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 > + > +#include "libavutil/bprint.h" > +#include "avcodec.h" > +#include "ass.h" > +#include "bytestream.h" > + > +static int textst_event_to_ass(AVBPrint *buf, const char *p, int > size) > +{ > +    GetByteContext gb; > +    int i, count; > + > +    bytestream2_init(&gb, p, size); > +    count = bytestream2_get_byte(&gb); > + > +    if (count > 127) { > +        int size = bytestream2_get_be16(&gb); > +        bytestream2_skip(&gb, size); > +    } > +    if (bytestream2_get_bytes_left(&gb) > 2) { > +        count = bytestream2_get_byte(&gb); > + > +        for (i = 0; i < count; i++) { > +            int dlength; > + > +            bytestream2_skip(&gb, 2); > +            dlength = bytestream2_get_be16(&gb); > + > +            while (dlength > 3) { > +                int type, length; > +                int code = bytestream2_get_byte(&gb); > + > +                dlength--; > +                if (code != 0x1b) > +                    continue; > + > +                type   = bytestream2_get_byte(&gb); > +                length = bytestream2_get_byte(&gb); > +                dlength -= (2 + length); > + > +                switch (type) { > +                case 1: > +                    av_bprint_append_data(buf, gb.buffer, > FFMIN(length, bytestream2_get_bytes_left(&gb))); > +                    bytestream2_skip(&gb, length); > +                    break; > +                case 0x0a: > +                    av_bprintf(buf, "\n"); > +                default: > +                    bytestream2_skip(&gb, length); > +                    break; > +                } > +            } > +        } > +    } > + > +    return 0; > +} > + > +static int textst_decode_frame(AVCodecContext *avctx, > +                               void *data, int *got_sub_ptr, > AVPacket *avpkt) > +{ > +    FFASSDecoderContext *s = avctx->priv_data; > +    const char *ptr = avpkt->data; > +    AVSubtitle *sub = data; > +    AVBPrint buf; > +    int ret = 0; > + > +    av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); > +    if (ptr && avpkt->size > 13 && !textst_event_to_ass(&buf, ptr + > 13, avpkt->size - 13)) I'd check segment type here (buf[0] == 0x82). > +        ret = ff_ass_add_rect(sub, buf.str, s->readorder++, 0, NULL, > NULL); > +    av_bprint_finalize(&buf, NULL); > +    if (ret < 0) > +        return ret; > +    *got_sub_ptr = sub->num_rects > 0; > +    return avpkt->size; > +} > + > +AVCodec ff_textst_decoder = { > +    .name           = "textst", > +    .long_name      = NULL_IF_CONFIG_SMALL("HDMV TextST subtitle"), > +    .type           = AVMEDIA_TYPE_SUBTITLE, > +    .id             = AV_CODEC_ID_HDMV_TEXT_SUBTITLE, > +    .decode         = textst_decode_frame, > +    .init           = ff_ass_subtitle_header_default, > +    .flush          = ff_ass_decoder_flush, > +    .priv_data_size = sizeof(FFASSDecoderContext), > +}; > diff --git a/libavformat/utils.c b/libavformat/utils.c > index 0711310..74f808f 100644 > --- a/libavformat/utils.c > +++ b/libavformat/utils.c > @@ -1445,6 +1445,7 @@ static int parse_packet(AVFormatContext *s, > AVPacket *pkt, int stream_index) >   >          out_pkt.stream_index = st->index; >          out_pkt.pts          = st->parser->pts; > +        out_pkt.duration     = st->parser->duration; >          out_pkt.dts          = st->parser->dts; >          out_pkt.pos          = st->parser->pos; > Simple decoder that decodes only the dialog texts and ignores the formatting. --- libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/hdmv_textstdec.c | 240 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+) create mode 100644 libavcodec/hdmv_textstdec.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 407c6c3..6d4b7dd 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -297,6 +297,7 @@ OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec_h2645.o OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o OBJS-$(CONFIG_HAP_DECODER) += hapdec.o hap.o OBJS-$(CONFIG_HAP_ENCODER) += hapenc.o hap.o +OBJS-$(CONFIG_HDMV_TEXTST_DECODER) += hdmv_textstdec.o ass.o OBJS-$(CONFIG_HEVC_DECODER) += hevc.o hevc_mvs.o hevc_ps.o hevc_sei.o \ hevc_cabac.o hevc_refs.o hevcpred.o \ hevcdsp.o hevc_filter.o hevc_parse.o hevc_data.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index dbf3927..188e224 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -526,6 +526,7 @@ void avcodec_register_all(void) REGISTER_DECODER(CCAPTION, ccaption); REGISTER_ENCDEC (DVBSUB, dvbsub); REGISTER_ENCDEC (DVDSUB, dvdsub); + REGISTER_DECODER(HDMV_TEXTST, hdmv_textst); REGISTER_DECODER(JACOSUB, jacosub); REGISTER_DECODER(MICRODVD, microdvd); REGISTER_ENCDEC (MOVTEXT, movtext); diff --git a/libavcodec/hdmv_textstdec.c b/libavcodec/hdmv_textstdec.c new file mode 100644 index 0000000..d7f99c5 --- /dev/null +++ b/libavcodec/hdmv_textstdec.c @@ -0,0 +1,240 @@ +/* + * BluRay text subtitle decoder + * Copyright (c) 2014 Petri Hintukainen + * + * 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/bprint.h" +#include "libavutil/intreadwrite.h" +#include "avcodec.h" +#include "ass.h" +#include "bytestream.h" + +enum { + DIALOG_STYLE_SEGMENT = 0x81, + DIALOG_PRESENTATION_SEGMENT = 0x82, +}; + +enum { + BD_TEXTST_DATA_ESCAPE = 0x1b, + BD_TEXTST_DATA_STRING = 1, + BD_TEXTST_DATA_FONT_ID = 2, + BD_TEXTST_DATA_FONT_STYLE = 3, + BD_TEXTST_DATA_FONT_SIZE = 4, + BD_TEXTST_DATA_FONT_COLOR = 5, + BD_TEXTST_DATA_NEWLINE = 0x0a, + BD_TEXTST_DATA_RESET_STYLE = 0x0b, +}; + + +static void decode_region_data(AVCodecContext *avctx, GetByteContext *gb, AVBPrint *sub) +{ + + while (bytestream2_get_bytes_left(gb) > 2) { + + unsigned int code, type, length; + + /* parse header */ + + code = bytestream2_get_byte(gb); + if (code != BD_TEXTST_DATA_ESCAPE) { + continue; + } + type = bytestream2_get_byte(gb); + length = bytestream2_get_byte(gb); + + /* parse content */ + + if (length > bytestream2_get_bytes_left(gb)) { + av_log(avctx, AV_LOG_WARNING, "decode_dialog_region(): unexpected end of data\n"); + return; + } + + switch (type) { + case BD_TEXTST_DATA_STRING: + av_bprint_append_data(sub, gb->buffer, length); + break; + case BD_TEXTST_DATA_NEWLINE: + av_bprint_append_data(sub, "\\N", 2); + break; + default: + break; + } + + bytestream2_skip(gb, length); + } +} + +static int decode_region(AVCodecContext *avctx, GetByteContext *gb, AVBPrint *sub, int *forced_on_flag) +{ + GetByteContext gb_region; + int flags, data_length; + + flags = bytestream2_get_byte(gb); + /*continous_present_flag = !!(flags & 0x80);*/ + *forced_on_flag = !!(flags & 0x40); + /*region_style_id_ref=*/ bytestream2_get_byte(gb); + data_length = bytestream2_get_be16(gb); + + if (data_length > bytestream2_get_bytes_left(gb)) { + av_log(avctx, AV_LOG_WARNING, "decode_dialog_region(): unexpected end of data\n"); + return -1; + } + + bytestream2_init(&gb_region, gb->buffer, data_length); + decode_region_data(avctx, &gb_region, sub); + + bytestream2_skip(gb, data_length); + + av_bprintf(sub, "\r\n"); + + return 1; +} + +static int64_t decode_pts(GetByteContext *gb) +{ + return (((uint64_t)bytestream2_get_byte(gb) & 1) << 32) | bytestream2_get_be32(gb); +} + +static int decode_palette(AVCodecContext *avctx, GetByteContext *gb) +{ + unsigned int length; + + length = bytestream2_get_be16(gb); + + if (length > bytestream2_get_bytes_left(gb)) { + av_log(avctx, AV_LOG_WARNING, "decode_palette(): unexpected end of data\n"); + return -1; + } + + /* skip palette update */ + av_log(avctx, AV_LOG_WARNING, "ignoring palette update\n"); + bytestream2_skip(gb, length); + + return 1; +} + +static void decode_presentation_segment(AVCodecContext *avctx, GetByteContext *gb, AVSubtitle *sub) +{ + unsigned ii, palette_update_flag, region_count; + int64_t start_pts, end_pts; + int64_t ts_start, ts_end; + + start_pts = decode_pts(gb); + end_pts = decode_pts(gb); + sub->pts = start_pts; + + ts_start = av_rescale_q(start_pts, + avctx->time_base, + (AVRational){1,100}); + ts_end = av_rescale_q(end_pts, + avctx->time_base, + (AVRational){1,100}); + + palette_update_flag = bytestream2_get_byte(gb) >> 7; + if (palette_update_flag) { + if (decode_palette(avctx, gb) < 0) { + return; + } + } + + region_count = bytestream2_get_byte(gb); + if (region_count > 2) { + av_log(avctx, AV_LOG_WARNING, "too many regions (%d)\n", region_count); + return; + } + + for (ii = 0; ii < region_count; ii++) { + AVBPrint buffer; + char *dec_sub; + int forced_on_flag; + + av_bprint_init(&buffer, 1024, 1024); + + if (decode_region(avctx, gb, &buffer, &forced_on_flag) < 0) { + av_bprint_finalize(&buffer, NULL); + return; + } + + av_bprint_finalize(&buffer, &dec_sub); + + ff_ass_add_rect(sub, dec_sub, ts_start, ts_end - ts_start, 0); + av_free(dec_sub); + + if (forced_on_flag && sub->num_rects > 0) { + sub->rects[sub->num_rects - 1]->flags |= AV_SUBTITLE_FLAG_FORCED; + } + } + + if (bytestream2_get_bytes_left(gb)) { + av_log(avctx, AV_LOG_WARNING, "unknown data after dialog segment (%d bytes)\n", bytestream2_get_bytes_left(gb)); + } +} + +static int hdmv_decode_frame(AVCodecContext *avctx, + void *data, int *got_sub_ptr, AVPacket *avpkt) +{ + AVSubtitle *sub = data; + int segment_type, segment_size; + GetByteContext gb; + + if (avpkt->size < 3) { + return avpkt->size; + } + + bytestream2_init(&gb, avpkt->data, avpkt->size); + + segment_type = bytestream2_get_byte(&gb); + segment_size = bytestream2_get_be16(&gb); + + if (avpkt->size < segment_size + 3) { + av_log(avctx, AV_LOG_WARNING, "segment 0x%02x size mismatch: segment %d bytes, packet %d bytes\n", + segment_type, segment_size, avpkt->size); + return avpkt->size; + } + + switch (segment_type) { + case DIALOG_STYLE_SEGMENT: + break; + + case DIALOG_PRESENTATION_SEGMENT: + decode_presentation_segment(avctx, &gb, sub); + break; + default: + av_log(avctx, AV_LOG_WARNING, "unknown segment type 0x%02x\n", segment_type); + break; + } + + *got_sub_ptr = (sub->num_rects > 0); + + return avpkt->size; +} + +static int init_codec(AVCodecContext *avctx) +{ + return ff_ass_subtitle_header_default(avctx); +} + +AVCodec ff_hdmv_textst_decoder = { + .name = "hdmv_textst", + .long_name = NULL_IF_CONFIG_SMALL("HDMV Text subtitle"), + .type = AVMEDIA_TYPE_SUBTITLE, + .id = AV_CODEC_ID_HDMV_TEXT_SUBTITLE, + .init = init_codec, + .decode = hdmv_decode_frame, +};