From: Marth64 <marth64@proxyid.net> To: ffmpeg-devel@ffmpeg.org Cc: Marth64 <marth64@proxyid.net> Subject: [FFmpeg-devel] [PATCH v5 1/4] avformat/rcwtdec: add RCWT Closed Captions demuxer Date: Tue, 19 Mar 2024 12:39:10 -0500 Message-ID: <20240319173913.2754690-1-marth64@proxyid.net> (raw) In-Reply-To: <CA+28BfACxLCHY=kmiQtLA58y=BwJ7xe7Z8GDGZq60M0vz5Scdg@mail.gmail.com> Signed-off-by: Marth64 <marth64@proxyid.net> --- Changelog | 2 +- doc/demuxers.texi | 29 ++++++++ libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/rcwtdec.c | 148 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 libavformat/rcwtdec.c diff --git a/Changelog b/Changelog index e3ca52430c..be871f75cd 100644 --- a/Changelog +++ b/Changelog @@ -19,7 +19,7 @@ version <next>: - lavu/eval: introduce randomi() function in expressions - VVC decoder - fsync filter -- Raw Captions with Time (RCWT) closed caption muxer +- Raw Captions with Time (RCWT) closed caption muxer and demuxer - ffmpeg CLI -bsf option may now be used for input as well as output - ffmpeg CLI options may now be used as -/opt <path>, which is equivalent to -opt <contents of file <path>> diff --git a/doc/demuxers.texi b/doc/demuxers.texi index b70f3a38d7..26d4ba18a1 100644 --- a/doc/demuxers.texi +++ b/doc/demuxers.texi @@ -1038,6 +1038,35 @@ the command: ffplay -f rawvideo -pixel_format rgb24 -video_size 320x240 -framerate 10 input.raw @end example +@anchor{rcwtdec} +@section rcwt + +RCWT (Raw Captions With Time) is a format native to ccextractor, a commonly +used open source tool for processing 608/708 Closed Captions (CC) sources. +It can be used to archive the original, raw CC bitstream and to produce +a source file for later CC processing or conversion. This demuxer can process +RCWT sources created by ccextractor or FFmpeg. For more information on the format, +see @ref{rcwtenc,,,ffmpeg-formats}. + +This demuxer implements the specification as of March 2024, which has +been stable and unchanged since April 2014. + +@subsection Examples + +@itemize +@item +Render Closed Captions to ASSA (using FFmpeg's CC decoder): +@example +ffmpeg -i CC.rcwt.bin CC.ass +@end example + +@item +Convert an RCWT backup to SCC: +@example +ffmpeg -i CC.rcwt.bin -c:s copy CC.scc +@end example +@end itemize + @section sbg SBaGen script demuxer. diff --git a/libavformat/Makefile b/libavformat/Makefile index 94a949f555..a6de720d8c 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -493,6 +493,7 @@ OBJS-$(CONFIG_QOA_DEMUXER) += qoadec.o OBJS-$(CONFIG_R3D_DEMUXER) += r3d.o OBJS-$(CONFIG_RAWVIDEO_DEMUXER) += rawvideodec.o OBJS-$(CONFIG_RAWVIDEO_MUXER) += rawenc.o +OBJS-$(CONFIG_RCWT_DEMUXER) += rcwtdec.o subtitles.o OBJS-$(CONFIG_RCWT_MUXER) += rcwtenc.o subtitles.o OBJS-$(CONFIG_REALTEXT_DEMUXER) += realtextdec.o subtitles.o OBJS-$(CONFIG_REDSPARK_DEMUXER) += redspark.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index e15d0fa6d7..3140018f8d 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -391,6 +391,7 @@ extern const FFInputFormat ff_qoa_demuxer; extern const FFInputFormat ff_r3d_demuxer; extern const FFInputFormat ff_rawvideo_demuxer; extern const FFOutputFormat ff_rawvideo_muxer; +extern const FFInputFormat ff_rcwt_demuxer; extern const FFOutputFormat ff_rcwt_muxer; extern const FFInputFormat ff_realtext_demuxer; extern const FFInputFormat ff_redspark_demuxer; diff --git a/libavformat/rcwtdec.c b/libavformat/rcwtdec.c new file mode 100644 index 0000000000..1baa571231 --- /dev/null +++ b/libavformat/rcwtdec.c @@ -0,0 +1,148 @@ +/* + * RCWT (Raw Captions With Time) demuxer + * + * 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 + */ + +/* + * RCWT (Raw Captions With Time) is a format native to ccextractor, a commonly + * used open source tool for processing 608/708 Closed Captions (CC) sources. + * + * This demuxer implements the specification as of March 2024, which has + * been stable and unchanged since April 2014. + * + * A free specification of RCWT can be found here: + * @url{https://github.com/CCExtractor/ccextractor/blob/master/docs/BINARY_FILE_FORMAT.TXT} + */ + +#include "avformat.h" +#include "demux.h" +#include "internal.h" +#include "subtitles.h" +#include "libavutil/intreadwrite.h" + +#define RCWT_CLUSTER_MAX_BLOCKS 65535 +#define RCWT_BLOCK_SIZE 3 +#define RCWT_HEADER_SIZE 11 + +typedef struct RCWTContext { + FFDemuxSubtitlesQueue q; +} RCWTContext; + +static int rcwt_read_header(AVFormatContext *avf) +{ + RCWTContext *rcwt = avf->priv_data; + + AVPacket *sub = NULL; + AVStream *st; + uint8_t header[RCWT_HEADER_SIZE] = {0}; + int nb_bytes = 0; + + /* validate the header */ + nb_bytes = avio_read(avf->pb, header, RCWT_HEADER_SIZE); + if (nb_bytes != RCWT_HEADER_SIZE) { + av_log(avf, AV_LOG_ERROR, "Header does not have the expected size " + "(expected=%d actual=%d)\n", + RCWT_HEADER_SIZE, nb_bytes); + return AVERROR_INVALIDDATA; + } + + if (AV_RB16(header + 6) != 0x0001) { + av_log(avf, AV_LOG_ERROR, "RCWT format version is not compatible " + "(only version 0.001 is known)\n"); + return AVERROR_INVALIDDATA; + } + + av_log(avf, AV_LOG_DEBUG, "RCWT writer application: %02X version: %02x\n", + header[3], header[5]); + + /* setup AVStream */ + st = avformat_new_stream(avf, NULL); + if (!st) + return AVERROR(ENOMEM); + + st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; + st->codecpar->codec_id = AV_CODEC_ID_EIA_608; + + avpriv_set_pts_info(st, 64, 1, 1000); + + /* demux */ + while (!avio_feof(avf->pb)) { + int64_t cluster_pts = AV_NOPTS_VALUE; + int cluster_nb_blocks = 0; + int cluster_size = 0; + uint8_t *cluster_buf; + + cluster_pts = avio_rl64(avf->pb); + cluster_nb_blocks = avio_rl16(avf->pb); + if (cluster_nb_blocks == 0) + continue; + + cluster_size = cluster_nb_blocks * RCWT_BLOCK_SIZE; + cluster_buf = av_malloc(cluster_size); + if (!cluster_buf) + return AVERROR(ENOMEM); + + nb_bytes = avio_read(avf->pb, cluster_buf, cluster_size); + if (nb_bytes < 0) + return nb_bytes; + + if (nb_bytes != cluster_size) { + av_freep(&cluster_buf); + av_log(avf, AV_LOG_ERROR, "Cluster does not have the expected size " + "(expected=%d actual=%d pos=%ld)\n", + cluster_size, nb_bytes, avio_tell(avf->pb)); + return AVERROR_INVALIDDATA; + } + + sub = ff_subtitles_queue_insert(&rcwt->q, cluster_buf, cluster_size, 0); + if (!sub) { + av_freep(&cluster_buf); + return AVERROR(ENOMEM); + } + + sub->pos = avio_tell(avf->pb); + sub->pts = cluster_pts; + + av_freep(&cluster_buf); + cluster_buf = NULL; + } + + ff_subtitles_queue_finalize(avf, &rcwt->q); + + return 0; +} + +static int rcwt_probe(const AVProbeData *p) +{ + return p->buf_size > RCWT_HEADER_SIZE && + AV_RB16(p->buf) == 0xCCCC && AV_RB8(p->buf + 2) == 0xED ? 50 : 0; +} + +const FFInputFormat ff_rcwt_demuxer = { + .p.name = "rcwt", + .p.long_name = NULL_IF_CONFIG_SMALL("RCWT (Raw Captions With Time)"), + .p.extensions = "bin", + .p.flags = AVFMT_TS_DISCONT, + .priv_data_size = sizeof(RCWTContext), + .flags_internal = FF_FMT_INIT_CLEANUP, + .read_probe = rcwt_probe, + .read_header = rcwt_read_header, + .read_packet = ff_subtitles_read_packet, + .read_seek2 = ff_subtitles_read_seek, + .read_close = ff_subtitles_read_close +}; -- 2.34.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next prev parent reply other threads:[~2024-03-19 17:39 UTC|newest] Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top 2024-03-12 5:59 [FFmpeg-devel] [PATCH v3 0/6] Closed Captions improvements (phase 1) Marth64 2024-03-12 6:00 ` [FFmpeg-devel] [PATCH v3 1/6] avcodec/mpeg12dec: extract only one type of CC substream Marth64 2024-03-12 11:00 ` Stefano Sabatini 2024-03-12 11:52 ` Andreas Rheinhardt 2024-03-28 9:29 ` Anton Khirnov 2024-03-28 15:41 ` Marth64 2024-03-12 6:00 ` [FFmpeg-devel] [PATCH v3 2/6] avcodec/ccaption_dec: don't print multiple \an and \pos tags Marth64 2024-03-12 13:49 ` Stefano Sabatini 2024-03-12 6:00 ` [FFmpeg-devel] [PATCH v3 3/6] avcodec/ccaption_dec: ignore leading non-breaking spaces Marth64 2024-03-12 13:50 ` Stefano Sabatini 2024-03-17 4:27 ` Marth64 2024-03-12 6:00 ` [FFmpeg-devel] [PATCH v3 4/6] avcodec/rcwtenc: canonize name and refresh documentation Marth64 2024-03-12 13:52 ` Stefano Sabatini 2024-03-12 6:00 ` [FFmpeg-devel] [PATCH v3 5/6] avformat/rcwtdec: add RCWT Closed Captions demuxer Marth64 2024-03-12 11:44 ` Andreas Rheinhardt 2024-03-12 14:12 ` Marth64 2024-03-17 4:29 ` [FFmpeg-devel] [PATCH v4] " Marth64 2024-03-18 20:12 ` Marth64 2024-03-19 14:35 ` Stefano Sabatini 2024-03-19 15:55 ` Marth64 2024-03-19 17:39 ` Marth64 [this message] 2024-03-19 17:39 ` [FFmpeg-devel] [PATCH v5 2/4] avformat/rcwtenc: remove repeated documentation Marth64 2024-03-19 17:39 ` [FFmpeg-devel] [PATCH v5 3/4] doc/muxers: refresh and simplify RCWT muxer documentation Marth64 2024-03-19 17:39 ` [FFmpeg-devel] [PATCH v5 4/4] doc/indevs: update CC extraction example to use RCWT muxer Marth64 2024-03-20 14:13 ` Stefano Sabatini 2024-03-19 21:41 ` [FFmpeg-devel] [PATCH v5 1/4] avformat/rcwtdec: add RCWT Closed Captions demuxer Michael Niedermayer 2024-03-19 22:07 ` Marth64 2024-03-20 14:11 ` Stefano Sabatini 2024-03-12 6:00 ` [FFmpeg-devel] [PATCH v3 6/6] avformat/sccdec: remove unused bprint.h include Marth64 2024-03-12 13:53 ` Stefano Sabatini
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20240319173913.2754690-1-marth64@proxyid.net \ --to=marth64@proxyid.net \ --cc=ffmpeg-devel@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git