FFmpeg
Loading...
Searching...
No Matches
jacosubdec.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012 Clément Bœsch
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 * @file
23 * JACOsub subtitle demuxer
24 * @see http://unicorn.us.com/jacosub/jscripts.html
25 * @todo Support P[ALETTE] directive.
26 */
27
28#include "avformat.h"
29#include "demux.h"
30#include "internal.h"
32#include "subtitles.h"
33#include "libavcodec/jacosub.h"
34#include "libavutil/avstring.h"
35#include "libavutil/bprint.h"
37
38typedef struct {
40 int shift;
41 unsigned timeres;
43
44static int timed_line(const char *ptr)
45{
46 char c;
47 int fs, fe;
48 return (sscanf(ptr, "%*u:%*u:%*u.%*u %*u:%*u:%*u.%*u %c", &c) == 1 ||
49 (sscanf(ptr, "@%u @%u %c", &fs, &fe, &c) == 3 && fs < fe));
50}
51
52static int jacosub_probe(const AVProbeData *p)
53{
54 const char *ptr = p->buf;
55 const char *ptr_end = p->buf + p->buf_size;
56
57 if (AV_RB24(ptr) == 0xEFBBBF)
58 ptr += 3; /* skip UTF-8 BOM */
59
60 while (ptr < ptr_end) {
61 while (jss_whitespace(*ptr))
62 ptr++;
63 if (*ptr != '#' && *ptr != '\n') {
64 if (timed_line(ptr))
65 return AVPROBE_SCORE_EXTENSION + 1;
66 return 0;
67 }
68 ptr += ff_subtitles_next_line(ptr);
69 }
70 return 0;
71}
72
73static const char * const cmds[] = {
74 "CLOCKPAUSE",
75 "DIRECTIVE",
76 "FONT",
77 "HRES",
78 "INCLUDE",
79 "PALETTE",
80 "QUANTIZE",
81 "RAMP",
82 "SHIFT",
83 "TIMERES",
84};
85
86static int get_jss_cmd(char k)
87{
88 int i;
89
90 k = av_toupper(k);
91 for (i = 0; i < FF_ARRAY_ELEMS(cmds); i++)
92 if (k == cmds[i][0])
93 return i;
94 return -1;
95}
96
97static const char *read_ts(JACOsubContext *jacosub, const char *buf,
98 int64_t *start, int64_t *duration)
99{
100 int len;
101 unsigned hs, ms, ss, fs; // hours, minutes, seconds, frame start
102 unsigned he, me, se, fe; // hours, minutes, seconds, frame end
103 int ts_start, ts_end;
104 int64_t ts_start64, ts_end64;
105
106 /* timed format */
107 if (sscanf(buf, "%u:%u:%u.%u %u:%u:%u.%u %n",
108 &hs, &ms, &ss, &fs,
109 &he, &me, &se, &fe, &len) == 8) {
110 ts_start = (hs*3600 + ms*60 + ss) * jacosub->timeres + fs;
111 ts_end = (he*3600 + me*60 + se) * jacosub->timeres + fe;
112 goto shift_and_ret;
113 }
114
115 /* timestamps format */
116 if (sscanf(buf, "@%u @%u %n", &ts_start, &ts_end, &len) == 2)
117 goto shift_and_ret;
118
119 return NULL;
120
121shift_and_ret:
122 ts_start64 = (ts_start + (int64_t)jacosub->shift) * 100LL / jacosub->timeres;
123 ts_end64 = (ts_end + (int64_t)jacosub->shift) * 100LL / jacosub->timeres;
124 *start = ts_start64;
125 *duration = ts_end64 - ts_start64;
126 return buf + len;
127}
128
129static int get_shift(unsigned timeres, const char *buf)
130{
131 int sign = 1;
132 int h = 0, m = 0, s = 0, d = 0;
133 int64_t ret;
134#define SSEP "%*1[.:]"
135 int n = sscanf(buf, "%d"SSEP"%d"SSEP"%d"SSEP"%d", &h, &m, &s, &d);
136#undef SSEP
137
138 if (h == INT_MIN)
139 return 0;
140
141 if (*buf == '-' || h < 0) {
142 sign = -1;
143 h = FFABS(h);
144 }
145
146 ret = 0;
147 switch (n) {
148 case 1: h = 0; av_fallthrough; //clear all in case of a single parameter
149 case 2: s = m; m = h; h = 0; av_fallthrough; //shift into second subsecondd
150 case 3: d = s; s = m; m = h; h = 0; //shift into minute second subsecond
151 }
152
153 ret = (int64_t)h*3600 + (int64_t)m*60 + s;
154 if (FFABS(ret) > (INT64_MAX - FFABS((int64_t)d)) / timeres)
155 return 0;
156 ret = sign * (ret * timeres + d);
157
158 if ((int)ret != ret)
159 ret = 0;
160
161 return ret;
162}
163
165{
166 AVBPrint header;
167 AVIOContext *pb = s->pb;
169 JACOsubContext *jacosub = s->priv_data;
170 int shift_set = 0; // only the first shift matters
171 int merge_line = 0;
172 int i, ret;
173
175 if (!st)
176 return AVERROR(ENOMEM);
177 avpriv_set_pts_info(st, 64, 1, 100);
180
181 jacosub->timeres = 30;
182
184
185 while (!avio_feof(pb)) {
186 int cmd_len;
187 const char *p = line;
188 int64_t pos = avio_tell(pb);
189 int len = ff_get_line(pb, line, sizeof(line));
190
191 p = jss_skip_whitespace(p);
192
193 /* queue timed line */
194 if (merge_line || timed_line(p)) {
195 AVPacket *sub;
196
197 sub = ff_subtitles_queue_insert(&jacosub->q, line, len, merge_line);
198 if (!sub) {
200 return AVERROR(ENOMEM);
201 }
202 sub->pos = pos;
203 merge_line = len > 1 && !strcmp(&line[len - 2], "\\\n");
204 continue;
205 }
206
207 /* skip all non-compiler commands and focus on the command */
208 if (*p != '#')
209 continue;
210 p++;
211 i = get_jss_cmd(p[0]);
212 if (i == -1)
213 continue;
214
215 /* trim command + spaces */
216 cmd_len = strlen(cmds[i]);
217 if (av_strncasecmp(p, cmds[i], cmd_len) == 0)
218 p += cmd_len;
219 else
220 p++;
221 p = jss_skip_whitespace(p);
222
223 /* handle commands which affect the whole script */
224 switch (cmds[i][0]) {
225 case 'S': // SHIFT command affect the whole script...
226 if (!shift_set) {
227 jacosub->shift = get_shift(jacosub->timeres, p);
228 shift_set = 1;
229 }
230 av_bprintf(&header, "#S %s", p);
231 break;
232 case 'T': { // ...but must be placed after TIMERES
233 int64_t timeres = strtol(p, NULL, 10);
234 if (timeres <= 0 || timeres > UINT32_MAX) {
235 jacosub->timeres = 30;
236 } else {
237 jacosub->timeres = timeres;
238 av_bprintf(&header, "#T %s", p);
239 }
240 break;
241 }
242 }
243 }
244
245 /* general/essential directives in the extradata */
247 if (ret < 0)
248 return ret;
249
250 /* SHIFT and TIMERES affect the whole script so packet timing can only be
251 * done in a second pass */
252 for (i = 0; i < jacosub->q.nb_subs; i++) {
253 AVPacket *sub = jacosub->q.subs[i];
254 read_ts(jacosub, sub->data, &sub->pts, &sub->duration);
255 }
256 ff_subtitles_queue_finalize(s, &jacosub->q);
257
258 return 0;
259}
260
262 .p.name = "jacosub",
263 .p.long_name = NULL_IF_CONFIG_SMALL("JACOsub subtitle format"),
264 .priv_data_size = sizeof(JACOsubContext),
265 .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP,
269 .read_seek2 = ff_subtitles_read_seek,
271};
const FFInputFormat ff_jacosub_demuxer
Definition jacosubdec.c:261
void avpriv_set_pts_info(AVStream *st, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition avformat.c:834
Main libavformat public API header.
#define AVPROBE_SCORE_EXTENSION
score for file extension
Definition avformat.h:481
int avio_feof(AVIOContext *s)
Similar to feof() but also returns nonzero on read errors.
Definition aviobuf.c:349
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition avio.h:494
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
int ff_get_line(AVIOContext *s, char *buf, int maxlen)
Read a whole line of text from AVIOContext.
Definition aviobuf.c:772
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition bprint.c:122
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition bprint.c:69
AVBPrint public header.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define se(name, range_min, range_max)
Definition cbs_h264.c:67
#define ss(width, name, subs,...)
Definition cbs_vp9.c:202
#define s(width, name)
Definition cbs_vp9.c:198
#define fs(width, name, subs,...)
Definition cbs_vp9.c:200
static int read_probe(const AVProbeData *p)
Definition cdg.c:30
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition common.h:74
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
#define FF_INFMT_FLAG_INIT_CLEANUP
For an FFInputFormat with this flag set read_close() needs to be called by the caller upon read_heade...
Definition demux.h:35
static int64_t duration
Definition ffplay.c:330
static int read_header(FFV1Context *f, RangeCoder *c)
Definition ffv1dec.c:578
@ AV_CODEC_ID_JACOSUB
Definition codec_id.h:577
#define AV_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding.
Definition defs.h:40
AVStream * avformat_new_stream(AVFormatContext *s, const struct AVCodec *c)
Add a new stream to a media file.
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition bprint.c:235
#define AVERROR(e)
Definition error.h:45
@ AVMEDIA_TYPE_SUBTITLE
Definition avutil.h:203
static av_const int av_toupper(int c)
Locale-independent conversion of ASCII characters to uppercase.
Definition avstring.h:227
int av_strncasecmp(const char *a, const char *b, size_t n)
Locale-independent case-insensitive compare.
Definition avstring.c:218
#define AV_RB24(x)
JACOsub shared utils.
static av_always_inline int jss_whitespace(char c)
Definition jacosub.h:33
#define JSS_MAX_LINESIZE
Definition jacosub.h:31
static av_always_inline const char * jss_skip_whitespace(const char *p)
Definition jacosub.h:38
int ff_bprint_to_codecpar_extradata(AVCodecParameters *par, struct AVBPrint *buf)
Finalize buf into extradata and set its size appropriately.
Definition utils.c:594
static int get_shift(unsigned timeres, const char *buf)
Definition jacosubdec.c:129
static int get_jss_cmd(char k)
Definition jacosubdec.c:86
static const char *const cmds[]
Definition jacosubdec.c:73
static int jacosub_probe(const AVProbeData *p)
Definition jacosubdec.c:52
#define SSEP
static int jacosub_read_header(AVFormatContext *s)
Definition jacosubdec.c:164
static const char * read_ts(JACOsubContext *jacosub, const char *buf, int64_t *start, int64_t *duration)
Definition jacosubdec.c:97
static int timed_line(const char *ptr)
Definition jacosubdec.c:44
Macro definitions for various function/variable attributes.
#define av_fallthrough
Definition attributes.h:67
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
static av_cold int read_close(AVFormatContext *ctx)
Definition libcdio.c:143
static const uint8_t header[24]
Definition sdr2.c:68
#define FF_ARRAY_ELEMS(a)
unsigned int pos
Definition spdifenc.c:431
enum AVMediaType codec_type
General type of the encoded data.
Definition codec_par.h:53
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition codec_par.h:57
Format I/O context.
Definition avformat.h:1333
Bytestream IO Context.
Definition avio.h:160
This structure stores compressed data.
Definition packet.h:580
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition packet.h:621
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition packet.h:596
uint8_t * data
Definition packet.h:603
int64_t pos
byte position in stream, -1 if unknown
Definition packet.h:623
This structure contains the data a format has to probe a file.
Definition avformat.h:471
Stream structure.
Definition avformat.h:766
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition avformat.h:789
int nb_subs
number of subtitles packets
Definition subtitles.h:105
AVPacket ** subs
array of subtitles packets
Definition subtitles.h:104
unsigned timeres
Definition jacosubdec.c:41
FFDemuxSubtitlesQueue q
Definition jacosubdec.c:39
int ff_subtitles_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition subtitles.c:331
AVPacket * ff_subtitles_queue_insert(FFDemuxSubtitlesQueue *q, const uint8_t *event, size_t len, int merge)
Insert a new subtitle event.
Definition subtitles.c:111
int ff_subtitles_read_seek(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
Definition subtitles.c:337
int ff_subtitles_read_close(AVFormatContext *s)
Definition subtitles.c:345
void ff_subtitles_queue_finalize(void *log_ctx, FFDemuxSubtitlesQueue *q)
Set missing durations, sort subtitles by PTS (and then byte position), and drop duplicated events.
Definition subtitles.c:212
static av_always_inline int ff_subtitles_next_line(const char *ptr)
Get the number of characters to increment to jump to the next line, or to the end of the string.
Definition subtitles.h:205
#define me
int len
static double c[64]