]> granicus.if.org Git - libass/blobdiff - libass/ass.c
Add Blur field to ASS_Style
[libass] / libass / ass.c
index 057a6e349b8fcc31f120e5e41a1e22d8dd7c145c..678a9a3b39f0518b0c5caaed61e07cfe31bb198c 100644 (file)
@@ -3,19 +3,17 @@
  *
  * This file is part of libass.
  *
- * libass 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.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * libass 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 libass; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 #include "config.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <strings.h>
 #include <assert.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <inttypes.h>
+#include <ctype.h>
 
 #ifdef CONFIG_ICONV
 #include <iconv.h>
@@ -38,6 +38,8 @@
 #include "ass_utils.h"
 #include "ass_library.h"
 
+#define ass_atof(STR) (ass_strtod((STR),NULL))
+
 typedef enum {
     PST_UNKNOWN = 0,
     PST_INFO,
@@ -62,26 +64,23 @@ void ass_free_track(ASS_Track *track)
     int i;
 
     if (track->parser_priv) {
-        if (track->parser_priv->fontname)
-            free(track->parser_priv->fontname);
-        if (track->parser_priv->fontdata)
-            free(track->parser_priv->fontdata);
+        free(track->parser_priv->fontname);
+        free(track->parser_priv->fontdata);
         free(track->parser_priv);
     }
-    if (track->style_format)
-        free(track->style_format);
-    if (track->event_format)
-        free(track->event_format);
+    free(track->style_format);
+    free(track->event_format);
+    free(track->Language);
     if (track->styles) {
         for (i = 0; i < track->n_styles; ++i)
             ass_free_style(track, i);
-        free(track->styles);
     }
+    free(track->styles);
     if (track->events) {
         for (i = 0; i < track->n_events; ++i)
             ass_free_event(track, i);
-        free(track->events);
     }
+    free(track->events);
     free(track->name);
     free(track);
 }
@@ -133,23 +132,19 @@ int ass_alloc_event(ASS_Track *track)
 void ass_free_event(ASS_Track *track, int eid)
 {
     ASS_Event *event = track->events + eid;
-    if (event->Name)
-        free(event->Name);
-    if (event->Effect)
-        free(event->Effect);
-    if (event->Text)
-        free(event->Text);
-    if (event->render_priv)
-        free(event->render_priv);
+
+    free(event->Name);
+    free(event->Effect);
+    free(event->Text);
+    free(event->render_priv);
 }
 
 void ass_free_style(ASS_Track *track, int sid)
 {
     ASS_Style *style = track->styles + sid;
-    if (style->Name)
-        free(style->Name);
-    if (style->FontName)
-        free(style->FontName);
+
+    free(style->Name);
+    free(style->FontName);
 }
 
 // ==============================================================================================
@@ -171,28 +166,29 @@ static void rskip_spaces(char **str, char *limit)
 }
 
 /**
- * \brief find style by name
- * \param track track
- * \param name style name
- * \return index in track->styles
- * Returnes 0 if no styles found => expects at least 1 style.
- * Parsing code always adds "Default" style in the end.
+ * \brief Set up default style
+ * \param style style to edit to defaults
+ * The parameters are mostly taken directly from VSFilter source for
+ * best compatibility.
  */
-static int lookup_style(ASS_Track *track, char *name)
+static void set_default_style(ASS_Style *style)
 {
-    int i;
-    if (*name == '*')
-        ++name;                 // FIXME: what does '*' really mean ?
-    for (i = track->n_styles - 1; i >= 0; --i) {
-        // FIXME: mb strcasecmp ?
-        if (strcmp(track->styles[i].Name, name) == 0)
-            return i;
-    }
-    i = track->default_style;
-    ass_msg(track->library, MSGL_WARN,
-            "[%p]: Warning: no style named '%s' found, using '%s'",
-            track, name, track->styles[i].Name);
-    return i;                   // use the first style
+    style->Name             = strdup("Default");
+    style->FontName         = strdup("Arial");
+    style->FontSize         = 18;
+    style->PrimaryColour    = 0xffffff00;
+    style->SecondaryColour  = 0x00ffff00;
+    style->OutlineColour    = 0x00000000;
+    style->BackColour       = 0x00000080;
+    style->Bold             = 200;
+    style->ScaleX           = 1.0;
+    style->ScaleY           = 1.0;
+    style->Spacing          = 0;
+    style->BorderStyle      = 1;
+    style->Outline          = 2;
+    style->Shadow           = 3;
+    style->Alignment        = 2;
+    style->MarginL = style->MarginR = style->MarginV = 20;
 }
 
 static uint32_t string2color(ASS_Library *library, char *p)
@@ -250,7 +246,7 @@ static int numpad2align(int val)
                ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token);
 
 #define INTVAL(name) ANYVAL(name,atoi)
