Browse Source

Add other subtitles format
.vtt .sub .sub2
and option -e to force choice

Olivier Marty 8 years ago
parent
commit
a4d61080d0
14 changed files with 354 additions and 41 deletions
  1. 1 1
      Makefile
  2. 4 4
      README.md
  3. 8 0
      example.srt
  4. 5 0
      example.sub
  5. 2 0
      example.sub2
  6. 10 0
      example.vtt
  7. 66 4
      main.c
  8. 3 31
      parser.c
  9. 13 1
      parser.h
  10. 55 0
      parser_srt.c
  11. 65 0
      parser_sub.c
  12. 65 0
      parser_sub2.c
  13. 56 0
      parser_vtt.c
  14. 1 0
      time.c

+ 1 - 1
Makefile

@@ -17,7 +17,7 @@
 #  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 #
 
-SRCS=time.c parser.c rich_text.c events.c printer.c main.c
+SRCS=time.c parser.c parser_srt.c parser_sub.c parser_sub2.c parser_vtt.c rich_text.c events.c printer.c main.c
 CC=gcc
 CFLAGS=
 LIBS=$(shell pkg-config --cflags --libs x11) -lrt

+ 4 - 4
README.md

@@ -6,8 +6,8 @@ Print subtitles above a X-screen, independently of the video player.
 
 This program uses X11 to show subtitles.
 
-Currently, this program support only .srt subtitles. Please check also there is no empty line at the beginning of the file, or some unprintable characters before the first "1".
-You can see the specs of this format here : http://matroska.org/technical/specs/subtitles/srt.html
+This program support .srt, .vtt, and two .sub subtitles types. Please check also there is no empty line at the beginning of the file, or some unprintable characters before the first character.
+You can see the specs of format .srt here : http://matroska.org/technical/specs/subtitles/srt.html
 
 To have transparency between subtitles, try to launch xcompmgr before subtitlesPrinter.
 
@@ -30,12 +30,12 @@ subtitlesPrinter file.srt
 ### Controls
 
 To quit, press CTRL+C in the terminal.
-To pause and resume, press space anywhere (this does not work with all windows).
+To pause and resume, press space anywhere (badly this does not work with all windows).
 To shift the clock, press left and right arrows.
 
 ### Optional arguments
 
-It is possible to skip x seconds, or to change the delay before starting. For other parameters and details see
+It is possible to skip x seconds with option -s, and to scale time with option -t. For other parameters and details see
 ```bash
 subtitlesPrinter -h
 ```

+ 8 - 0
example.srt

@@ -0,0 +1,8 @@
+1
+00:00:00,500 --> 00:00:01,400
+<i>line 1</i>
+
+2
+00:00:02,600 --> 00:00:03,800
+<b>line 2</b>
+<b><i>line 3</i></b>

+ 5 - 0
example.sub

@@ -0,0 +1,5 @@
+00:00:00.03,00:00:01.82
+line 1
+
+00:00:02.19,00:00:03.47
+line 2[br]line 3

+ 2 - 0
example.sub2

@@ -0,0 +1,2 @@
+{11}{33}line 1
+{62}{91}line 2|line 3

+ 10 - 0
example.vtt

@@ -0,0 +1,10 @@
+WEBVTT
+
+1
+00:00:00.500 --> 00:00:01.400
+line 1
+
+2
+00:00:01.600 --> 00:00:02.800
+line 2
+line 3

+ 66 - 4
main.c

