[MPlayer-dev-eng] [PATCH] Style tag support for srt and microdvd subtitles

ubitux ubitux at gmail.com
Sat May 15 15:36:03 CEST 2010


Hi,

Here is a more complete patch which now also supports MicroDVD subtitles.
So now, with -ass you can get basic tags working for MicroDVD and SubRip
subtitles (bold/italic/underline/strike-through).

Since last time, I've a bit modified the SubRip conversion support:

- Function name
- Overflow check (again)
- Let the old filter html tags if there is ones left

About the MicroDVD support, I've commented it a bit since the code is a
bit larger. As I say it supports basic tagging, but also tag persistence.

Next step is colors/size support, but I think this is a first patch that
can be safetly applied.

Can you make a review of this stuff?

Regards,

-- 
ubitux
-------------- next part --------------
Index: subreader.c
===================================================================
--- subreader.c	(revision 31179)
+++ subreader.c	(working copy)
@@ -36,6 +36,8 @@
 #include "libavutil/common.h"
 #include "libavutil/avstring.h"
 
+#include "libass/ass_mp.h"
+
 #ifdef CONFIG_ENCA
 #include <enca.h>
 #endif
@@ -251,7 +253,96 @@
     return current;
 }
 
+static int indexof(const char *s, int c)
+{
+    char *f = strchr(s, c);
 
+    return (f) ? (f - s) : -1;
+}
+
+#define MICRODVD_ALLOWED_STYLES "ibus"  /* italic, bold, underline, strike-through */
+#define MICRODVD_DEFAULT_STYLES "...."  /* no styles */
+#define MICRODVD_TAG_DISABLED   '.'
+
+static void subconvert_microdvd_to_ass(char *line)
+{
+    char new_line[LINE_LEN + 1];
+    int i = 0, j = 0;
+    char ass_otag[] = "{\\.1}";    /* ASS/SSA opening tag */
+    char ass_ctag[] = "{\\.0}";    /* ASS/SSA closing tag */
+    char tags_to_close[] = MICRODVD_DEFAULT_STYLES;
+
+    while (line[i] && j < sizeof(new_line) - 1) {
+
+        /* End of line */
+        if (line[i] == '|') {
+            int n;
+
+            /* close non-persistent style tags */
+            for (n = sizeof(tags_to_close) - 2; n >= 0; n--) {
+                if (tags_to_close[n] != MICRODVD_TAG_DISABLED) {
+                    if (j + sizeof(ass_ctag) < sizeof(new_line) - 1) {
+                        ass_ctag[2] = tags_to_close[n];
+                        strcpy(&new_line[j], ass_ctag);
+                        j += sizeof(ass_ctag) - 1;
+                    }
+                    tags_to_close[n] = MICRODVD_TAG_DISABLED;
+                }
+            }
+
+            /* ASS/SSA end of line */
+            if (j + 2 < sizeof(new_line) - 1) {
+                strcpy(&new_line[j], "\\N");
+                j += 2;
+            }
+
+            i++;
+            continue;
+        }
+
+        /* Opening style tags */
+        if (strncasecmp(&line[i], "{y:", 3) == 0) {
+            int n, persistent = (line[i + 1] == 'Y');
+            char tags_to_open[] = MICRODVD_DEFAULT_STYLES;
+
+            i += 3;
+
+            /* Reference style tags to open */
+            while (line[i] && line[i] != '}') {
+                int tag_index = indexof(MICRODVD_ALLOWED_STYLES, line[i]);
+
+                if (tag_index >= 0)
+                    tags_to_open[tag_index] = line[i];
+                i++;
+            }
+
+            if (!line[i])
+                break;
+
+            /* Open them in order to close them the exact opposite way they are opened */
+            for (n = 0; tags_to_open[n]; n++) {
+                if (tags_to_open[n] != MICRODVD_TAG_DISABLED &&
+                        j + sizeof(ass_otag) < sizeof(new_line) - 1) {
+                    ass_otag[2] = tags_to_open[n];
+                    strcpy(&new_line[j], ass_otag);
+                    j += sizeof(ass_otag) - 1;
+                    if (!persistent)
+                        tags_to_close[n] = tags_to_open[n];
+                }
+            }
+
+            i++;
+            continue;
+        }
+
+        /* Part of the text */
+        new_line[j++] = line[i++];
+    }
+
+    new_line[j] = 0;
+    strcpy(line, new_line);
+}
+
 static char *sub_readtext(char *source, char **dest) {
     int len=0;
     char *p=source;
@@ -291,6 +382,9 @@
 
     p=line2;
 
+    if (ass_enabled)
+        subconvert_microdvd_to_ass(p);
+
     next=p, i=0;
     while ((next =sub_readtext (next, &(current->text[i])))) {
         if (current->text[i]==ERR) {return ERR;}
@@ -358,6 +452,42 @@
     return current;
 }
 
+static const struct {
+    char *from;
+    char *to;
+} subviewer_to_ass[] = {
+    {"<i>", "{\\i1}"}, {"</i>", "{\\i0}"},
+    {"<b>", "{\\b1}"}, {"</b>", "{\\b0}"},
+    {"<u>", "{\\u1}"}, {"</u>", "{\\u0}"},
+    {"<s>", "{\\s1}"}, {"</s>", "{\\s0}"}
+};
+
+static void subconvert_subviewer_to_ass(char *line)
+{
+    char new_line[LINE_LEN + 1];
+    int i = 0, j = 0;
+
+    while (line[i] && j < sizeof(new_line) - 1) {
+        int n, match = 0;
+
+        for (n = 0; n < (int)(sizeof(subviewer_to_ass) / sizeof(*subviewer_to_ass)); n++) {
+            int from_len = strlen(subviewer_to_ass[n].from);
+
+            if (strncmp(&line[i], subviewer_to_ass[n].from, from_len) == 0) {
+                strcpy(&new_line[j], subviewer_to_ass[n].to);
+                i += from_len;
+                j += strlen(subviewer_to_ass[n].to);
+                match = 1;
+                break;
+            }
+        }
+        if (!match)
+            new_line[j++] = line[i++];
+    }
+    new_line[j] = 0;
+    strcpy(line, new_line);
+}
+
 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;
@@ -373,6 +503,10 @@
 	for (i=0; i<SUB_MAX_TEXT;) {
 	    int blank = 1;
 	    if (!stream_read_line (st, line, LINE_LEN, utf16)) break;
+
+	    if (ass_enabled)
+		subconvert_subviewer_to_ass(line);
+
 	    len=0;
 	    for (p=line; *p!='\n' && *p!='\r' && *p; p++,len++)
 		if (*p != ' ' && *p != '\t')


More information about the MPlayer-dev-eng mailing list