-#define FPVAL(name) ANYVAL(name,atof)
+#define FPVAL(name) ANYVAL(name,ass_atof)
 #define TIMEVAL(name) \
        } else if (strcasecmp(tname, #name) == 0) { \
                target->name = string2timecode(track->library, token); \
@@ -315,8 +311,8 @@ static int process_event_tail(ASS_Track *track, ASS_Event *event,
         // add "Default" style to the end
         // will be used if track does not contain a default style (or even does not contain styles at all)
         int sid = ass_alloc_style(track);
-        track->styles[sid].Name = strdup("Default");
-        track->styles[sid].FontName = strdup("Arial");
+        set_default_style(&track->styles[sid]);
+        track->default_style = sid;
     }
 
     for (i = 0; i < n_ignored; ++i) {
@@ -384,11 +380,13 @@ void ass_process_force_style(ASS_Track *track)
         else if (!strcasecmp(*fs, "PlayResY"))
             track->PlayResY = atoi(token);
         else if (!strcasecmp(*fs, "Timer"))
-            track->Timer = atof(token);
+            track->Timer = ass_atof(token);
         else if (!strcasecmp(*fs, "WrapStyle"))
             track->WrapStyle = atoi(token);
         else if (!strcasecmp(*fs, "ScaledBorderAndShadow"))
             track->ScaledBorderAndShadow = parse_bool(token);
+        else if (!strcasecmp(*fs, "Kerning"))
+            track->Kerning = parse_bool(token);
 
         dt = strrchr(*fs, '.');
         if (dt) {
@@ -426,6 +424,7 @@ void ass_process_force_style(ASS_Track *track)
                     FPVAL(ScaleY)
                     FPVAL(Outline)
                     FPVAL(Shadow)
+                    FPVAL(Blur)
                 }
             }
         }
@@ -473,6 +472,14 @@ static int process_style(ASS_Track *track, char *str)
 
     q = format = strdup(track->style_format);
 
+    // Add default style first
+    if (track->n_styles == 0) {
+        // will be used if track does not contain a default style (or even does not contain styles at all)
+        int sid = ass_alloc_style(track);
+        set_default_style(&track->styles[sid]);
+        track->default_style = sid;
+    }
+
     ass_msg(track->library, MSGL_V, "[%p] Style: %s", track, str);
 
     sid = ass_alloc_style(track);
@@ -508,7 +515,7 @@ static int process_style(ASS_Track *track, char *str)
             INTVAL(Underline)
             INTVAL(StrikeOut)
             FPVAL(Spacing)
-            INTVAL(Angle)
+            FPVAL(Angle)
             INTVAL(BorderStyle)
             INTVAL(Alignment)
             if (track->track_type == TRACK_TYPE_ASS)
@@ -532,12 +539,6 @@ static int process_style(ASS_Track *track, char *str)
         style->Name = strdup("Default");
     if (!style->FontName)
         style->FontName = strdup("Arial");
-    // skip '@' at the start of the font name
-    if (*style->FontName == '@') {
-        p = style->FontName;
-        style->FontName = strdup(p + 1);
-        free(p);
-    }
     free(format);
     return 0;
 
@@ -566,11 +567,19 @@ static int process_info_line(ASS_Track *track, char *str)
     } else if (!strncmp(str, "PlayResY:", 9)) {
         track->PlayResY = atoi(str + 9);
     } else if (!strncmp(str, "Timer:", 6)) {
-        track->Timer = atof(str + 6);
+        track->Timer = ass_atof(str + 6);
     } else if (!strncmp(str, "WrapStyle:", 10)) {
         track->WrapStyle = atoi(str + 10);
     } else if (!strncmp(str, "ScaledBorderAndShadow:", 22)) {
         track->ScaledBorderAndShadow = parse_bool(str + 22);
+    } else if (!strncmp(str, "Kerning:", 8)) {
+        track->Kerning = parse_bool(str + 8);
+    } else if (!strncmp(str, "Language:", 9)) {
+        char *p = str + 9;
+        while (*p && isspace(*p)) p++;
+        track->Language = malloc(3);
+        strncpy(track->Language, p, 2);
+        track->Language[2] = 0;
     }
     return 0;
 }
