summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUoti Urpala <uau@glyph.nonexistent.invalid>2010-05-19 01:05:25 +0300
committerUoti Urpala <uau@glyph.nonexistent.invalid>2011-01-18 15:17:28 +0200
commit4284cf9ef050044619c773b195f0eb941f922e88 (patch)
treefa1c57bce88ca589a4dc00390dc35860fb928a16
parentd5eaf6a820d73181f07de3387cd1c115a49648f5 (diff)
downloadmpv-4284cf9ef050044619c773b195f0eb941f922e88.tar.bz2
mpv-4284cf9ef050044619c773b195f0eb941f922e88.tar.xz
subtitles: style support for common SubRip tags and MicroDVD
SubRip subtitles have no "official" spec for any styling support, but various tags are in common use; previous code filtered out text between <> to remove HTML-style tags. Add support for those tags and for MicroDVD subtitle styling. The style display is implemented by converting the subtitles to the ASS subtitle format and displaying them with libass, so libass needs to be enabled. Original patch by Clément Bœsch <ubitux@gmail.com>.
-rw-r--r--Makefile1
-rw-r--r--mplayer.c4
-rw-r--r--sub/subassconvert.c502
-rw-r--r--sub/subassconvert.h27
-rw-r--r--subreader.c152
-rw-r--r--subreader.h4
6 files changed, 669 insertions, 21 deletions
diff --git a/Makefile b/Makefile
index 9f5dbc6f23..15bbfbc31c 100644
--- a/Makefile
+++ b/Makefile
@@ -517,6 +517,7 @@ SRCS_COMMON = asxparser.c \
stream/stream_null.c \
stream/url.c \
sub/dec_sub.c \
+ sub/subassconvert.c \
$(SRCS_COMMON-yes)
diff --git a/mplayer.c b/mplayer.c
index 69e4dcd0fb..1c41e35f9d 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -1105,7 +1105,7 @@ void add_subtitles(struct MPContext *mpctx, char *filename, float fps, int noerr
asst = ass_read_stream(ass_library, filename, 0);
#endif
if (!asst) {
- subd = sub_read_file(filename, fps);
+ subd = sub_read_file(filename, fps, &mpctx->opts);
if (subd) {
asst = ass_read_subdata(ass_library, subd, fps);
if (asst) {
@@ -1116,7 +1116,7 @@ void add_subtitles(struct MPContext *mpctx, char *filename, float fps, int noerr
}
} else
#endif
- subd = sub_read_file(filename, fps);
+ subd = sub_read_file(filename, fps, &mpctx->opts);
if (!asst && !subd) {
diff --git a/sub/subassconvert.c b/sub/subassconvert.c
new file mode 100644
index 0000000000..773cb7f4d7
--- /dev/null
+++ b/sub/subassconvert.c
@@ -0,0 +1,502 @@
+/*
+ * Subtitles converter to SSA/ASS in order to allow special formatting
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdbool.h>
+
+#include "mp_msg.h"
+#include "subassconvert.h"
+#include "bstr.h"
+#include "libavutil/common.h"
+
+struct line {
+ char *buf;
+ int bufsize;
+ int len;
+};
+
+#ifdef __GNUC__
+static void append_text(struct line *dst, char *fmt, ...) __attribute__ ((format(printf, 2, 3)));
+#endif
+
+static void append_text(struct line *dst, char *fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+ int ret = vsnprintf(dst->buf + dst->len, dst->bufsize - dst->len, fmt, va);
+ if (ret < 0)
+ goto out;
+ dst->len += ret;
+ if (dst->len > dst->bufsize)
+ dst->len = dst->bufsize;
+ out:
+ va_end(va);
+}
+
+static int indexof(const char *s, int c)
+{
+ char *f = strchr(s, c);
+ return f ? (f - s) : -1;
+}
+
+
+
+/*
+ * SubRip
+ *
+ * Support basic tags (italic, bold, underline, strike-through)
+ * and font tag with size, color and face attributes.
+ *
+ */
+
+struct font_tag {
+ int size;
+ uint32_t color;
+ struct bstr face;
+ bool has_size : 1;
+ bool has_color : 1;
+ bool has_face : 1;
+};
+
+static const struct tag_conv {
+ char *from;
+ char *to;
+} subrip_basic_tags[] = {
+ {"<i>", "{\\i1}"}, {"</i>", "{\\i0}"},
+ {"<b>", "{\\b1}"}, {"</b>", "{\\b0}"},
+ {"<u>", "{\\u1}"}, {"</u>", "{\\u0}"},
+ {"<s>", "{\\s1}"}, {"</s>", "{\\s0}"},
+ {"{", "\\{"}, {"}", "\\}"},
+ {"\n", "\\N"}
+};
+
+static const struct {
+ char *s;
+ uint32_t v;
+} subrip_web_colors[] = {
+ /* 16 named HTML colors in BGR format */
+ {"red", 0x0000ff}, {"blue", 0xff0000}, {"lime", 0x00ff00},
+ {"aqua", 0xffff00}, {"purple", 0x800080}, {"yellow", 0x00ffff},
+ {"fuchsia", 0xff00ff}, {"white", 0xffffff}, {"gray", 0x808080},
+ {"maroon", 0x000080}, {"olive", 0x008080}, {"black", 0x000000},
+ {"silver", 0xc0c0c0}, {"teal", 0x808000}, {"green", 0x008000},
+ {"navy", 0x800000}
+};
+
+#define SUBRIP_MAX_STACKED_FONT_TAGS 16
+
+void subassconvert_subrip(const char *orig, char *dest, int dest_buffer_size)
+{
+ /* line is not const to avoid warnings with strtol, etc.
+ * orig content won't be changed */
+ char *line = (char *)orig;
+ struct line new_line = {
+ .buf = dest,
+ .bufsize = dest_buffer_size,
+ };
+ struct font_tag font_stack[SUBRIP_MAX_STACKED_FONT_TAGS + 1];
+ font_stack[0] = (struct font_tag){0}; // type with all defaults
+ int sp = 0;
+
+ while (*line && new_line.len < new_line.bufsize - 1) {
+ char *orig_line = line;
+
+ for (int i = 0; i < FF_ARRAY_ELEMS(subrip_basic_tags); i++) {
+ const struct tag_conv *tag = &subrip_basic_tags[i];
+ int from_len = strlen(tag->from);
+ if (strncmp(line, tag->from, from_len) == 0) {
+ append_text(&new_line, "%s", tag->to);
+ line += from_len;
+ }
+ }
+
+ if (strncmp(line, "</font>", 7) == 0) {
+ /* Closing font tag */
+ line += 7;
+
+ if (sp > 0) {
+ struct font_tag *tag = &font_stack[sp];
+ struct font_tag *last_tag = &tag[-1];
+ sp--;
+
+ if (tag->has_size) {
+ if (!last_tag->has_size)
+ append_text(&new_line, "{\\fs}");
+ else if (last_tag->size != tag->size)
+ append_text(&new_line, "{\\fs%d}", last_tag->size);
+ }
+
+ if (tag->has_color) {
+ if (!last_tag->has_color)
+ append_text(&new_line, "{\\c}");
+ else if (last_tag->color != tag->color)
+ append_text(&new_line, "{\\c&H%06X&}", last_tag->color);
+ }
+
+ if (tag->has_face) {
+ if (!last_tag->has_face)
+ append_text(&new_line, "{\\fn}");
+ else if (bstrcmp(last_tag->face, tag->face) != 0)
+ append_text(&new_line, "{\\fn%.*s}",
+ BSTR_P(last_tag->face));
+ }
+ }
+ } else if (strncmp(line, "<font ", 6) == 0
+ && sp + 1 < FF_ARRAY_ELEMS(font_stack)) {
+ /* Opening font tag */
+ char *potential_font_tag_start = line;
+ int len_backup = new_line.len;
+ struct font_tag *tag = &font_stack[sp + 1];
+ bool has_valid_attr = false;
+
+ *tag = tag[-1]; // keep values from previous tag
+ line += 6;
+
+ while (*line && *line != '>') {
+ if (strncmp(line, "size=\"", 6) == 0) {
+ line += 6;
+ tag->size = strtol(line, &line, 10);
+ if (*line != '"')
+ break;
+ append_text(&new_line, "{\\fs%d}", tag->size);
+ tag->has_size = true;
+ has_valid_attr = true;
+ } else if (strncmp(line, "color=\"", 7) == 0) {
+ line += 7;
+ if (*line == '#') {
+ // #RRGGBB format
+ line++;
+ tag->color = strtol(line, &line, 16) & 0x00ffffff;
+ if (*line != '"')
+ break;
+ tag->color = ((tag->color & 0xff) << 16)
+ | (tag->color & 0xff00)
+ | ((tag->color & 0xff0000) >> 16);
+ } else {
+ // Standard web colors
+ int len = indexof(line, '"');
+ if (len <= 0)
+ break;
+ for (int i = 0; i < FF_ARRAY_ELEMS(subrip_web_colors); i++) {
+ char *color = subrip_web_colors[i].s;
+ if (strlen(color) == len
+ && strncasecmp(line, color, len) == 0) {
+ tag->color = subrip_web_colors[i].v;
+ goto foundcolor;
+ }
+ }
+
+ /* We didn't find any matching color */
+ mp_tmsg(MSGT_SUBREADER, MSGL_WARN,
+ "SubRip: unknown font color in subtitle: %s\n", orig);
+ append_text(&new_line, "{\\c}");
+ line += len + 1;
+ continue;
+
+ foundcolor:
+ line += len;
+ }
+ append_text(&new_line, "{\\c&H%06X&}", tag->color);
+ tag->has_color = true;
+ has_valid_attr = true;
+ } else if (strncmp(line, "face=\"", 6) == 0) {
+ /* Font face attribute */
+ line += 6;
+ int len = indexof(line, '"');
+ if (len <= 0)
+ break;
+ tag->face.start = line;
+ tag->face.len = len;
+ line += len;
+ append_text(&new_line, "{\\fn%.*s}", BSTR_P(tag->face));
+ tag->has_face = true;
+ has_valid_attr = true;
+ }
+ line++;
+ }
+
+ if (!has_valid_attr || *line != '>') { /* Not valid font tag */
+ line = potential_font_tag_start;
+ new_line.len = len_backup;
+ } else {
+ sp++;
+ line++;
+ }
+ }
+
+ /* Tag conversion code didn't match */
+ if (line == orig_line)
+ new_line.buf[new_line.len++] = *line++;
+ }
+ new_line.buf[new_line.len] = 0;
+}
+
+
+/*
+ * MicroDVD
+ *
+ * Based on the specifications found here:
+ * https://trac.videolan.org/vlc/ticket/1825#comment:6
+ */
+
+struct microdvd_tag {
+ char key;
+ int persistent;
+ uint32_t data1;
+ uint32_t data2;
+ struct bstr data_string;
+};
+
+#define MICRODVD_PERSISTENT_OFF 0
+#define MICRODVD_PERSISTENT_ON 1
+#define MICRODVD_PERSISTENT_OPENED 2
+
+// Color, Font, Size, cHarset, stYle, Position, cOordinate
+#define MICRODVD_TAGS "cfshyYpo"
+
+static void microdvd_set_tag(struct microdvd_tag *tags, struct microdvd_tag tag)
+{
+ int tag_index = indexof(MICRODVD_TAGS, tag.key);
+
+ if (tag_index < 0)
+ return;
+ memcpy(&tags[tag_index], &tag, sizeof(tag));
+}
+
+// italic, bold, underline, strike-through
+#define MICRODVD_STYLES "ibus"
+
+static char *microdvd_load_tags(struct microdvd_tag *tags, char *s)
+{
+ while (*s == '{') {
+ char *start = s;
+ char tag_char = *(s + 1);
+ struct microdvd_tag tag = {0};
+
+ if (!tag_char || *(s + 2) != ':')
+ break;
+ s += 3;
+
+ switch (tag_char) {
+
+ /* Style */
+ case 'Y':
+ tag.persistent = MICRODVD_PERSISTENT_ON;
+ case 'y':
+ while (*s && *s != '}') {
+ int style_index = indexof(MICRODVD_STYLES, *s);
+
+ if (style_index >= 0)
+ tag.data1 |= (1 << style_index);
+ s++;
+ }
+ if (*s != '}')
+ break;
+ /* We must distinguish persistent and non-persistent styles
+ * to handle this kind of style tags: {y:ib}{Y:us} */
+ tag.key = tag_char;
+ break;
+
+ /* Color */
+ case 'C':
+ tag.persistent = MICRODVD_PERSISTENT_ON;
+ case 'c':
+ tag.data1 = strtol(s, &s, 16) & 0x00ffffff;
+ if (*s != '}')
+ break;
+ tag.key = 'c';
+ break;
+
+ /* Font name */
+ case 'F':
+ tag.persistent = MICRODVD_PERSISTENT_ON;
+ case 'f':
+ {
+ int len = indexof(s, '}');
+ if (len < 0)
+ break;
+ tag.data_string.start = s;
+ tag.data_string.len = len;
+ s += len;
+ tag.key = 'f';
+ break;
+ }
+
+ /* Font size */
+ case 'S':
+ tag.persistent = MICRODVD_PERSISTENT_ON;
+ case 's':
+ tag.data1 = strtol(s, &s, 10);
+ if (*s != '}')
+ break;
+ tag.key = 's';
+ break;
+
+ /* Charset */
+ case 'H':
+ {
+ //TODO: not yet handled, just parsed.
+ int len = indexof(s, '}');
+ if (len < 0)
+ break;
+ tag.data_string.start = s;
+ tag.data_string.len = len;
+ s += len;
+ tag.key = 'h';
+ break;
+ }
+
+ /* Position */
+ case 'P':
+ tag.persistent = MICRODVD_PERSISTENT_ON;
+ tag.data1 = (*s++ == '1');
+ if (*s != '}')
+ break;
+ tag.key = 'p';
+ break;
+
+ /* Coordinates */
+ case 'o':
+ tag.persistent = MICRODVD_PERSISTENT_ON;
+ tag.data1 = strtol(s, &s, 10);
+ if (*s != ',')
+ break;
+ s++;
+ tag.data2 = strtol(s, &s, 10);
+ if (*s != '}')
+ break;
+ tag.key = 'o';
+ break;
+
+ default: /* Unknown tag, we consider it to be text */
+ break;
+ }
+
+ if (tag.key == 0)
+ return start;
+
+ microdvd_set_tag(tags, tag);
+ s++;
+ }
+ return s;
+}
+
+static void microdvd_open_tags(struct line *new_line, struct microdvd_tag *tags)
+{
+ for (int i = 0; i < sizeof(MICRODVD_TAGS) - 1; i++) {
+ if (tags[i].persistent == MICRODVD_PERSISTENT_OPENED)
+ continue;
+ switch (tags[i].key) {
+ case 'Y':
+ case 'y':
+ for (int sidx = 0; sidx < sizeof(MICRODVD_STYLES) - 1; sidx++)
+ if (tags[i].data1 & (1 << sidx))
+ append_text(new_line, "{\\%c1}", MICRODVD_STYLES[sidx]);
+ break;
+
+ case 'c':
+ append_text(new_line, "{\\c&H%06X&}", tags[i].data1);
+ break;
+
+ case 'f':
+ append_text(new_line, "{\\fn%.*s}", BSTR_P(tags[i].data_string));
+ break;
+
+ case 's':
+ append_text(new_line, "{\\fs%d}", tags[i].data1);
+ break;
+
+ case 'p':
+ if (tags[i].data1 == 0)
+ append_text(new_line, "{\\an8}");
+ break;
+
+ case 'o':
+ append_text(new_line, "{\\pos(%d,%d)}",
+ tags[i].data1, tags[i].data2);
+ break;
+ }
+ if (tags[i].persistent == MICRODVD_PERSISTENT_ON)
+ tags[i].persistent = MICRODVD_PERSISTENT_OPENED;
+ }
+}
+
+static void microdvd_close_no_persistent_tags(struct line *new_line,
+ struct microdvd_tag *tags)
+{
+ int i;
+
+ for (i = sizeof(MICRODVD_TAGS) - 2; i; i--) {
+ if (tags[i].persistent != MICRODVD_PERSISTENT_OFF)
+ continue;
+ switch (tags[i].key) {
+
+ case 'y':
+ for (int sidx = sizeof(MICRODVD_STYLES) - 2; sidx >= 0; sidx--)
+ if (tags[i].data1 & (1 << sidx))
+ append_text(new_line, "{\\%c0}", MICRODVD_STYLES[sidx]);
+ break;
+
+ case 'c':
+ append_text(new_line, "{\\c}");
+ break;
+
+ case 'f':
+ append_text(new_line, "{\\fn}");
+ break;
+
+ case 's':
+ append_text(new_line, "{\\fs}");
+ break;
+ }
+ tags[i].key = 0;
+ }
+}
+
+void subassconvert_microdvd(const char *orig, char *dest, int dest_buffer_size)
+{
+ /* line is not const to avoid warnings with strtol, etc.
+ * orig content won't be changed */
+ char *line = (char *)orig;
+ struct line new_line = {
+ .buf = dest,
+ .bufsize = dest_buffer_size,
+ };
+ struct microdvd_tag tags[sizeof(MICRODVD_TAGS) - 1] = {{0}};
+
+ while (*line) {
+ line = microdvd_load_tags(tags, line);
+ microdvd_open_tags(&new_line, tags);
+
+ while (*line && *line != '|')
+ new_line.buf[new_line.len++] = *line++;
+
+ if (*line == '|') {
+ microdvd_close_no_persistent_tags(&new_line, tags);
+ append_text(&new_line, "\\N");
+ line++;
+ }
+ }
+ new_line.buf[new_line.len] = 0;
+}
diff --git a/sub/subassconvert.h b/sub/subassconvert.h
new file mode 100644
index 0000000000..e6a4425198
--- /dev/null
+++ b/sub/subassconvert.h
@@ -0,0 +1,27 @@
+/*
+ * Header for subtitles converter to SSA/ASS
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPLAYER_SUBASSCONVERT_H
+#define MPLAYER_SUBASSCONVERT_H
+
+void subassconvert_subrip(const char *orig, char *dest, int dest_buffer_size);
+void subassconvert_microdvd(const char *orig, char *dest, int dest_buffer_size);
+
+#endif
diff --git a/subreader.c b/subreader.c
index c9b3261c0e..10794b2ff5 100644
--- a/subreader.c
+++ b/subreader.c
@@ -33,6 +33,8 @@
#include "mp_msg.h"
#include "subreader.h"
#include "mpcommon.h"
+#include "sub/subassconvert.h"
+#include "options.h"
#include "stream/stream.h"
#include "libavutil/common.h"
#include "libavutil/avstring.h"
@@ -54,6 +56,12 @@ int flip_hebrew = 1; ///flip subtitles using fribidi
int fribidi_flip_commas = 0; ///flip comma when fribidi is used
#endif
+// Parameter struct for the format-specific readline functions
+struct readline_args {
+ int utf16;
+ struct MPOpts *opts;
+};
+
/* Maximal length of line of a subtitle */
#define LINE_LEN 1000
static float mpsub_position=0;
@@ -119,7 +127,10 @@ static void sami_add_line(subtitle *current, char *buffer, char **pos) {
*pos = buffer;
}
-static subtitle *sub_read_line_sami(stream_t* st, subtitle *current, int utf16) {
+static subtitle *sub_read_line_sami(stream_t* st, subtitle *current,
+ struct readline_args *args)
+{
+ int utf16 = args->utf16;
static char line[LINE_LEN+1];
static char *s = NULL, *slacktime_s;
char text[LINE_LEN+1], *p=NULL, *q;
@@ -278,7 +289,10 @@ static char *sub_readtext(char *source, char **dest) {
else return NULL; // last text field
}
-static subtitle *sub_read_line_microdvd(stream_t *st,subtitle *current, int utf16) {
+static subtitle *sub_read_line_microdvd(stream_t *st,subtitle *current,
+ struct readline_args *args)
+{
+ int utf16 = args->utf16;
char line[LINE_LEN+1];
char line2[LINE_LEN+1];
char *p, *next;
@@ -293,7 +307,11 @@ static subtitle *sub_read_line_microdvd(stream_t *st,subtitle *current, int utf1
"{%ld}{%ld}%[^\r\n]",
&(current->start), &(current->end), line2) < 3));
- p=line2;
+ if (args->opts->ass_enabled) {
+ subassconvert_microdvd(line2, line, LINE_LEN + 1);
+ p = line;
+ } else
+ p = line2;
next=p, i=0;
while ((next =sub_readtext (next, &(current->text[i])))) {
@@ -306,7 +324,10 @@ static subtitle *sub_read_line_microdvd(stream_t *st,subtitle *current, int utf1
return current;
}
-static subtitle *sub_read_line_mpl2(stream_t *st,subtitle *current, int utf16) {
+static subtitle *sub_read_line_mpl2(stream_t *st,subtitle *current,
+ struct readline_args *args)
+{
+ int utf16 = args->utf16;
char line[LINE_LEN+1];
char line2[LINE_LEN+1];
char *p, *next;
@@ -332,7 +353,10 @@ static subtitle *sub_read_line_mpl2(stream_t *st,subtitle *current, int utf16) {
return current;
}
-static subtitle *sub_read_line_subrip(stream_t* st, subtitle *current, int utf16) {
+static subtitle *sub_read_line_subrip(stream_t* st, subtitle *current,
+ struct readline_args *args)
+{
+ int utf16 = args->utf16;
char line[LINE_LEN+1];
int a1,a2,a3,a4,b1,b2,b3,b4;
char *p=NULL, *q=NULL;
@@ -362,12 +386,75 @@ static subtitle *sub_read_line_subrip(stream_t* st, subtitle *current, int utf16
return current;
}
-static subtitle *sub_read_line_subviewer(stream_t *st,subtitle *current, int utf16) {
+static subtitle *sub_ass_read_line_subviewer(stream_t *st, subtitle *current,
+ struct readline_args *args)
+{
+ int utf16 = args->utf16;
+ int a1, a2, a3, a4, b1, b2, b3, b4, j = 0;
+
+ while (!current->text[0]) {
+ char line[LINE_LEN + 1], full_line[LINE_LEN + 1], sep;
+ int i;
+
+ /* Parse SubRip header */
+ if (!stream_read_line(st, line, LINE_LEN, utf16))
+ return NULL;
+ if (sscanf(line, "%d:%d:%d%[,.:]%d --> %d:%d:%d%[,.:]%d",
+ &a1, &a2, &a3, &sep, &a4, &b1, &b2, &b3, &sep, &b4) < 10)
+ continue;
+
+ current->start = a1 * 360000 + a2 * 6000 + a3 * 100 + a4 / 10;
+ current->end = b1 * 360000 + b2 * 6000 + b3 * 100 + b4 / 10;
+
+ /* Concat lines */
+ full_line[0] = 0;
+ for (i = 0; i < SUB_MAX_TEXT; i++) {
+ int blank = 1, len = 0;
+ char *p;
+
+ if (!stream_read_line(st, line, LINE_LEN, utf16))
+ break;
+
+ for (p = line; *p != '\n' && *p != '\r' && *p; p++, len++)
+ if (*p != ' ' && *p != '\t')
+ blank = 0;
+
+ if (blank)
+ break;
+
+ *p = 0;
+
+ if (!(j + 1 + len < sizeof(full_line) - 1))
+ break;
+
+ if (j != 0)
+ full_line[j++] = '\n';
+ strcpy(&full_line[j], line);
+ j += len;
+ }
+
+ /* Use the ASS/SSA converter to transform the whole lines */
+ if (full_line[0]) {
+ char converted_line[LINE_LEN + 1];
+ subassconvert_subrip(full_line, converted_line, LINE_LEN + 1);
+ current->text[0] = strdup(converted_line);
+ current->lines = 1;
+ }
+ }
+ return current;
+}
+
+static subtitle *sub_read_line_subviewer(stream_t *st,subtitle *current,
+ struct readline_args *args)
+{
+ int utf16 = args->utf16;
char line[LINE_LEN+1];
int a1,a2,a3,a4,b1,b2,b3,b4;
char *p=NULL;
int i,len;
+ if (args->opts->ass_enabled)
+ return sub_ass_read_line_subviewer(st, current, args);
while (!current->text[0]) {
if (!stream_read_line (st, line, LINE_LEN, utf16)) return NULL;
if ((len=sscanf (line, "%d:%d:%d%[,.:]%d --> %d:%d:%d%[,.:]%d",&a1,&a2,&a3,(char *)&i,&a4,&b1,&b2,&b3,(char *)&i,&b4)) < 10)
@@ -414,7 +501,10 @@ static subtitle *sub_read_line_subviewer(stream_t *st,subtitle *current, int utf
return current;
}
-static subtitle *sub_read_line_subviewer2(stream_t *st,subtitle *current, int utf16) {
+static subtitle *sub_read_line_subviewer2(stream_t *st,subtitle *current,
+ struct readline_args *args)
+{
+ int utf16 = args->utf16;
char line[LINE_LEN+1];
int a1,a2,a3,a4;
char *p=NULL;
@@ -447,7 +537,10 @@ static subtitle *sub_read_line_subviewer2(stream_t *st,subtitle *current, int ut
}
-static subtitle *sub_read_line_vplayer(stream_t *st,subtitle *current, int utf16) {
+static subtitle *sub_read_line_vplayer(stream_t *st,subtitle *current,
+ struct readline_args *args)
+{
+ int utf16 = args->utf16;
char line[LINE_LEN+1];
int a1,a2,a3;
char *p=NULL, *next,separator;
@@ -493,7 +586,11 @@ static subtitle *sub_read_line_vplayer(stream_t *st,subtitle *current, int utf16
return current;
}
-static subtitle *sub_read_line_rt(stream_t *st,subtitle *current, int utf16) {
+static subtitle *sub_read_line_rt(stream_t *st,subtitle *current,
+ struct readline_args *args)
+{
+ int utf16 = args->utf16;
+
//TODO: This format uses quite rich (sub/super)set of xhtml
// I couldn't check it since DTD is not included.
// WARNING: full XML parses can be required for proper parsing
@@ -543,7 +640,9 @@ static subtitle *sub_read_line_rt(stream_t *st,subtitle *current, int utf16) {
return current;
}
-static subtitle *sub_read_line_ssa(stream_t *st,subtitle *current, int utf16) {
+static subtitle *sub_read_line_ssa(stream_t *st,subtitle *current,
+ struct readline_args *args)
+{
/*
* Sub Station Alpha v4 (and v2?) scripts have 9 commas before subtitle
* other Sub Station Alpha scripts have only 8 commas before subtitle
@@ -553,6 +652,7 @@ static subtitle *sub_read_line_ssa(stream_t *st,subtitle *current, int utf16) {
* http://www.scriptclub.org is a good place to find more examples
* http://www.eswat.demon.co.uk is where the SSA specs can be found
*/
+ int utf16 = args->utf16;
int comma;
static int max_comma = 32; /* let's use 32 for the case that the */
/* amount of commas increase with newer SSA versions */
@@ -645,7 +745,10 @@ static void sub_pp_ssa(subtitle *sub) {
*
* by set, based on code by szabi (dunnowhat sub format ;-)
*/
-static subtitle *sub_read_line_pjs(stream_t *st,subtitle *current, int utf16) {
+static subtitle *sub_read_line_pjs(stream_t *st,subtitle *current,
+ struct readline_args *args)
+{
+ int utf16 = args->utf16;
char line[LINE_LEN+1];
char text[LINE_LEN+1], *s, *d;
@@ -683,7 +786,10 @@ static subtitle *sub_read_line_pjs(stream_t *st,subtitle *current, int utf16) {
return current;
}
-static subtitle *sub_read_line_mpsub(stream_t *st, subtitle *current, int utf16) {
+static subtitle *sub_read_line_mpsub(stream_t *st, subtitle *current,
+ struct readline_args *args)
+{
+ int utf16 = args->utf16;
char line[LINE_LEN+1];
float a,b;
int num=0;
@@ -728,7 +834,10 @@ static subtitle *sub_read_line_mpsub(stream_t *st, subtitle *current, int utf16)
subtitle *previous_aqt_sub = NULL;
#endif
-static subtitle *sub_read_line_aqt(stream_t *st,subtitle *current, int utf16) {
+static subtitle *sub_read_line_aqt(stream_t *st,subtitle *current,
+ struct readline_args *args)
+{
+ int utf16 = args->utf16;
char line[LINE_LEN+1];
char *next;
int i;
@@ -785,7 +894,10 @@ static subtitle *sub_read_line_aqt(stream_t *st,subtitle *current, int utf16) {
subtitle *previous_subrip09_sub = NULL;
#endif
-static subtitle *sub_read_line_subrip09(stream_t *st,subtitle *current, int utf16) {
+static subtitle *sub_read_line_subrip09(stream_t *st,subtitle *current,
+ struct readline_args *args)
+{
+ int utf16 = args->utf16;
char line[LINE_LEN+1];
int a1,a2,a3;
char * next=NULL;
@@ -837,8 +949,10 @@ static subtitle *sub_read_line_subrip09(stream_t *st,subtitle *current, int utf1
return current;
}
-static subtitle *sub_read_line_jacosub(stream_t* st, subtitle * current, int utf16)
+static subtitle *sub_read_line_jacosub(stream_t* st, subtitle * current,
+ struct readline_args *args)
{
+ int utf16 = args->utf16;
char line1[LINE_LEN], line2[LINE_LEN], directive[LINE_LEN], *p, *q;
unsigned a1, a2, a3, a4, b1, b2, b3, b4, comment = 0;
static unsigned jacoTimeres = 30;
@@ -1285,7 +1399,8 @@ static void adjust_subs_time(subtitle* sub, float subtime, float fps, int block,
}
struct subreader {
- subtitle * (*read)(stream_t *st,subtitle *dest,int utf16);
+ subtitle * (*read)(stream_t *st, subtitle *dest,
+ struct readline_args *args);
void (*post)(subtitle *dest);
const char *name;
};
@@ -1351,7 +1466,8 @@ const char* guess_cp(stream_t *st, const char *preferred_language, const char *f
#undef MAX_GUESS_BUFFER_SIZE
#endif
-sub_data* sub_read_file (char *filename, float fps) {
+sub_data* sub_read_file(char *filename, float fps, struct MPOpts *opts)
+{
int utf16;
stream_t* fd;
int n_max, n_first, i, j, sub_first, sub_orig;
@@ -1436,7 +1552,7 @@ sub_data* sub_read_file (char *filename, float fps) {
sub = &first[sub_num];
#endif
memset(sub, '\0', sizeof(subtitle));
- sub=srp->read(fd,sub,utf16);
+ sub=srp->read(fd, sub, &(struct readline_args){utf16, opts});
if(!sub) break; // EOF
#ifdef CONFIG_ICONV
if ((sub!=ERR) && sub_utf8 == 2) sub=subcp_recode(sub);
diff --git a/subreader.h b/subreader.h
index b1aa07421b..9c7465d71a 100644
--- a/subreader.h
+++ b/subreader.h
@@ -20,6 +20,7 @@
#define MPLAYER_SUBREADER_H
#include <stdio.h>
+#include <stdbool.h>
#include "config.h"
@@ -84,7 +85,8 @@ extern char *fribidi_charset;
extern int flip_hebrew;
extern int fribidi_flip_commas;
-sub_data* sub_read_file (char *filename, float pts);
+struct MPOpts;
+sub_data* sub_read_file (char *filename, float pts, struct MPOpts *opts);
subtitle* subcp_recode (subtitle *sub);
// enca_fd is the file enca uses to determine the codepage.
// setting to NULL disables enca.