FFmpeg  4.0
srtdec.c
Go to the documentation of this file.
1 /*
2  * SubRip subtitle demuxer
3  * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
4  * Copyright (c) 2015 Clément Bœsch <u pkh me>
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #include "avformat.h"
24 #include "internal.h"
25 #include "subtitles.h"
26 #include "libavutil/bprint.h"
27 #include "libavutil/intreadwrite.h"
28 
29 typedef struct {
31 } SRTContext;
32 
33 static int srt_probe(AVProbeData *p)
34 {
35  int v;
36  char buf[64], *pbuf;
37  FFTextReader tr;
38 
39  ff_text_init_buf(&tr, p->buf, p->buf_size);
40 
41  while (ff_text_peek_r8(&tr) == '\r' || ff_text_peek_r8(&tr) == '\n')
42  ff_text_r8(&tr);
43 
44  /* Check if the first non-empty line is a number. We do not check what the
45  * number is because in practice it can be anything.
46  * Also, that number can be followed by random garbage, so we can not
47  * unfortunately check that we only have a number. */
48  if (ff_subtitles_read_line(&tr, buf, sizeof(buf)) < 0 ||
49  strtol(buf, &pbuf, 10) < 0 || pbuf == buf)
50  return 0;
51 
52  /* Check if the next line matches a SRT timestamp */
53  if (ff_subtitles_read_line(&tr, buf, sizeof(buf)) < 0)
54  return 0;
55  pbuf = buf;
56  if (buf[0] == '-')
57  pbuf++;
58  if (pbuf[0] >= '0' && pbuf[0] <= '9' && strstr(buf, " --> ")
59  && sscanf(buf, "%*d:%*d:%*d%*1[,.]%*d --> %*d:%*d:%*d%*1[,.]%d", &v) == 1)
60  return AVPROBE_SCORE_MAX;
61 
62  return 0;
63 }
64 
65 struct event_info {
67  int duration;
68  int64_t pts;
69  int64_t pos;
70 };
71 
72 static int get_event_info(const char *line, struct event_info *ei)
73 {
74  int hh1, mm1, ss1, ms1;
75  int hh2, mm2, ss2, ms2;
76 
77  ei->x1 = ei->x2 = ei->y1 = ei->y2 = ei->duration = -1;
78  ei->pts = AV_NOPTS_VALUE;
79  ei->pos = -1;
80  if (sscanf(line, "%d:%d:%d%*1[,.]%d --> %d:%d:%d%*1[,.]%d"
81  "%*[ ]X1:%"PRId32" X2:%"PRId32" Y1:%"PRId32" Y2:%"PRId32,
82  &hh1, &mm1, &ss1, &ms1,
83  &hh2, &mm2, &ss2, &ms2,
84  &ei->x1, &ei->x2, &ei->y1, &ei->y2) >= 8) {
85  const int64_t start = (hh1*3600LL + mm1*60LL + ss1) * 1000LL + ms1;
86  const int64_t end = (hh2*3600LL + mm2*60LL + ss2) * 1000LL + ms2;
87  ei->duration = end - start;
88  ei->pts = start;
89  return 0;
90  }
91  return -1;
92 }
93 
94 static int add_event(FFDemuxSubtitlesQueue *q, AVBPrint *buf, char *line_cache,
95  const struct event_info *ei, int append_cache)
96 {
97  if (append_cache && line_cache[0])
98  av_bprintf(buf, "%s\n", line_cache);
99  line_cache[0] = 0;
100 
101  while (buf->len > 0 && buf->str[buf->len - 1] == '\n')
102  buf->str[--buf->len] = 0;
103 
104  if (buf->len) {
105  AVPacket *sub = ff_subtitles_queue_insert(q, buf->str, buf->len, 0);
106  if (!sub)
107  return AVERROR(ENOMEM);
108  av_bprint_clear(buf);
109  sub->pos = ei->pos;
110  sub->pts = ei->pts;
111  sub->duration = ei->duration;
112  if (ei->x1 != -1) {
114  if (p) {
115  AV_WL32(p, ei->x1);
116  AV_WL32(p + 4, ei->y1);
117  AV_WL32(p + 8, ei->x2);
118  AV_WL32(p + 12, ei->y2);
119  }
120  }
121  }
122 
123  return 0;
124 }
125 
127 {
128  SRTContext *srt = s->priv_data;
129  AVBPrint buf;
131  int res = 0;
132  char line[4096], line_cache[4096];
133  int has_event_info = 0;
134  struct event_info ei;
135  FFTextReader tr;
136  ff_text_init_avio(s, &tr, s->pb);
137 
138  if (!st)
139  return AVERROR(ENOMEM);
140  avpriv_set_pts_info(st, 64, 1, 1000);
143 
145 
146  line_cache[0] = 0;
147 
148  while (!ff_text_eof(&tr)) {
149  struct event_info tmp_ei;
150  const int64_t pos = ff_text_pos(&tr);
151  ptrdiff_t len = ff_subtitles_read_line(&tr, line, sizeof(line));
152 
153  if (len < 0)
154  break;
155 
156  if (!len || !line[0])
157  continue;
158 
159  if (get_event_info(line, &tmp_ei) < 0) {
160  char *pline;
161 
162  if (!has_event_info)
163  continue;
164 
165  if (line_cache[0]) {
166  /* We got some cache and a new line so we assume the cached
167  * line was actually part of the payload */
168  av_bprintf(&buf, "%s\n", line_cache);
169  line_cache[0] = 0;
170  }
171 
172  /* If the line doesn't start with a number, we assume it's part of
173  * the payload, otherwise is likely an event number preceding the
174  * timing information... but we can't be sure of this yet, so we
175  * cache it */
176  if (strtol(line, &pline, 10) < 0 || line == pline)
177  av_bprintf(&buf, "%s\n", line);
178  else
179  strcpy(line_cache, line);
180  } else {
181  if (has_event_info) {
182  /* We have the information of previous event, append it to the
183  * queue. We insert the cached line if and only if the payload
184  * is empty and the cached line is not a standalone number. */
185  char *pline = NULL;
186  const int standalone_number = strtol(line_cache, &pline, 10) >= 0 && pline && !*pline;
187  res = add_event(&srt->q, &buf, line_cache, &ei, !buf.len && !standalone_number);
188  if (res < 0)
189  goto end;
190  } else {
191  has_event_info = 1;
192  }
193  tmp_ei.pos = pos;
194  ei = tmp_ei;
195  }
196  }
197 
198  /* Append the last event. Here we force the cache to be flushed, because a
199  * trailing number is more likely to be geniune (for example a copyright
200  * date) and not the event index of an inexistant event */
201  if (has_event_info) {
202  res = add_event(&srt->q, &buf, line_cache, &ei, 1);
203  if (res < 0)
204  goto end;
205  }
206 
207  ff_subtitles_queue_finalize(s, &srt->q);
208 
209 end:
210  av_bprint_finalize(&buf, NULL);
211  return res;
212 }
213 
215 {
216  SRTContext *srt = s->priv_data;
217  return ff_subtitles_queue_read_packet(&srt->q, pkt);
218 }
219 
220 static int srt_read_seek(AVFormatContext *s, int stream_index,
221  int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
222 {
223  SRTContext *srt = s->priv_data;
224  return ff_subtitles_queue_seek(&srt->q, s, stream_index,
225  min_ts, ts, max_ts, flags);
226 }
227 
229 {
230  SRTContext *srt = s->priv_data;
232  return 0;
233 }
234 
236  .name = "srt",
237  .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
238  .priv_data_size = sizeof(SRTContext),
242  .read_seek2 = srt_read_seek,
244 };
#define NULL
Definition: coverity.c:32
const char * s
Definition: avisynth_c.h:768
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:94
static int get_event_info(const char *line, struct event_info *ei)
Definition: srtdec.c:72
int64_t pos
byte position in stream, -1 if unknown
Definition: avcodec.h:1450
void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition: utils.c:4811
Subtitle event position.
Definition: avcodec.h:1286
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: avcodec.h:3884
int32_t y2
Definition: srtdec.c:66
void ff_subtitles_queue_clean(FFDemuxSubtitlesQueue *q)
Remove and destroy all the subtitles packets.
Definition: subtitles.c:297
FFDemuxSubtitlesQueue q
Definition: srtdec.c:30
int ff_text_peek_r8(FFTextReader *r)
Like ff_text_r8(), but don&#39;t remove the byte from the buffer.
Definition: subtitles.c:97
static int srt_read_close(AVFormatContext *s)
Definition: srtdec.c:228
int32_t x1
Definition: srtdec.c:66
static AVPacket pkt
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
int64_t pts
Definition: srtdec.c:68
static int add_event(FFDemuxSubtitlesQueue *q, AVBPrint *buf, char *line_cache, const struct event_info *ei, int append_cache)
Definition: srtdec.c:94
Format I/O context.
Definition: avformat.h:1342
uint8_t
int ff_subtitles_queue_read_packet(FFDemuxSubtitlesQueue *q, AVPacket *pkt)
Generic read_packet() callback for subtitles demuxers using this queue system.
Definition: subtitles.c:208
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: avcodec.h:1448
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:4441
static int flags
Definition: log.c:55
static av_cold int read_close(AVFormatContext *ctx)
Definition: libcdio.c:145
#define AV_BPRINT_SIZE_UNLIMITED
int ff_text_eof(FFTextReader *r)
Return non-zero if EOF was reached.
Definition: subtitles.c:92
#define AVERROR(e)
Definition: error.h:43
ptrdiff_t ff_subtitles_read_line(FFTextReader *tr, char *buf, size_t size)
Read a line of text.
Definition: subtitles.c:406
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
enum AVMediaType codec_type
General type of the encoded data.
Definition: avcodec.h:3880
Definition: graph2dot.c:48
void ff_text_init_avio(void *s, FFTextReader *r, AVIOContext *pb)
Initialize the FFTextReader from the given AVIOContext.
Definition: subtitles.c:27
static int srt_probe(AVProbeData *p)
Definition: srtdec.c:33
int buf_size
Size of buf except extra allocated bytes.
Definition: avformat.h:451
unsigned char * buf
Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero.
Definition: avformat.h:450
int64_t ff_text_pos(FFTextReader *r)
Return the byte position of the next byte returned by ff_text_r8().
Definition: subtitles.c:60
int duration
Definition: srtdec.c:67
int64_t pos
Definition: srtdec.c:69
static int read_probe(AVProbeData *pd)
Definition: jvdec.c:55
int32_t
int32_t y1
Definition: srtdec.c:66
static int read_header(FFV1Context *f)
Definition: ffv1dec.c:530
int ff_text_r8(FFTextReader *r)
Return the next byte.
Definition: subtitles.c:65
Stream structure.
Definition: avformat.h:873
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
Definition: avio_reading.c:42
int ff_subtitles_queue_seek(FFDemuxSubtitlesQueue *q, AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
Update current_sub_idx to emulate a seek.
Definition: subtitles.c:245
AVIOContext * pb
I/O context.
Definition: avformat.h:1384
int32_t x2
Definition: srtdec.c:66
void * buf
Definition: avisynth_c.h:690
AVInputFormat ff_srt_demuxer
Definition: srtdec.c:235
This structure contains the data a format has to probe a file.
Definition: avformat.h:448
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:227
#define AVPROBE_SCORE_MAX
maximum score
Definition: avformat.h:460
Main libavformat public API header.
static int srt_read_seek(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags)
Definition: srtdec.c:220
void ff_text_init_buf(FFTextReader *r, void *buf, size_t size)
Similar to ff_text_init_avio(), but sets it up to read from a bounded buffer.
Definition: subtitles.c:53
static int srt_read_header(AVFormatContext *s)
Definition: srtdec.c:126
static int srt_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition: srtdec.c:214
int len
void * priv_data
Format private data.
Definition: avformat.h:1370
void INT64 start
Definition: avisynth_c.h:690
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:647
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1020
uint8_t * av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type, int size)
Allocate new information of a packet.
Definition: avpacket.c:329
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
This structure stores compressed data.
Definition: avcodec.h:1407
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:193
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: avcodec.h:1423
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
#define AV_WL32(p, v)
Definition: intreadwrite.h:426