3 * Copyright (c) 2017 Paul B Mahol
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "subtitles.h"
25 #include "libavutil/avstring.h"
26 #include "libavutil/bprint.h"
27 #include "libavutil/intreadwrite.h"
29 typedef struct SCCContext
{
30 FFDemuxSubtitlesQueue q
;
33 static int scc_probe(const AVProbeData
*p
)
38 ff_text_init_buf(&tr
, p
->buf
, p
->buf_size
);
40 while (ff_text_peek_r8(&tr
) == '\r' || ff_text_peek_r8(&tr
) == '\n')
43 ff_text_read(&tr
, buf
, sizeof(buf
));
45 if (!memcmp(buf
, "Scenarist_SCC V1.0", 18))
46 return AVPROBE_SCORE_MAX
;
51 static int convert(uint8_t x
)
62 static int scc_read_header(AVFormatContext
*s
)
64 SCCContext
*scc
= s
->priv_data
;
65 AVStream
*st
= avformat_new_stream(s
, NULL
);
66 char line
[4096], line2
[4096];
67 int64_t ts_start
, ts_end
;
68 int count
= 0, ret
= 0;
73 ff_text_init_avio(s
, &tr
, s
->pb
);
76 return AVERROR(ENOMEM
);
77 avpriv_set_pts_info(st
, 64, 1, 1000);
78 st
->codecpar
->codec_type
= AVMEDIA_TYPE_SUBTITLE
;
79 st
->codecpar
->codec_id
= AV_CODEC_ID_EIA_608
;
81 while (!ff_text_eof(&tr
)) {
82 int64_t current_pos
, next_pos
;
83 char *saveptr
= NULL
, *lline
;
84 int hh1
, mm1
, ss1
, fs1
, i
;
85 int hh2
, mm2
, ss2
, fs2
;
89 current_pos
= ff_text_pos(&tr
);
90 while (!ff_text_eof(&tr
)) {
91 len
= ff_subtitles_read_line(&tr
, line
, sizeof(line
));
97 if (!strncmp(line
, "Scenarist_SCC V1.0", 18))
99 if (av_sscanf(line
, "%d:%d:%d%*[:;]%d", &hh1
, &mm1
, &ss1
, &fs1
) != 4)
102 ts_start
= (hh1
* 3600LL + mm1
* 60LL + ss1
) * 1000LL + fs1
* 33;
104 next_pos
= ff_text_pos(&tr
);
105 while (!ff_text_eof(&tr
)) {
106 len2
= ff_subtitles_read_line(&tr
, line2
, sizeof(line2
));
110 if (av_sscanf(line2
, "%d:%d:%d%*[:;]%d", &hh2
, &mm2
, &ss2
, &fs2
) != 4)
113 ts_end
= (hh2
* 3600LL + mm2
* 60LL + ss2
) * 1000LL + fs2
* 33;
117 lline
= (char *)&line
;
120 for (i
= 0; i
< 4095; i
+= 3) {
121 char *ptr
= av_strtok(lline
, " ", &saveptr
);
127 if (av_sscanf(ptr
, "%c%c%c%c", &c1
, &c2
, &c3
, &c4
) != 4)
132 out
[i
+1] = convert(c2
) | (convert(c1
) << 4);
133 out
[i
+2] = convert(c4
) | (convert(c3
) << 4);
137 sub
= ff_subtitles_queue_insert(&scc
->q
, out
, i
, 0);
141 sub
->pos
= current_pos
;
143 sub
->duration
= ts_end
- ts_start
;
144 memmove(line
, line2
, sizeof(line
));
145 current_pos
= next_pos
;
155 ff_subtitles_queue_finalize(s
, &scc
->q
);
159 ff_subtitles_queue_clean(&scc
->q
);
160 return AVERROR(ENOMEM
);
163 static int scc_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
165 SCCContext
*scc
= s
->priv_data
;
166 return ff_subtitles_queue_read_packet(&scc
->q
, pkt
);
169 static int scc_read_seek(AVFormatContext
*s
, int stream_index
,
170 int64_t min_ts
, int64_t ts
, int64_t max_ts
, int flags
)
172 SCCContext
*scc
= s
->priv_data
;
173 return ff_subtitles_queue_seek(&scc
->q
, s
, stream_index
,
174 min_ts
, ts
, max_ts
, flags
);
177 static int scc_read_close(AVFormatContext
*s
)
179 SCCContext
*scc
= s
->priv_data
;
180 ff_subtitles_queue_clean(&scc
->q
);
184 AVInputFormat ff_scc_demuxer
= {
186 .long_name
= NULL_IF_CONFIG_SMALL("Scenarist Closed Captions"),
187 .priv_data_size
= sizeof(SCCContext
),
188 .read_probe
= scc_probe
,
189 .read_header
= scc_read_header
,
190 .read_packet
= scc_read_packet
,
191 .read_seek2
= scc_read_seek
,
192 .read_close
= scc_read_close
,