2 * SubRip subtitle demuxer
3 * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
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/bprint.h"
26 #include "libavutil/intreadwrite.h"
29 FFDemuxSubtitlesQueue q
;
32 static int srt_probe(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 /* Check if the first non-empty line is a number. We do not check what the
44 * number is because in practice it can be anything. */
45 if (ff_subtitles_read_line(&tr
, buf
, sizeof(buf
)) < 0 ||
46 strtol(buf
, &pbuf
, 10) < 0 || *pbuf
)
49 /* Check if the next line matches a SRT timestamp */
50 if (ff_subtitles_read_line(&tr
, buf
, sizeof(buf
)) < 0)
52 if (buf
[0] >= '0' && buf
[1] <= '9' && strstr(buf
, " --> ")
53 && sscanf(buf
, "%*d:%*2d:%*2d%*1[,.]%*3d --> %*d:%*2d:%*2d%*1[,.]%3d", &v
) == 1)
54 return AVPROBE_SCORE_MAX
;
59 static int64_t get_pts(const char **buf
, int *duration
,
60 int32_t *x1
, int32_t *y1
, int32_t *x2
, int32_t *y2
)
65 int hh1
, mm1
, ss1
, ms1
;
66 int hh2
, mm2
, ss2
, ms2
;
67 if (sscanf(*buf
, "%d:%2d:%2d%*1[,.]%3d --> %d:%2d:%2d%*1[,.]%3d"
68 "%*[ ]X1:%u X2:%u Y1:%u Y2:%u",
69 &hh1
, &mm1
, &ss1
, &ms1
,
70 &hh2
, &mm2
, &ss2
, &ms2
,
71 x1
, x2
, y1
, y2
) >= 8) {
72 int64_t start
= (hh1
*3600LL + mm1
*60LL + ss1
) * 1000LL + ms1
;
73 int64_t end
= (hh2
*3600LL + mm2
*60LL + ss2
) * 1000LL + ms2
;
74 *duration
= end
- start
;
75 *buf
+= ff_subtitles_next_line(*buf
);
78 *buf
+= ff_subtitles_next_line(*buf
);
80 return AV_NOPTS_VALUE
;
83 static int srt_read_header(AVFormatContext
*s
)
85 SRTContext
*srt
= s
->priv_data
;
87 AVStream
*st
= avformat_new_stream(s
, NULL
);
90 ff_text_init_avio(s
, &tr
, s
->pb
);
93 return AVERROR(ENOMEM
);
94 avpriv_set_pts_info(st
, 64, 1, 1000);
95 st
->codec
->codec_type
= AVMEDIA_TYPE_SUBTITLE
;
96 st
->codec
->codec_id
= AV_CODEC_ID_SUBRIP
;
98 av_bprint_init(&buf
, 0, AV_BPRINT_SIZE_UNLIMITED
);
100 while (!ff_text_eof(&tr
)) {
101 ff_subtitles_read_text_chunk(&tr
, &buf
);
104 int64_t pos
= ff_text_pos(&tr
);
107 const char *ptr
= buf
.str
;
108 int32_t x1
= -1, y1
= -1, x2
= -1, y2
= -1;
111 pts
= get_pts(&ptr
, &duration
, &x1
, &y1
, &x2
, &y2
);
112 if (pts
!= AV_NOPTS_VALUE
) {
113 int len
= buf
.len
- (ptr
- buf
.str
);
116 sub
= ff_subtitles_queue_insert(&srt
->q
, ptr
, len
, 0);
118 res
= AVERROR(ENOMEM
);
123 sub
->duration
= duration
;
125 uint8_t *p
= av_packet_new_side_data(sub
, AV_PKT_DATA_SUBTITLE_POSITION
, 16);
137 ff_subtitles_queue_finalize(&srt
->q
);
140 av_bprint_finalize(&buf
, NULL
);
144 static int srt_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
146 SRTContext
*srt
= s
->priv_data
;
147 return ff_subtitles_queue_read_packet(&srt
->q
, pkt
);
150 static int srt_read_seek(AVFormatContext
*s
, int stream_index
,
151 int64_t min_ts
, int64_t ts
, int64_t max_ts
, int flags
)
153 SRTContext
*srt
= s
->priv_data
;
154 return ff_subtitles_queue_seek(&srt
->q
, s
, stream_index
,
155 min_ts
, ts
, max_ts
, flags
);
158 static int srt_read_close(AVFormatContext
*s
)
160 SRTContext
*srt
= s
->priv_data
;
161 ff_subtitles_queue_clean(&srt
->q
);
165 AVInputFormat ff_srt_demuxer
= {
167 .long_name
= NULL_IF_CONFIG_SMALL("SubRip subtitle"),
168 .priv_data_size
= sizeof(SRTContext
),
169 .read_probe
= srt_probe
,
170 .read_header
= srt_read_header
,
171 .read_packet
= srt_read_packet
,
172 .read_seek2
= srt_read_seek
,
173 .read_close
= srt_read_close
,