FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/rcwtdec.c
Date: 2024-11-20 23:03:26
Exec Total Coverage
Lines: 4 37 10.8%
Functions: 1 2 50.0%
Branches: 2 22 9.1%

Line Branch Exec Source
1 /*
2 * RCWT (Raw Captions With Time) demuxer
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /*
22 * RCWT (Raw Captions With Time) is a format native to ccextractor, a commonly
23 * used open source tool for processing 608/708 Closed Captions (CC) sources.
24 *
25 * This demuxer implements the specification as of March 2024, which has
26 * been stable and unchanged since April 2014.
27 *
28 * A free specification of RCWT can be found here:
29 * @url{https://github.com/CCExtractor/ccextractor/blob/master/docs/BINARY_FILE_FORMAT.TXT}
30 */
31
32 #include "avformat.h"
33 #include "demux.h"
34 #include "internal.h"
35 #include "subtitles.h"
36 #include "libavutil/intreadwrite.h"
37
38 #define RCWT_HEADER_SIZE 11
39
40 typedef struct RCWTContext {
41 FFDemuxSubtitlesQueue q;
42 } RCWTContext;
43
44 static int rcwt_read_header(AVFormatContext *avf)
45 {
46 RCWTContext *rcwt = avf->priv_data;
47
48 AVStream *st;
49 uint8_t header[RCWT_HEADER_SIZE];
50 int ret;
51
52 /* read header */
53 ret = ffio_read_size(avf->pb, header, RCWT_HEADER_SIZE);
54 if (ret < 0)
55 return ret;
56
57 if (AV_RB16(header + 6) != 0x0001) {
58 av_log(avf, AV_LOG_ERROR, "RCWT format version is not compatible "
59 "(only version 0.001 is known)\n");
60 return AVERROR_INVALIDDATA;
61 }
62
63 av_log(avf, AV_LOG_DEBUG, "RCWT writer application: %02X version: %02x\n",
64 header[3], header[5]);
65
66 /* setup stream */
67 st = avformat_new_stream(avf, NULL);
68 if (!st)
69 return AVERROR(ENOMEM);
70
71 st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE;
72 st->codecpar->codec_id = AV_CODEC_ID_EIA_608;
73
74 avpriv_set_pts_info(st, 64, 1, 1000);
75
76 /* demux */
77 while (!avio_feof(avf->pb)) {
78 AVPacket *sub;
79 int64_t cluster_pos = avio_tell(avf->pb);
80 int64_t cluster_pts = avio_rl64(avf->pb);
81 int cluster_nb_blocks = avio_rl16(avf->pb);
82
83 if (cluster_nb_blocks == 0)
84 continue;
85
86 sub = ff_subtitles_queue_insert(&rcwt->q, NULL, 0, 0);
87 if (!sub)
88 return AVERROR(ENOMEM);
89
90 ret = av_get_packet(avf->pb, sub, cluster_nb_blocks * 3);
91 if (ret < 0)
92 return ret;
93
94 sub->pos = cluster_pos;
95 sub->pts = cluster_pts;
96 }
97
98 ff_subtitles_queue_finalize(avf, &rcwt->q);
99
100 return 0;
101 }
102
103 7186 static int rcwt_probe(const AVProbeData *p)
104 {
105 14372 return p->buf_size > RCWT_HEADER_SIZE &&
106
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7186 times.
7186 AV_RB16(p->buf) == 0xCCCC &&
107 AV_RB8(p->buf + 2) == 0xED &&
108
1/4
✓ Branch 0 taken 7186 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
14372 AV_RB16(p->buf + 6) == 0x0001 ? 50 : 0;
109 }
110
111 const FFInputFormat ff_rcwt_demuxer = {
112 .p.name = "rcwt",
113 .p.long_name = NULL_IF_CONFIG_SMALL("RCWT (Raw Captions With Time)"),
114 .p.flags = AVFMT_TS_DISCONT,
115 .priv_data_size = sizeof(RCWTContext),
116 .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP,
117 .read_probe = rcwt_probe,
118 .read_header = rcwt_read_header,
119 .read_packet = ff_subtitles_read_packet,
120 .read_seek2 = ff_subtitles_read_seek,
121 .read_close = ff_subtitles_read_close
122 };
123