@@ -32,11 +32,12 @@ typedef enum _t_state t_state;
 
 void displayUsage(char *name)
 {
-  printf("Usage : %s file.srt\n", name);
+  printf("Usage : %s file.srt or .sub .sub2 .vtt\n", name);
   printf("Options :\n");
   printf("  -s sec\t: skip the first x seconds\n");
   printf("  -d sec\t: wait x seconds before starting (default : 5)\n");
   printf("  -t x\t\t: time factor x1000\n");
+  printf("  -e x\t\t: input format (srt, sub, sub2 (MicroDVD), vtt)\n");
   printf("  -m px\t\t: margin with the bottom of the screen\n");
   printf("  -p px\t\t: padding of the box\n");
   printf("  -g px\t\t: gap between two lines\n");
@@ -64,17 +65,29 @@ void display(struct printerEnv *env, struct richText *rt, int time, t_events *ev
   eventsPush(events, e);
 }
 
+int extension(const char *str, const char *suffix)
+{
+  if(!str || !suffix)
+    return 0;
+  size_t lenstr = strlen(str);
+  size_t lensuffix = strlen(suffix);
+  if(lensuffix > lenstr)
+    return 0;
+  return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
+}
+
 int main(int argc, char **argv)
 {
   int i, delay = 5, margin_bottom = 50, padding = 5, gap = 5, gap2 = 20;
   double factor = 1.0, shift = 0.;
-  char *font = NULL, *font_i = NULL, *font_b = NULL, *font_bi = NULL;
+  char *font = NULL, *font_i = NULL, *font_b = NULL, *font_bi = NULL,
+    *format = NULL;
   FILE *f = NULL;
   t_state state = S_RUNNING;
 
   // parse arguments
   int c;
-  while((c = getopt (argc, argv, "s:d:t:m:p:g:k:f:i:b:j:h")) != -1)
+  while((c = getopt (argc, argv, "s:d:t:e:m:p:g:k:f:i:b:j:h")) != -1)
     switch(c)
     {
       case 's':
@@ -86,6 +99,10 @@ int main(int argc, char **argv)
       case 't':
         factor = atoi(optarg)/1000.;
         break;
+      case 'e':
+        format = malloc(strlen(optarg)+1);
+        strcpy(format, optarg);
+        break;
       case 'm':
         margin_bottom = atoi(optarg);
         break;
@@ -136,6 +153,50 @@ int main(int argc, char **argv)
     exit(1);
   }
 
+  int (*start_f)(FILE*);
+  int (*next_f)(FILE *f, int expected, struct SubtitleLine *r);
+
+  if((format == NULL && extension(argv[optind], ".srt"))
+    || (format != NULL && !strcmp(format, "srt")))
+  {
+    printf("Type : srt\n");
+    start_f = start_srt;
+    next_f = next_srt;
+  }
+  else if((format == NULL && extension(argv[optind], ".sub"))
+    || (format != NULL && !strcmp(format, "sub")))
+  {
+    printf("Type : sub\n");
+    start_f = start_sub;
+    next_f = next_sub;
+  }
+  else if((format == NULL && extension(argv[optind], ".sub2"))
+    || (format != NULL && !strcmp(format, "sub2")))
+  {
+    printf("Type : sub2\n");
+    start_f = start_sub2;
+    next_f = next_sub2;
+  }
+  else if((format == NULL && extension(argv[optind], ".vtt"))
+    || (format != NULL && !strcmp(format, "vtt")))
+  {
+    printf("Type : vtt\n");
+    start_f = start_vtt;
+    next_f = next_vtt;
+  }
+  else
+  {
+    fprintf(stderr, "Unknow format !\n");
+    displayUsage(argv[0]);
+    exit(1);
+  }
+
+  if(!start_f(f))
+  {
+    fprintf(stderr, "Bad header !\n");
+    exit(1);
+  }
+
   // open the window
   struct printerEnv penv = printerOpenWindow(font, font_i, font_b, font_bi);
 
@@ -227,7 +288,7 @@ int main(int argc, char **argv)
               struct SubtitleLine sline;
               if(feof(f))
                 break;
-              id = next(f, id+1, &sline);
+              id = next_f(f, id+1, &sline);
               sline.begin = timeFactor(sline.begin, factor);
               sline.end = timeFactor(sline.end, factor);
               if(timeInFuture(sline.end))
@@ -339,4 +400,5 @@ int main(int argc, char **argv)
   richTextFree(pausert);
   printerCloseWindow(penv);
   fclose(f);
+  return 0;
 }

+ 3 - 31
parser.c

@@ -20,38 +20,10 @@
 
 #include "parser.h"
 
+// TODO give an environment to parser, in order to store style...
+// or parse everything at once
+
 int empty_line(char *str)
 {
   return str[0] == '\n' || str[0] == '\0' || (str[0] == '\r' && str[1] == '\n');
 }
-
-int next(FILE *f, int expected, struct SubtitleLine *r)
-{
-  int t_h, t_m, t_s, t_ms;
-  fscanf(f, "%d ", &r->id);
-  if(r->id != expected)
-    fprintf(stderr, "expected : %d; found : %d\n", expected, r->id);
-
-  fscanf(f, "%d:%d:%d,%d --> ", &t_h, &t_m, &t_s, &t_ms);
-  r->begin = timeCreate(t_h*3600 + t_m*60 + t_s, t_ms*1000000);
-  // TODO and if there are 4 digits ?
-  fscanf(f, "%d:%d:%d,%d ", &t_h, &t_m, &t_s, &t_ms);
-  r->end = timeCreate(t_h*3600 + t_m*60 + t_s, t_ms*1000000);
-
-  *(r->text) = '\0';
-  char line[1024];
-  while(1)
-  {
-    fgets(line, 1024, f);
-    if(empty_line(line))
-      break;
-    strcat(r->text, line);
-    if(feof(f))
-    {
-      strcat(r->text, "\n");
-      break;
-    }
-  }
-
-  return r->id;
-}

+ 13 - 1
parser.h

@@ -30,8 +30,20 @@ struct SubtitleLine
   mytime end;
 };
 
+// read the header, if any
+int start_srt(FILE *f);
+int start_sub(FILE *f);
+int start_sub2(FILE *f);
+int start_vtt(FILE *f);
+
 // read the next subtitle, expected to be expected-th
 // return the number of the readed subtitle
-int next(FILE *f, int expected, struct SubtitleLine *r);
+int next_srt(FILE *f, int expected, struct SubtitleLine *r);
+int next_sub(FILE *f, int expected, struct SubtitleLine *r);
+int next_sub2(FILE *f, int expected, struct SubtitleLine *r);
+int next_vtt(FILE *f, int expected, struct SubtitleLine *r);
+
+// test if a string is an empty line
+int empty_line(char *f);
 
 #endif

+ 55 - 0
parser_srt.c

@@ -0,0 +1,55 @@
+/*
+  Copyright (C) 2014  Olivier Marty <olivier.marty.m at gmail.com>
+
+  This program 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.
+
+  This program 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 this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#include <string.h>
+
+#include "parser.h"
+
+int start_srt(FILE *f)
+{
+  return 1;
+}
+
+int next_srt(FILE *f, int expected, struct SubtitleLine *r)
+{
+  int t_h, t_m, t_s, t_ms;
+  fscanf(f, "%*d "); // we ignore it
+
+  fscanf(f, "%d:%d:%d,%d --> ", &t_h, &t_m, &t_s, &t_ms);
+  r->begin = timeCreate(t_h*3600 + t_m*60 + t_s, t_ms*1000000);
+  // TODO and if there are 4 digits ?
+  fscanf(f, "%d:%d:%d,%d ", &t_h, &t_m, &t_s, &t_ms);
+  r->end = timeCreate(t_h*3600 + t_m*60 + t_s, t_ms*1000000);
+
+  *(r->text) = '\0';
+  char line[1024];
+  while(1)
+  {
+    if(fgets(line, 1024, f) == NULL || empty_line(line))
+      break;
+    strcat(r->text, line);
+    if(feof(f))
+    {
+      strcat(r->text, "\n");
+      break;
+    }
+  }
+
+  r->id = expected;
+  return r->id;
+}

+ 65 - 0
parser_sub.c

@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2014  Olivier Marty <olivier.marty.m at gmail.com>
+
+  This program 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.
+
+  This program 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 this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#include <string.h>
+
+#include "parser.h"
+
+int start_sub(FILE *f)
+{
+  return 1;
+}
+
+int next_sub(FILE *f, int expected, struct SubtitleLine *r)
+{
+  int t_h, t_m, t_s, t_ms;
+  fscanf(f, "%d:%d:%d.%d,", &t_h, &t_m, &t_s, &t_ms);
+  r->begin = timeCreate(t_h*3600 + t_m*60 + t_s, t_ms*10000000);
+  fscanf(f, "%d:%d:%d.%d\n", &t_h, &t_m, &t_s, &t_ms);
+  r->end = timeCreate(t_h*3600 + t_m*60 + t_s, t_ms*10000000);
+
+  *(r->text) = '\0';
+  char line[1024];
+  while(1)
+  {
+    if(fgets(line, 1024, f) == NULL)
+      break;
+    strcat(r->text, line);
+    if(line[strlen(line)-1] == '\n') // read only one line
+      break;
+    if(feof(f))
+    {
+      strcat(r->text, "\n");
+      break;
+    }
+  }
+
+  // replace "[br]" by "\n"
+  char* pos = r->text;
+  char* end = pos + strlen(r->text);
+  while(pos < end && (pos = strstr(pos, "[br]")) != NULL)
+  {
+    *pos++ = '\n';
+    *pos++ = 127;
+    *pos++ = 127;
+    *pos++ = 127;
+  }
+
+  r->id = expected;
+  return r->id;
+}

+ 65 - 0
parser_sub2.c

@@ -0,0 +1,65 @@
+/*
+  Copyright (C) 2014  Olivier Marty <olivier.marty.m at gmail.com>
+
+  This program 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.
+
+  This program 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 this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#include <string.h>
+#include <string.h>
+
+#include "parser.h"
+
+int start_sub2(FILE *f)
+{
+  return 1;
+}
+
+int next_sub2(FILE *f, int expected, struct SubtitleLine *r)
+{
+  float framerate = 23.976; // TODO option
+  int tstart, tend;
+  fscanf(f, "{%d}{%d}", &tstart, &tend);
+  time_t s = tstart/framerate;
+  r->begin = timeCreate(s, (tstart/framerate-s)*1000000000);
+  s = tend/framerate;
+  r->end = timeCreate(s, (tend/framerate-s)*1000000000);
+
+  *(r->text) = '\0';
+  char line[1024];
+  while(1)
+  {
+    if(fgets(line, 1024, f) == NULL)
+      break;
+    strcat(r->text, line);
+    if(line[strlen(line)-1] == '\n') // read only one line
+      break;
+    if(feof(f))
+    {
+      strcat(r->text, "\n");
+      break;
+    }
+  }
+
+  // replace "|" by "\n"
+  char* pos = r->text;
+  char* end = pos + strlen(r->text);
+  while(pos < end && (pos = strchr(pos, '|')) != NULL)
+  {
+    *pos++ = '\n';
+  }
+
+  r->id = expected;
+  return r->id;
+}

+ 56 - 0
parser_vtt.c

@@ -0,0 +1,56 @@
+/*
+  Copyright (C) 2014  Olivier Marty <olivier.marty.m at gmail.com>
+
+  This program 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.
+
+  This program 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 this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+
+#include <string.h>
+
+#include "parser.h"
+
+int start_vtt(FILE *f)
+{
+  char word[7];
+  return fscanf(f, "%6s ", word) == 1 && strcmp(word, "WEBVTT") == 0;
+}
+
+int next_vtt(FILE *f, int expected, struct SubtitleLine *r)
+{
+  int t_h, t_m, t_s, t_ms;
+  fscanf(f, "%*d "); // we ignore it
+
+  fscanf(f, "%d:%d:%d.%d --> ", &t_h, &t_m, &t_s, &t_ms);
+  r->begin = timeCreate(t_h*3600 + t_m*60 + t_s, t_ms*1000000);
+  // TODO and if there are 4 digits ?
+  fscanf(f, "%d:%d:%d.%d ", &t_h, &t_m, &t_s, &t_ms);
+  r->end = timeCreate(t_h*3600 + t_m*60 + t_s, t_ms*1000000);
+
+  *(r->text) = '\0';
+  char line[1024];
+  while(1)
+  {
+    if(fgets(line, 1024, f) == NULL || empty_line(line))
+      break;
+    strcat(r->text, line);
+    if(feof(f))
+    {
+      strcat(r->text, "\n");
+      break;
+    }
+  }
+
+  r->id = expected;
+  return r->id;
+}

+ 1 - 0
time.c

@@ -93,6 +93,7 @@ struct timespec timeCreate(time_t s, long ns)
   struct timespec r;
   r.tv_sec = s;
   r.tv_nsec = ns;
+  normalize(&r);
   return r;
 }