@@ -579,10 +588,10 @@ static void event_format_fallback(ASS_Track *track)
 {
     track->parser_priv->state = PST_EVENTS;
     if (track->track_type == TRACK_TYPE_SSA)
-        track->event_format = strdup("Format: Marked, Start, End, Style, "
+        track->event_format = strdup("Marked, Start, End, Style, "
             "Name, MarginL, MarginR, MarginV, Effect, Text");
     else
-        track->event_format = strdup("Format: Layer, Start, End, Style, "
+        track->event_format = strdup("Layer, Start, End, Style, "
             "Actor, MarginL, MarginR, MarginV, Effect, Text");
     ass_msg(track->library, MSGL_V,
             "No event format found, using fallback");
@@ -593,6 +602,7 @@ static int process_events_line(ASS_Track *track, char *str)
     if (!strncmp(str, "Format:", 7)) {
         char *p = str + 7;
         skip_spaces(&p);
+        free(track->event_format);
         track->event_format = strdup(p);
         ass_msg(track->library, MSGL_DBG2, "Event format: %s", track->event_format);
     } else if (!strncmp(str, "Dialogue:", 9)) {
@@ -614,7 +624,7 @@ static int process_events_line(ASS_Track *track, char *str)
 
         process_event_tail(track, event, str, 0);
     } else {
-        ass_msg(track->library, MSGL_V, "Not understood: '%s'", str);
+        ass_msg(track->library, MSGL_V, "Not understood: '%.30s'", str);
     }
     return 0;
 }
@@ -673,12 +683,10 @@ static int decode_font(ASS_Track *track)
     if (track->library->extract_fonts) {
         ass_add_font(track->library, track->parser_priv->fontname,
                      (char *) buf, dsize);
-        buf = 0;
     }
 
-  error_decode_font:
-    if (buf)
-        free(buf);
+error_decode_font:
+    free(buf);
     free(track->parser_priv->fontname);
     free(track->parser_priv->fontdata);
     track->parser_priv->fontname = 0;
@@ -905,6 +913,20 @@ void ass_process_chunk(ASS_Track *track, char *data, int size,
     free(str);
 }
 
+/**
+ * \brief Flush buffered events.
+ * \param track track
+*/
+void ass_flush_events(ASS_Track *track)
+{
+    if (track->events) {
+        int eid;
+        for (eid = 0; eid < track->n_events; eid++)
+            ass_free_event(track, eid);
+        track->n_events = 0;
+    }
+}
+
 #ifdef CONFIG_ICONV
 /** \brief recode buffer to utf-8
  * constraint: codepage != 0
@@ -967,7 +989,9 @@ static char *sub_recode(ASS_Library *library, char *data, size_t size,
                     oleft += size;
                 } else {
                     ass_msg(library, MSGL_WARN, "Error recoding file");
-                    return NULL;
+                    free(outbuf);
+                    outbuf = NULL;
+                    goto out;
                 }
             } else if (clear)
                 break;
@@ -975,6 +999,7 @@ static char *sub_recode(ASS_Library *library, char *data, size_t size,
         outbuf[osize - oleft - 1] = 0;
     }
 
+out:
     if (icdsc != (iconv_t) (-1)) {
         (void) iconv_close(icdsc);
         icdsc = (iconv_t) (-1);
@@ -1015,14 +1040,6 @@ static char *read_file(ASS_Library *library, char *fname, size_t *bufsize)
     sz = ftell(fp);
     rewind(fp);
 
-    if (sz > 10 * 1024 * 1024) {
-        ass_msg(library, MSGL_INFO,
-               "ass_read_file(%s): Refusing to load subtitles "
-               "larger than 10MiB", fname);
-        fclose(fp);
-        return 0;
-    }
-
     ass_msg(library, MSGL_V, "File size: %ld", sz);
 
     buf = malloc(sz + 1);
@@ -1096,12 +1113,13 @@ ASS_Track *ass_read_memory(ASS_Library *library, char *buf,
         return 0;
 
 #ifdef CONFIG_ICONV
-    if (codepage)
+    if (codepage) {
         buf = sub_recode(library, buf, bufsize, codepage);
-    if (!buf)
-        return 0;
-    else
-        need_free = 1;
+        if (!buf)
+            return 0;
+        else
+            need_free = 1;
+    }
 #endif
     track = parse_memory(library, buf);
     if (need_free)
@@ -1239,3 +1257,36 @@ ASS_Track *ass_new_track(ASS_Library *library)
     track->parser_priv = calloc(1, sizeof(ASS_ParserPriv));
     return track;
 }
+
+/**
+ * \brief Prepare track for rendering
+ */
+void ass_lazy_track_init(ASS_Library *lib, ASS_Track *track)
+{
+    if (track->PlayResX && track->PlayResY)
+        return;
+    if (!track->PlayResX && !track->PlayResY) {
+        ass_msg(lib, MSGL_WARN,
+               "Neither PlayResX nor PlayResY defined. Assuming 384x288");
+        track->PlayResX = 384;
+        track->PlayResY = 288;
+    } else {
+        if (!track->PlayResY && track->PlayResX == 1280) {
+            track->PlayResY = 1024;
+            ass_msg(lib, MSGL_WARN,
+                   "PlayResY undefined, setting to %d", track->PlayResY);
+        } else if (!track->PlayResY) {
+            track->PlayResY = track->PlayResX * 3 / 4;
+            ass_msg(lib, MSGL_WARN,
+                   "PlayResY undefined, setting to %d", track->PlayResY);
+        } else if (!track->PlayResX && track->PlayResY == 1024) {
+            track->PlayResX = 1280;
+            ass_msg(lib, MSGL_WARN,
+                   "PlayResX undefined, setting to %d", track->PlayResX);
+        } else if (!track->PlayResX) {
+            track->PlayResX = track->PlayResY * 4 / 3;
+            ass_msg(lib, MSGL_WARN,
+                   "PlayResX undefined, setting to %d", track->PlayResX);
+        }
+    }
+}