[MPlayer-dev-eng] [PATCH] Tags support for SubRip and MicroDVD subtitles
ubitux
ubitux at gmail.com
Tue May 18 23:54:36 CEST 2010
Hi,
According to what was said on IRC, and the feedback I got here, here is a
new version of the patch, with those changes:
* Pointed by Uoti Urpala *
- [SubRip] stack pointer size check incorrect,
- [SubRip] return the structure pointer instead of field in the function to get the
last matching tag. This avoid cast & ugliness,
- cosmetics: switch/case alignment.
* Pointed by Kazuo Teramoto *
- [SubRip] Applied (with some minor changes) the color patch.
* Personnal improvements *
- [SubRip] Handle multilines tags. I've added a new function to get the
old one clear in subreader.c,
- Remove "nested tags" handle for persistent tags since it's totally
useless and slower.
Finally, a SubRip subtitle like this:
This <font color="#112233" size="6" face="Arial">could be
the <font size="35" face="Times New Roman">m<font color="#000000">o</font>st</font>
difficult thing to</font>implement.
<font color="blue">Qu’y a-t-il <i>dans un <s>nom</s> ?</i>
Will become:
This {\c&H332211&}{\fs6}{\fnArial}could be\Nthe {\fs35}{\fnTimes New Roman}m{\c&H000000&}o{\c&H332211&}st{\fs6}{\fnArial}\Ndifficult thing to{\fs}{\c}{\fn}implement.\N{\c&HFF0000&}Qu’y a-t-il {\i1}dans un {\s1}nom{\s0} ?{\i0}
I was looking for implementing the SubRip coordinates, but I just don't
understand how it can be handled:
X1:100 X2:100 Y1:100 Y2:100
Why two coordinates? I just don't know. If anyone want me to implement it,
just tell me how it works.
Once again, this mail is sent with both SVN and Git version, and I still
hope for new feedback/reviews.
Best regards,
--
ubitux
-------------- next part --------------
Index: Makefile
===================================================================
--- Makefile (revision 31179)
+++ Makefile (working copy)
@@ -344,6 +344,7 @@
playtreeparser.c \
spudec.c \
sub_cc.c \
+ subassconvert.c \
subopt-helper.c \
subreader.c \
vobsub.c \
Index: subassconvert.c
===================================================================
--- subassconvert.c (revision 0)
+++ subassconvert.c (revision 0)
@@ -0,0 +1,579 @@
+/*
+ * 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 "subreader.h"
+#include "subassconvert.h"
+
+#define SUB_MAX_FONTSTRING_LEN 32
+
+static int insert_text_in_subdest(char *dst, int *j, char *src, int srclen)
+{
+ if (!(*j + srclen + 1 < LINE_LEN))
+ return -1;
+ strcpy(&dst[*j], src);
+ *j += srclen;
+ return 0;
+}
+
+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.
+ *
+ */
+
+typedef struct {
+ int field;
+ long int size;
+ uint32_t color;
+ char face[SUB_MAX_FONTSTRING_LEN];
+} font_tag_type;
+
+#define SUBRIP_FIELD_FONT_SIZE (1 << 0)
+#define SUBRIP_FIELD_FONT_COLOR (1 << 1)
+#define SUBRIP_FIELD_FONT_FACE (1 << 2)
+
+static const struct {
+ char *from;
+ char *to;
+} subrip_basic_tags[] = {
+ {"<i>", "{\\i1}"}, {"</i>", "{\\i0}"},
+ {"<b>", "{\\b1}"}, {"</b>", "{\\b0}"},
+ {"<u>", "{\\u1}"}, {"</u>", "{\\u0}"},
+ {"<s>", "{\\s1}"}, {"</s>", "{\\s0}"},
+};
+
+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
+
+static font_tag_type *subrip_get_last_matching_tag(font_tag_type *fstack, int sp, int flag)
+{
+ while (sp > 0) {
+ font_tag_type *tag;
+
+ sp--;
+ tag = &fstack[sp];
+ if (tag->field & flag)
+ return tag;
+ }
+ return NULL;
+}
+
+void subassconvert_subrip(char *line)
+{
+ char new_line[LINE_LEN + 1];
+ char *start_line = line;
+ int j = 0;
+ font_tag_type font_stack[SUBRIP_MAX_STACKED_FONT_TAGS];
+ int sp = 0;
+
+ while (*line && j < sizeof(new_line) - 1) {
+ int n, match = 0;
+
+ /* Basic tags */
+ for (n = 0; n < (int)(sizeof(subrip_basic_tags) / sizeof(*subrip_basic_tags)); n++) {
+ int from_len = strlen(subrip_basic_tags[n].from);
+ int to_len = strlen(subrip_basic_tags[n].to);
+
+ if (strncmp(line, subrip_basic_tags[n].from, from_len) == 0) {
+ insert_text_in_subdest(new_line, &j, subrip_basic_tags[n].to, to_len);
+ line += from_len;
+ match = 1;
+ break;
+ }
+ }
+
+ if (!match) {
+
+ /* Closing font tag */
+ if (strncmp(line, "</font>", 7) == 0) {
+ line += 7;
+ match = 1;
+
+ if (sp > 0) {
+ font_tag_type *tag;
+
+ sp--;
+ tag = &font_stack[sp];
+
+ if (tag->field & SUBRIP_FIELD_FONT_SIZE) {
+ font_tag_type *last_tag = subrip_get_last_matching_tag(font_stack, sp, SUBRIP_FIELD_FONT_SIZE);
+
+ if (last_tag == NULL) {
+ insert_text_in_subdest(new_line, &j, "{\\fs}", sizeof("{\\fs}") - 1);
+ } else {
+ char stag[4 + sizeof(last_tag->size) + 2];
+
+ sprintf(stag, "{\\fs%ld}", last_tag->size);
+ insert_text_in_subdest(new_line, &j, stag, strlen(stag));
+ }
+ }
+
+ if (tag->field & SUBRIP_FIELD_FONT_COLOR) {
+ font_tag_type *last_tag = subrip_get_last_matching_tag(font_stack, sp, SUBRIP_FIELD_FONT_COLOR);
+
+ if (last_tag == NULL) {
+ insert_text_in_subdest(new_line, &j, "{\\c}", sizeof("{\\c}") - 1);
+ } else {
+ char ctag[] = "{\\c&Hbbggrr&}";
+
+ sprintf(ctag, "{\\c&H%06X&}", last_tag->color);
+ insert_text_in_subdest(new_line, &j, ctag, sizeof(ctag) - 1);
+ }
+ }
+
+ if (tag->field & SUBRIP_FIELD_FONT_FACE) {
+ font_tag_type *last_tag = subrip_get_last_matching_tag(font_stack, sp, SUBRIP_FIELD_FONT_FACE);
+
+ if (last_tag == NULL) {
+ insert_text_in_subdest(new_line, &j, "{\\fn}", sizeof("{\\fn}") - 1);
+ } else {
+ char ftag[4 + sizeof(last_tag->face) + 2];
+ int len = sprintf(ftag, "{\\fn%s}", last_tag->face);
+
+ insert_text_in_subdest(new_line, &j, ftag, len);
+ }
+ }
+ }
+
+ /* Opening font tag */
+ } else if (strncmp(line, "<font ", 6) == 0) {
+ char *potential_font_tag_start = line;
+ int j_backup = j;
+ font_tag_type *tag = &font_stack[sp];
+
+ if (sp < sizeof(font_stack) / sizeof(*font_stack)) {
+ tag->field = 0;
+ line += 6;
+
+ while (*line && *line != '>') {
+
+ /* Size attribute */
+ if (strncmp(line, "size=\"", 6) == 0) {
+ char stag[4 + sizeof(tag->size) + 2];
+ int len;
+
+ line += 6;
+ tag->size = strtol(line, &line, 10);
+ if (*line != '"')
+ break;
+ len = sprintf(stag, "{\\fs%ld}", tag->size);
+ insert_text_in_subdest(new_line, &j, stag, len);
+ tag->field |= SUBRIP_FIELD_FONT_SIZE;
+
+ /* Color attribute */
+ } else if (strncmp(line, "color=\"", 7) == 0) {
+ char ctag[] = "{\\c&Hbbggrr&}";
+
+ line += 7;
+
+ /* #RRGGBB format */
+ if (*line == '#') {
+ line++;
+ tag->color = (uint32_t)strtol(line, &line, 16) & 0x00ffffff;
+ if (*line != '"')
+ break;
+ tag->color = ((tag->color & 0xff) << 16) | (tag->color & 0xff00) | ((tag->color & 0xff0000) >> 16);
+
+ /* Standard web colors */
+ } else {
+ int i, len = indexof(line, '"');
+
+ if (len <= 0)
+ break;
+ tag->color = 0x00ffffff; // Let's put some white in case we didn't find any matching colors
+
+ for (i = 0; i < sizeof(subrip_web_colors) / sizeof(*subrip_web_colors); i++) {
+ if(strncasecmp(line, subrip_web_colors[i].s, len) == 0) {
+ tag->color = subrip_web_colors[i].v;
+ break;
+ }
+ }
+ }
+ sprintf(ctag, "{\\c&H%06X&}", tag->color);
+ insert_text_in_subdest(new_line, &j, ctag, sizeof(ctag) - 1);
+ tag->field |= SUBRIP_FIELD_FONT_COLOR;
+
+ /* Font face attribute */
+ } else if (strncmp(line, "face=\"", 6) == 0) {
+ int i = 0, len;
+ char ftag[4 + sizeof(tag->face) + 2];
+
+ line += 6;
+ while (*line && *line != '"' && i < sizeof(tag->face) - 1)
+ tag->face[i++] = *line++;
+ tag->face[i] = 0;
+ if (*line != '"')
+ break;
+ len = sprintf(ftag, "{\\fn%s}", tag->face);
+ insert_text_in_subdest(new_line, &j, ftag, len);
+ tag->field |= SUBRIP_FIELD_FONT_FACE;
+ }
+
+ line++;
+ }
+
+ if (!tag->field || *line != '>') { /* Not valid font tag */
+ line = potential_font_tag_start;
+ j = j_backup;
+ } else {
+ match = 1;
+ sp++;
+ line++;
+ }
+ }
+ }
+ }
+
+ /* Normal text */
+ if (!match)
+ new_line[j++] = *line++;
+ }
+ new_line[j] = 0;
+ strcpy(start_line, new_line);
+}
+
+
+/*
+ * MicroDVD
+ *
+ * Based on the specifications found here:
+ * https://trac.videolan.org/vlc/ticket/1825#comment:6
+ */
+
+typedef struct {
+ char key;
+ int persistent;
+ uint32_t data1;
+ uint32_t data2;
+ char data_string[SUB_MAX_FONTSTRING_LEN];
+} microdvd_tag_type;
+
+#define MICRODVD_DEAD_TAG {MICRODVD_TAG_DISABLED, MICRODVD_PERSISTENT_OFF, 0, 0, ""}
+
+#define MICRODVD_PERSISTENT_OFF 0
+#define MICRODVD_PERSISTENT_ON 1
+#define MICRODVD_PERSISTENT_OPENED 2
+
+#define MICRODVD_TAGS "cfshyYpo" /* Color, Font, Size, cHarset, stYle, Position, cOordinate */
+
+static void microdvd_set_tag(microdvd_tag_type *tags, microdvd_tag_type tag)
+{
+ int tag_index = indexof(MICRODVD_TAGS, tag.key);
+
+ if (tag_index < 0)
+ return;
+ memcpy(&tags[tag_index], &tag, sizeof(tag));
+}
+
+#define MICRODVD_STYLES "ibus" /* italic, bold, underline, strike-through */
+#define MICRODVD_TAG_DISABLED '.'
+
+static char *microdvd_load_tags(microdvd_tag_type *tags, char *s)
+{
+ while (*s == '{') {
+ char *start = s;
+ char tag_char = *(s + 1);
+ microdvd_tag_type tag = MICRODVD_DEAD_TAG;
+
+ 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;
+ tag.key = tag_char; /* We must distinct persistent and non-persistent styles
+ to handle that kind of style tags: {y:ib}{Y:us} */
+ break;
+
+ /* Color */
+ case 'C':
+ tag.persistent = MICRODVD_PERSISTENT_ON;
+ case 'c':
+ tag.data1 = (uint32_t)strtol(s, &s, 16) & 0x00ffffff;
+ if (*s != '}')
+ break;
+ tag.key = 'c';
+ break;
+
+ /* Font name */
+ case 'F':
+ tag.persistent = MICRODVD_PERSISTENT_ON;
+ case 'f':
+ {
+ int i = 0;
+
+ while (*s && *s != '}' && i < sizeof(tag.data_string))
+ tag.data_string[i++] = *s++;
+ if (*s != '}')
+ break;
+ tag.key = 'f';
+ break;
+ }
+
+ /* Font size */
+ case 'S':
+ tag.persistent = MICRODVD_PERSISTENT_ON;
+ case 's':
+ {
+ tag.data1 = (uint32_t)strtol(s, &s, 10);
+ if (*s != '}' || tag.data1 > 72)
+ break;
+ tag.key = 's';
+ break;
+ }
+
+ /* Charset */
+ case 'H':
+ {
+ int i = 0;
+
+ //TODO: not yet handled, just parsed.
+ while (*s && *s != '}' && i < sizeof(tag.data_string))
+ tag.data_string[i++] = *s++;
+ if (*s != '}')
+ break;
+ 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 = (uint32_t)strtol(s, &s, 10);
+ if (*s != ',')
+ break;
+ s++;
+ tag.data2 = (uint32_t)strtol(s, &s, 10);
+ if (*s != '}')
+ break;
+ tag.key = 'o';
+ break;
+
+ default: /* Unknown tag, we considere it's text */
+ break;
+ }
+
+ if (tag.key == MICRODVD_TAG_DISABLED)
+ return start;
+
+ microdvd_set_tag(tags, tag);
+ s++;
+ }
+ return s;
+}
+
+static void microdvd_open_tags(char *new_line, int *j, microdvd_tag_type *tags)
+{
+ int i;
+
+ for (i = 0; i < sizeof(MICRODVD_TAGS) - 1; i++) {
+ if (tags[i].persistent == MICRODVD_PERSISTENT_OPENED)
+ continue;
+ switch (tags[i].key) {
+
+ case 'Y':
+ case 'y':
+ {
+ int style_index = 0;
+ char ytag[] = "{\\.1}";
+
+ while (style_index < sizeof(MICRODVD_STYLES) - 1) {
+ int style_mask = (1 << style_index);
+
+ if (tags[i].data1 & style_mask) {
+ ytag[2] = MICRODVD_STYLES[style_index];
+ insert_text_in_subdest(new_line, j, ytag, sizeof(ytag) - 1);
+ }
+ style_index++;
+ }
+ break;
+ }
+
+ case 'c':
+ {
+ char ctag[] = "{\\c&Hbbggrr&}";
+
+ sprintf(ctag, "{\\c&H%06X&}", tags[i].data1);
+ insert_text_in_subdest(new_line, j, ctag, sizeof(ctag) - 1);
+ break;
+ }
+
+ case 'f':
+ {
+ char ftag[4 + sizeof(tags[0].data_string) + 2];
+ int len = sprintf(ftag, "{\\fn%s}", tags[i].data_string);
+
+ insert_text_in_subdest(new_line, j, ftag, len);
+ break;
+ }
+
+ case 's':
+ {
+ char stag[4 + 2 + 2];
+ int len = sprintf(stag, "{\\fs%d}", tags[i].data1);
+
+ insert_text_in_subdest(new_line, j, stag, len);
+ break;
+ }
+
+ case 'p':
+ if (tags[i].data1 == 0)
+ insert_text_in_subdest(new_line, j, "{\\an8}", sizeof("{\\an8}") - 1);
+ break;
+
+ case 'o':
+ {
+ char otag[5 + sizeof(tags[0].data1) * 2 + 3];
+ int len = sprintf(otag, "{\\pos(%d,%d)}", tags[i].data1, tags[i].data2);
+
+ insert_text_in_subdest(new_line, j, otag, len);
+ break;
+ }
+
+ default:
+ break;
+ }
+ if (tags[i].persistent == MICRODVD_PERSISTENT_ON)
+ tags[i].persistent = MICRODVD_PERSISTENT_OPENED;
+ }
+}
+
+static void microdvd_close_no_persistent_tags(char *new_line, int *j, microdvd_tag_type *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':
+ {
+ int style_index = sizeof(MICRODVD_STYLES) - 2;
+ char ctag[] = "{\\.0}";
+
+ while (style_index >= 0) {
+ int style_mask = (1 << style_index);
+
+ if (tags[i].data1 & style_mask) {
+ ctag[2] = MICRODVD_STYLES[style_index];
+ insert_text_in_subdest(new_line, j, ctag, sizeof(ctag) - 1);
+ }
+ style_index--;
+ }
+ break;
+ }
+
+ case 'c':
+ insert_text_in_subdest(new_line, j, "{\\c}", sizeof("{\\c}") - 1);
+ break;
+
+ case 'f':
+ insert_text_in_subdest(new_line, j, "{\\fn}", sizeof("{\\fn}") - 1);
+ break;
+
+ case 's':
+ insert_text_in_subdest(new_line, j, "{\\fs}", sizeof("{\\fs}") - 1);
+ break;
+
+ default:
+ break;
+ }
+ tags[i].key = MICRODVD_TAG_DISABLED;
+ }
+}
+
+void subassconvert_microdvd(char *line)
+{
+ int i, j = 0;
+ char new_line[LINE_LEN + 1];
+ char *line_start = line;
+ microdvd_tag_type tags[sizeof(MICRODVD_TAGS) - 1];
+ const microdvd_tag_type dead_tag = MICRODVD_DEAD_TAG;
+
+ for (i = 0; MICRODVD_TAGS[i]; i++)
+ memcpy(&tags[i], &dead_tag, sizeof(dead_tag));
+
+ while (*line) {
+ line = microdvd_load_tags(tags, line);
+ microdvd_open_tags(new_line, &j, tags);
+
+ while (*line && *line != '|')
+ new_line[j++] = *line++;
+
+ if (*line == '|') {
+ microdvd_close_no_persistent_tags(new_line, &j, tags);
+ insert_text_in_subdest(new_line, &j, "\\N", sizeof("\\N") - 1);
+ line++;
+ }
+ }
+
+ new_line[j] = 0;
+ strcpy(line_start, new_line);
+}
Index: subassconvert.h
===================================================================
--- subassconvert.h (revision 0)
+++ subassconvert.h (revision 0)
@@ -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(char *line);
+void subassconvert_microdvd(char *line);
+
+#endif
Index: subreader.c
===================================================================
--- subreader.c (revision 31179)
+++ subreader.c (working copy)
@@ -36,6 +36,9 @@
#include "libavutil/common.h"
#include "libavutil/avstring.h"
+#include "libass/ass_mp.h"
+#include "subassconvert.h"
+
#ifdef CONFIG_ENCA
#include <enca.h>
#endif
@@ -55,8 +58,6 @@
extern char* dvdsub_lang;
-/* Maximal length of line of a subtitle */
-#define LINE_LEN 1000
static float mpsub_position=0;
static float mpsub_multiplier=1.;
static int sub_slacktime = 20000; //20 sec
@@ -291,6 +292,9 @@
p=line2;
+ if (ass_enabled)
+ subassconvert_microdvd(p);
+
next=p, i=0;
while ((next =sub_readtext (next, &(current->text[i])))) {
if (current->text[i]==ERR) {return ERR;}
@@ -358,12 +362,78 @@
return current;
}
+static subtitle *sub_ass_read_line_subviewer(stream_t *st, subtitle *current, int 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++] = '\\';
+ 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]) {
+ int len;
+
+ subassconvert_subrip(full_line);
+ len = strlen(full_line);
+ current->lines = 1;
+ current->text[0] = malloc(len + 1);
+ if (!current->text[0])
+ return ERR;
+ strncpy(current->text[0], full_line, len);
+ current->text[0][len] = '\0';
+ }
+ }
+ return current;
+}
+
static subtitle *sub_read_line_subviewer(stream_t *st,subtitle *current, int utf16) {
char line[LINE_LEN+1];
int a1,a2,a3,a4,b1,b2,b3,b4;
char *p=NULL;
int i,len;
+ if (ass_enabled)
+ return sub_ass_read_line_subviewer(st, current, utf16);
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)
Index: subreader.h
===================================================================
--- subreader.h (revision 31179)
+++ subreader.h (working copy)
@@ -44,6 +44,9 @@
#define SUB_JACOSUB 12
#define SUB_MPL2 13
+/* Maximal length of line of a subtitle */
+#define LINE_LEN 1000
+
// One of the SUB_* constant above
extern int sub_format;
-------------- next part --------------
diff --git a/Makefile b/Makefile
index d9cb34d..68f399e 100644
--- a/Makefile
+++ b/Makefile
@@ -348,6 +348,7 @@ SRCS_COMMON = asxparser.c \
playtreeparser.c \
spudec.c \
sub_cc.c \
+ subassconvert.c \
subopt-helper.c \
subreader.c \
talloc.c \
diff --git a/mencoder.c b/mencoder.c
index dc3d870..f7d08b4 100644
--- a/mencoder.c
+++ b/mencoder.c
@@ -346,7 +346,7 @@ static void add_subtitles(char *filename, float fps, int silent)
if (!filename) return;
- subd = sub_read_file(filename, fps);
+ subd = sub_read_file(filename, fps, &opts);
#ifdef CONFIG_ASS
if (opts.ass_enabled)
#ifdef CONFIG_ICONV
diff --git a/mplayer.c b/mplayer.c
index beb1af5..356f6d1 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -1119,7 +1119,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) {
@@ -1130,7 +1130,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/subassconvert.c b/subassconvert.c
new file mode 100644
index 0000000..978d9f4
--- /dev/null
+++ b/subassconvert.c
@@ -0,0 +1,579 @@
+/*
+ * 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 "subreader.h"
+#include "subassconvert.h"
+
+#define SUB_MAX_FONTSTRING_LEN 32
+
+static int insert_text_in_subdest(char *dst, int *j, char *src, int srclen)
+{
+ if (!(*j + srclen + 1 < LINE_LEN))
+ return -1;
+ strcpy(&dst[*j], src);
+ *j += srclen;
+ return 0;
+}
+
+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.
+ *
+ */
+
+typedef struct {
+ int field;
+ long int size;
+ uint32_t color;
+ char face[SUB_MAX_FONTSTRING_LEN];
+} font_tag_type;
+
+#define SUBRIP_FIELD_FONT_SIZE (1 << 0)
+#define SUBRIP_FIELD_FONT_COLOR (1 << 1)
+#define SUBRIP_FIELD_FONT_FACE (1 << 2)
+
+static const struct {
+ char *from;
+ char *to;
+} subrip_basic_tags[] = {
+ {"<i>", "{\\i1}"}, {"</i>", "{\\i0}"},
+ {"<b>", "{\\b1}"}, {"</b>", "{\\b0}"},
+ {"<u>", "{\\u1}"}, {"</u>", "{\\u0}"},
+ {"<s>", "{\\s1}"}, {"</s>", "{\\s0}"},
+};
+
+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
+
+static font_tag_type *subrip_get_last_matching_tag(font_tag_type *fstack, int sp, int flag)
+{
+ while (sp > 0) {
+ font_tag_type *tag;
+
+ sp--;
+ tag = &fstack[sp];
+ if (tag->field & flag)
+ return tag;
+ }
+ return NULL;
+}
+
+void subassconvert_subrip(char *line)
+{
+ char new_line[LINE_LEN + 1];
+ char *start_line = line;
+ int j = 0;
+ font_tag_type font_stack[SUBRIP_MAX_STACKED_FONT_TAGS];
+ int sp = 0;
+
+ while (*line && j < sizeof(new_line) - 1) {
+ int n, match = 0;
+
+ /* Basic tags */
+ for (n = 0; n < (int)(sizeof(subrip_basic_tags) / sizeof(*subrip_basic_tags)); n++) {
+ int from_len = strlen(subrip_basic_tags[n].from);
+ int to_len = strlen(subrip_basic_tags[n].to);
+
+ if (strncmp(line, subrip_basic_tags[n].from, from_len) == 0) {
+ insert_text_in_subdest(new_line, &j, subrip_basic_tags[n].to, to_len);
+ line += from_len;
+ match = 1;
+ break;
+ }
+ }
+
+ if (!match) {
+
+ /* Closing font tag */
+ if (strncmp(line, "</font>", 7) == 0) {
+ line += 7;
+ match = 1;
+
+ if (sp > 0) {
+ font_tag_type *tag;
+
+ sp--;
+ tag = &font_stack[sp];
+
+ if (tag->field & SUBRIP_FIELD_FONT_SIZE) {
+ font_tag_type *last_tag = subrip_get_last_matching_tag(font_stack, sp, SUBRIP_FIELD_FONT_SIZE);
+
+ if (last_tag == NULL) {
+ insert_text_in_subdest(new_line, &j, "{\\fs}", sizeof("{\\fs}") - 1);
+ } else {
+ char stag[4 + sizeof(last_tag->size) + 2];
+
+ sprintf(stag, "{\\fs%ld}", last_tag->size);
+ insert_text_in_subdest(new_line, &j, stag, strlen(stag));
+ }
+ }
+
+ if (tag->field & SUBRIP_FIELD_FONT_COLOR) {
+ font_tag_type *last_tag = subrip_get_last_matching_tag(font_stack, sp, SUBRIP_FIELD_FONT_COLOR);
+
+ if (last_tag == NULL) {
+ insert_text_in_subdest(new_line, &j, "{\\c}", sizeof("{\\c}") - 1);
+ } else {
+ char ctag[] = "{\\c&Hbbggrr&}";
+
+ sprintf(ctag, "{\\c&H%06X&}", last_tag->color);
+ insert_text_in_subdest(new_line, &j, ctag, sizeof(ctag) - 1);
+ }
+ }
+
+ if (tag->field & SUBRIP_FIELD_FONT_FACE) {
+ font_tag_type *last_tag = subrip_get_last_matching_tag(font_stack, sp, SUBRIP_FIELD_FONT_FACE);
+
+ if (last_tag == NULL) {
+ insert_text_in_subdest(new_line, &j, "{\\fn}", sizeof("{\\fn}") - 1);
+ } else {
+ char ftag[4 + sizeof(last_tag->face) + 2];
+ int len = sprintf(ftag, "{\\fn%s}", last_tag->face);
+
+ insert_text_in_subdest(new_line, &j, ftag, len);
+ }
+ }
+ }
+
+ /* Opening font tag */
+ } else if (strncmp(line, "<font ", 6) == 0) {
+ char *potential_font_tag_start = line;
+ int j_backup = j;
+ font_tag_type *tag = &font_stack[sp];
+
+ if (sp < sizeof(font_stack) / sizeof(*font_stack)) {
+ tag->field = 0;
+ line += 6;
+
+ while (*line && *line != '>') {
+
+ /* Size attribute */
+ if (strncmp(line, "size=\"", 6) == 0) {
+ char stag[4 + sizeof(tag->size) + 2];
+ int len;
+
+ line += 6;
+ tag->size = strtol(line, &line, 10);
+ if (*line != '"')
+ break;
+ len = sprintf(stag, "{\\fs%ld}", tag->size);
+ insert_text_in_subdest(new_line, &j, stag, len);
+ tag->field |= SUBRIP_FIELD_FONT_SIZE;
+
+ /* Color attribute */
+ } else if (strncmp(line, "color=\"", 7) == 0) {
+ char ctag[] = "{\\c&Hbbggrr&}";
+
+ line += 7;
+
+ /* #RRGGBB format */
+ if (*line == '#') {
+ line++;
+ tag->color = (uint32_t)strtol(line, &line, 16) & 0x00ffffff;
+ if (*line != '"')
+ break;
+ tag->color = ((tag->color & 0xff) << 16) | (tag->color & 0xff00) | ((tag->color & 0xff0000) >> 16);
+
+ /* Standard web colors */
+ } else {
+ int i, len = indexof(line, '"');
+
+ if (len <= 0)
+ break;
+ tag->color = 0x00ffffff; // Let's put some white in case we didn't find any matching colors
+
+ for (i = 0; i < sizeof(subrip_web_colors) / sizeof(*subrip_web_colors); i++) {
+ if(strncasecmp(line, subrip_web_colors[i].s, len) == 0) {
+ tag->color = subrip_web_colors[i].v;
+ break;
+ }
+ }
+ }
+ sprintf(ctag, "{\\c&H%06X&}", tag->color);
+ insert_text_in_subdest(new_line, &j, ctag, sizeof(ctag) - 1);
+ tag->field |= SUBRIP_FIELD_FONT_COLOR;
+
+ /* Font face attribute */
+ } else if (strncmp(line, "face=\"", 6) == 0) {
+ int i = 0, len;
+ char ftag[4 + sizeof(tag->face) + 2];
+
+ line += 6;
+ while (*line && *line != '"' && i < sizeof(tag->face) - 1)
+ tag->face[i++] = *line++;
+ tag->face[i] = 0;
+ if (*line != '"')
+ break;
+ len = sprintf(ftag, "{\\fn%s}", tag->face);
+ insert_text_in_subdest(new_line, &j, ftag, len);
+ tag->field |= SUBRIP_FIELD_FONT_FACE;
+ }
+
+ line++;
+ }
+
+ if (!tag->field || *line != '>') { /* Not valid font tag */
+ line = potential_font_tag_start;
+ j = j_backup;
+ } else {
+ match = 1;
+ sp++;
+ line++;
+ }
+ }
+ }
+ }
+
+ /* Normal text */
+ if (!match)
+ new_line[j++] = *line++;
+ }
+ new_line[j] = 0;
+ strcpy(start_line, new_line);
+}
+
+
+/*
+ * MicroDVD
+ *
+ * Based on the specifications found here:
+ * https://trac.videolan.org/vlc/ticket/1825#comment:6
+ */
+
+typedef struct {
+ char key;
+ int persistent;
+ uint32_t data1;
+ uint32_t data2;
+ char data_string[SUB_MAX_FONTSTRING_LEN];
+} microdvd_tag_type;
+
+#define MICRODVD_DEAD_TAG {MICRODVD_TAG_DISABLED, MICRODVD_PERSISTENT_OFF, 0, 0, ""}
+
+#define MICRODVD_PERSISTENT_OFF 0
+#define MICRODVD_PERSISTENT_ON 1
+#define MICRODVD_PERSISTENT_OPENED 2
+
+#define MICRODVD_TAGS "cfshyYpo" /* Color, Font, Size, cHarset, stYle, Position, cOordinate */
+
+static void microdvd_set_tag(microdvd_tag_type *tags, microdvd_tag_type tag)
+{
+ int tag_index = indexof(MICRODVD_TAGS, tag.key);
+
+ if (tag_index < 0)
+ return;
+ memcpy(&tags[tag_index], &tag, sizeof(tag));
+}
+
+#define MICRODVD_STYLES "ibus" /* italic, bold, underline, strike-through */
+#define MICRODVD_TAG_DISABLED '.'
+
+static char *microdvd_load_tags(microdvd_tag_type *tags, char *s)
+{
+ while (*s == '{') {
+ char *start = s;
+ char tag_char = *(s + 1);
+ microdvd_tag_type tag = MICRODVD_DEAD_TAG;
+
+ 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;
+ tag.key = tag_char; /* We must distinct persistent and non-persistent styles
+ to handle that kind of style tags: {y:ib}{Y:us} */
+ break;
+
+ /* Color */
+ case 'C':
+ tag.persistent = MICRODVD_PERSISTENT_ON;
+ case 'c':
+ tag.data1 = (uint32_t)strtol(s, &s, 16) & 0x00ffffff;
+ if (*s != '}')
+ break;
+ tag.key = 'c';
+ break;
+
+ /* Font name */
+ case 'F':
+ tag.persistent = MICRODVD_PERSISTENT_ON;
+ case 'f':
+ {
+ int i = 0;
+
+ while (*s && *s != '}' && i < sizeof(tag.data_string))
+ tag.data_string[i++] = *s++;
+ if (*s != '}')
+ break;
+ tag.key = 'f';
+ break;
+ }
+
+ /* Font size */
+ case 'S':
+ tag.persistent = MICRODVD_PERSISTENT_ON;
+ case 's':
+ {
+ tag.data1 = (uint32_t)strtol(s, &s, 10);
+ if (*s != '}' || tag.data1 > 72)
+ break;
+ tag.key = 's';
+ break;
+ }
+
+ /* Charset */
+ case 'H':
+ {
+ int i = 0;
+
+ //TODO: not yet handled, just parsed.
+ while (*s && *s != '}' && i < sizeof(tag.data_string))
+ tag.data_string[i++] = *s++;
+ if (*s != '}')
+ break;
+ 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 = (uint32_t)strtol(s, &s, 10);
+ if (*s != ',')
+ break;
+ s++;
+ tag.data2 = (uint32_t)strtol(s, &s, 10);
+ if (*s != '}')
+ break;
+ tag.key = 'o';
+ break;
+
+ default: /* Unknown tag, we considere it's text */
+ break;
+ }
+
+ if (tag.key == MICRODVD_TAG_DISABLED)
+ return start;
+
+ microdvd_set_tag(tags, tag);
+ s++;
+ }
+ return s;
+}
+
+static void microdvd_open_tags(char *new_line, int *j, microdvd_tag_type *tags)
+{
+ int i;
+
+ for (i = 0; i < sizeof(MICRODVD_TAGS) - 1; i++) {
+ if (tags[i].persistent == MICRODVD_PERSISTENT_OPENED)
+ continue;
+ switch (tags[i].key) {
+
+ case 'Y':
+ case 'y':
+ {
+ int style_index = 0;
+ char ytag[] = "{\\.1}";
+
+ while (style_index < sizeof(MICRODVD_STYLES) - 1) {
+ int style_mask = (1 << style_index);
+
+ if (tags[i].data1 & style_mask) {
+ ytag[2] = MICRODVD_STYLES[style_index];
+ insert_text_in_subdest(new_line, j, ytag, sizeof(ytag) - 1);
+ }
+ style_index++;
+ }
+ break;
+ }
+
+ case 'c':
+ {
+ char ctag[] = "{\\c&Hbbggrr&}";
+
+ sprintf(ctag, "{\\c&H%06X&}", tags[i].data1);
+ insert_text_in_subdest(new_line, j, ctag, sizeof(ctag) - 1);
+ break;
+ }
+
+ case 'f':
+ {
+ char ftag[4 + sizeof(tags[0].data_string) + 2];
+ int len = sprintf(ftag, "{\\fn%s}", tags[i].data_string);
+
+ insert_text_in_subdest(new_line, j, ftag, len);
+ break;
+ }
+
+ case 's':
+ {
+ char stag[4 + 2 + 2];
+ int len = sprintf(stag, "{\\fs%d}", tags[i].data1);
+
+ insert_text_in_subdest(new_line, j, stag, len);
+ break;
+ }
+
+ case 'p':
+ if (tags[i].data1 == 0)
+ insert_text_in_subdest(new_line, j, "{\\an8}", sizeof("{\\an8}") - 1);
+ break;
+
+ case 'o':
+ {
+ char otag[5 + sizeof(tags[0].data1) * 2 + 3];
+ int len = sprintf(otag, "{\\pos(%d,%d)}", tags[i].data1, tags[i].data2);
+
+ insert_text_in_subdest(new_line, j, otag, len);
+ break;
+ }
+
+ default:
+ break;
+ }
+ if (tags[i].persistent == MICRODVD_PERSISTENT_ON)
+ tags[i].persistent = MICRODVD_PERSISTENT_OPENED;
+ }
+}
+
+static void microdvd_close_no_persistent_tags(char *new_line, int *j, microdvd_tag_type *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':
+ {
+ int style_index = sizeof(MICRODVD_STYLES) - 2;
+ char ctag[] = "{\\.0}";
+
+ while (style_index >= 0) {
+ int style_mask = (1 << style_index);
+
+ if (tags[i].data1 & style_mask) {
+ ctag[2] = MICRODVD_STYLES[style_index];
+ insert_text_in_subdest(new_line, j, ctag, sizeof(ctag) - 1);
+ }
+ style_index--;
+ }
+ break;
+ }
+
+ case 'c':
+ insert_text_in_subdest(new_line, j, "{\\c}", sizeof("{\\c}") - 1);
+ break;
+
+ case 'f':
+ insert_text_in_subdest(new_line, j, "{\\fn}", sizeof("{\\fn}") - 1);
+ break;
+
+ case 's':
+ insert_text_in_subdest(new_line, j, "{\\fs}", sizeof("{\\fs}") - 1);
+ break;
+
+ default:
+ break;
+ }
+ tags[i].key = MICRODVD_TAG_DISABLED;
+ }
+}
+
+void subassconvert_microdvd(char *line)
+{
+ int i, j = 0;
+ char new_line[LINE_LEN + 1];
+ char *line_start = line;
+ microdvd_tag_type tags[sizeof(MICRODVD_TAGS) - 1];
+ const microdvd_tag_type dead_tag = MICRODVD_DEAD_TAG;
+
+ for (i = 0; MICRODVD_TAGS[i]; i++)
+ memcpy(&tags[i], &dead_tag, sizeof(dead_tag));
+
+ while (*line) {
+ line = microdvd_load_tags(tags, line);
+ microdvd_open_tags(new_line, &j, tags);
+
+ while (*line && *line != '|')
+ new_line[j++] = *line++;
+
+ if (*line == '|') {
+ microdvd_close_no_persistent_tags(new_line, &j, tags);
+ insert_text_in_subdest(new_line, &j, "\\N", sizeof("\\N") - 1);
+ line++;
+ }
+ }
+
+ new_line[j] = 0;
+ strcpy(line_start, new_line);
+}
diff --git a/subassconvert.h b/subassconvert.h
new file mode 100644
index 0000000..d1be265
--- /dev/null
+++ b/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(char *line);
+void subassconvert_microdvd(char *line);
+
+#endif
diff --git a/subreader.c b/subreader.c
index 394cc41..5cc9998 100644
--- a/subreader.c
+++ b/subreader.c
@@ -32,6 +32,8 @@
#include "config.h"
#include "mp_msg.h"
#include "subreader.h"
+#include "subassconvert.h"
+#include "options.h"
#include "stream/stream.h"
#include "libavutil/common.h"
#include "libavutil/avstring.h"
@@ -55,8 +57,6 @@ int fribidi_flip_commas = 0; ///flip comma when fribidi is used
extern char* dvdsub_lang;
-/* Maximal length of line of a subtitle */
-#define LINE_LEN 1000
static float mpsub_position=0;
static float mpsub_multiplier=1.;
static int sub_slacktime = 20000; //20 sec
@@ -291,6 +291,9 @@ static subtitle *sub_read_line_microdvd(stream_t *st,subtitle *current, int utf1
p=line2;
+ if (st->opts->ass_enabled)
+ subassconvert_microdvd(p);
+
next=p, i=0;
while ((next =sub_readtext (next, &(current->text[i])))) {
if (current->text[i]==ERR) {return ERR;}
@@ -358,12 +361,78 @@ static subtitle *sub_read_line_subrip(stream_t* st, subtitle *current, int utf16
return current;
}
+static subtitle *sub_ass_read_line_subviewer(stream_t *st, subtitle *current, int 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++] = '\\';
+ 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]) {
+ int len;
+
+ subassconvert_subrip(full_line);
+ len = strlen(full_line);
+ current->lines = 1;
+ current->text[0] = malloc(len + 1);
+ if (!current->text[0])
+ return ERR;
+ strncpy(current->text[0], full_line, len);
+ current->text[0][len] = '\0';
+ }
+ }
+ return current;
+}
+
static subtitle *sub_read_line_subviewer(stream_t *st,subtitle *current, int utf16) {
char line[LINE_LEN+1];
int a1,a2,a3,a4,b1,b2,b3,b4;
char *p=NULL;
int i,len;
+ if (st->opts->ass_enabled)
+ return sub_ass_read_line_subviewer(st, current, utf16);
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)
@@ -1352,7 +1421,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;
@@ -1381,6 +1451,7 @@ sub_data* sub_read_file (char *filename, float fps) {
if(filename==NULL) return NULL; //qnx segfault
i = 0;
fd=open_stream (filename, NULL, &i); if (!fd) return NULL;
+ fd->opts = opts;
sub_format = SUB_INVALID;
for (utf16 = 0; sub_format == SUB_INVALID && utf16 < 3; utf16++) {
diff --git a/subreader.h b/subreader.h
index f1706dc..e5704fd 100644
--- a/subreader.h
+++ b/subreader.h
@@ -44,6 +44,9 @@ extern int sub_match_fuzziness;
#define SUB_JACOSUB 12
#define SUB_MPL2 13
+/* Maximal length of line of a subtitle */
+#define LINE_LEN 1000
+
// One of the SUB_* constant above
extern int sub_format;
@@ -84,7 +87,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.
More information about the MPlayer-dev-eng
mailing list