Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FFmpeg/FFmpeg.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'libavformat')
-rw-r--r--libavformat/srtdec.c165
1 files changed, 115 insertions, 50 deletions
diff --git a/libavformat/srtdec.c b/libavformat/srtdec.c
index f08ed1d20d..6113f70562 100644
--- a/libavformat/srtdec.c
+++ b/libavformat/srtdec.c
@@ -1,6 +1,7 @@
/*
* SubRip subtitle demuxer
* Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
+ * Copyright (c) 2015 Clément Bœsch <u pkh me>
*
* This file is part of FFmpeg.
*
@@ -58,28 +59,65 @@ static int srt_probe(AVProbeData *p)
return 0;
}
-static int64_t get_pts(const char **buf, int *duration,
- int32_t *x1, int32_t *y1, int32_t *x2, int32_t *y2)
+struct event_info {
+ int32_t x1, x2, y1, y2;
+ int duration;
+ int64_t pts;
+ int64_t pos;
+};
+
+static int get_event_info(const char *line, struct event_info *ei)
+{
+ int hh1, mm1, ss1, ms1;
+ int hh2, mm2, ss2, ms2;
+
+ ei->x1 = ei->x2 = ei->y1 = ei->y2 = ei->duration = -1;
+ ei->pts = AV_NOPTS_VALUE;
+ ei->pos = -1;
+ if (sscanf(line, "%d:%2d:%2d%*1[,.]%3d --> %d:%2d:%2d%*1[,.]%3d"
+ "%*[ ]X1:%u X2:%u Y1:%u Y2:%u",
+ &hh1, &mm1, &ss1, &ms1,
+ &hh2, &mm2, &ss2, &ms2,
+ &ei->x1, &ei->x2, &ei->y1, &ei->y2) >= 8) {
+ const int64_t start = (hh1*3600LL + mm1*60LL + ss1) * 1000LL + ms1;
+ const int64_t end = (hh2*3600LL + mm2*60LL + ss2) * 1000LL + ms2;
+ ei->duration = end - start;
+ ei->pts = start;
+ return 0;
+ }
+ return -1;
+}
+
+static int add_event(FFDemuxSubtitlesQueue *q, AVBPrint *buf, char *line_cache,
+ const struct event_info *ei, int append_cache)
{
- int i;
-
- for (i=0; i<2; i++) {
- int hh1, mm1, ss1, ms1;
- int hh2, mm2, ss2, ms2;
- if (sscanf(*buf, "%d:%2d:%2d%*1[,.]%3d --> %d:%2d:%2d%*1[,.]%3d"
- "%*[ ]X1:%u X2:%u Y1:%u Y2:%u",
- &hh1, &mm1, &ss1, &ms1,
- &hh2, &mm2, &ss2, &ms2,
- x1, x2, y1, y2) >= 8) {
- int64_t start = (hh1*3600LL + mm1*60LL + ss1) * 1000LL + ms1;
- int64_t end = (hh2*3600LL + mm2*60LL + ss2) * 1000LL + ms2;
- *duration = end - start;
- *buf += ff_subtitles_next_line(*buf);
- return start;
+ if (append_cache && line_cache[0])
+ av_bprintf(buf, "%s\n", line_cache);
+ line_cache[0] = 0;
+
+ while (buf->len > 0 && buf->str[buf->len - 1] == '\n')
+ buf->str[--buf->len] = 0;
+
+ if (buf->len) {
+ AVPacket *sub = ff_subtitles_queue_insert(q, buf->str, buf->len, 0);
+ if (!sub)
+ return AVERROR(ENOMEM);
+ av_bprint_clear(buf);
+ sub->pos = ei->pos;
+ sub->pts = ei->pts;
+ sub->duration = ei->duration;
+ if (ei->x1 != -1) {
+ uint8_t *p = av_packet_new_side_data(sub, AV_PKT_DATA_SUBTITLE_POSITION, 16);
+ if (p) {
+ AV_WL32(p, ei->x1);
+ AV_WL32(p + 4, ei->y1);
+ AV_WL32(p + 8, ei->x2);
+ AV_WL32(p + 12, ei->y2);
+ }
}
- *buf += ff_subtitles_next_line(*buf);
}
- return AV_NOPTS_VALUE;
+
+ return 0;
}
static int srt_read_header(AVFormatContext *s)
@@ -88,6 +126,9 @@ static int srt_read_header(AVFormatContext *s)
AVBPrint buf;
AVStream *st = avformat_new_stream(s, NULL);
int res = 0;
+ char line[4096], line_cache[4096];
+ int has_event_info = 0;
+ struct event_info ei;
FFTextReader tr;
ff_text_init_avio(s, &tr, s->pb);
@@ -99,43 +140,67 @@ static int srt_read_header(AVFormatContext *s)
av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
+ line_cache[0] = 0;
+
while (!ff_text_eof(&tr)) {
- ff_subtitles_read_text_chunk(&tr, &buf);
-
- if (buf.len) {
- int64_t pos = ff_text_pos(&tr);
- int64_t pts;
- int duration;
- const char *ptr = buf.str;
- int32_t x1 = -1, y1 = -1, x2 = -1, y2 = -1;
- AVPacket *sub;
-
- pts = get_pts(&ptr, &duration, &x1, &y1, &x2, &y2);
- if (pts != AV_NOPTS_VALUE) {
- int len = buf.len - (ptr - buf.str);
- if (len <= 0)
- continue;
- sub = ff_subtitles_queue_insert(&srt->q, ptr, len, 0);
- if (!sub) {
- res = AVERROR(ENOMEM);
+ struct event_info tmp_ei;
+ const int64_t pos = ff_text_pos(&tr);
+ ptrdiff_t len = ff_subtitles_read_line(&tr, line, sizeof(line));
+
+ if (len < 0)
+ break;
+
+ if (!len || !line[0])
+ continue;
+
+ if (get_event_info(line, &tmp_ei) < 0) {
+ char *pline;
+
+ if (!has_event_info)
+ continue;
+
+ if (line_cache[0]) {
+ /* We got some cache and a new line so we assume the cached
+ * line was actually part of the payload */
+ av_bprintf(&buf, "%s\n", line_cache);
+ line_cache[0] = 0;
+ }
+
+ /* If the line doesn't start with a number, we assume it's part of
+ * the payload, otherwise is likely an event number preceding the
+ * timing information... but we can't be sure of this yet, so we
+ * cache it */
+ if (strtol(line, &pline, 10) < 0 || line == pline)
+ av_bprintf(&buf, "%s\n", line);
+ else
+ strcpy(line_cache, line);
+ } else {
+ if (has_event_info) {
+ /* We have the information of previous event, append it to the
+ * queue. We insert the cached line if and only if the payload
+ * is empty and the cached line is not a standalone number. */
+ char *pline = NULL;
+ const int standalone_number = strtol(line_cache, &pline, 10) >= 0 && pline && !*pline;
+ res = add_event(&srt->q, &buf, line_cache, &ei, !buf.len && !standalone_number);
+ if (res < 0)
goto end;
- }
- sub->pos = pos;
- sub->pts = pts;
- sub->duration = duration;
- if (x1 != -1) {
- uint8_t *p = av_packet_new_side_data(sub, AV_PKT_DATA_SUBTITLE_POSITION, 16);
- if (p) {
- AV_WL32(p, x1);
- AV_WL32(p + 4, y1);
- AV_WL32(p + 8, x2);
- AV_WL32(p + 12, y2);
- }
- }
+ } else {
+ has_event_info = 1;
}
+ tmp_ei.pos = pos;
+ ei = tmp_ei;
}
}
+ /* Append the last event. Here we force the cache to be flushed, because a
+ * trailing number is more likely to be geniune (for example a copyright
+ * date) and not the event index of an inexistant event */
+ if (has_event_info) {
+ res = add_event(&srt->q, &buf, line_cache, &ei, 1);
+ if (res < 0)
+ goto end;
+ }
+
ff_subtitles_queue_finalize(s, &srt->q);
end: