Ticket #6240: subfix.diff

File subfix.diff, 39.4 KB (added by robert.mcnamara@…, 15 years ago)

Fixes issue, also adds subtitle support for storage groups (and theoretically for recording storage groups too)

  • libs/libmythtv/xine_demux_sputext.cpp

     
     1/*
     2 * Copyright (C) 2000-2003 the xine project
     3 *
     4 * This file is part of xine, a free video player.
     5 *
     6 * xine is free software; you can redistribute it and/or modify
     7 * it under the terms of the GNU General Public License as published by
     8 * the Free Software Foundation; either version 2 of the License, or
     9 * (at your option) any later version.
     10 *
     11 * xine is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License
     17 * along with this program; if not, write to the Free Software
     18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
     19 *
     20 * $Id: xine_demux_sputext.c 20349 2009-04-11 00:04:30Z xris $
     21 *
     22 * code based on old libsputext/xine_decoder.c
     23 *
     24 * code based on mplayer module:
     25 *
     26 * Subtitle reader with format autodetection
     27 *
     28 * Written by laaz
     29 * Some code cleanup & realloc() by A'rpi/ESP-team
     30 * dunnowhat sub format by szabi
     31 */
     32
     33#ifdef HAVE_CONFIG_H
     34#include "config.h"
     35#endif
     36
     37#include <stdlib.h>
     38#include <stdio.h>
     39#include <unistd.h>
     40#include <string.h>
     41#include <sys/types.h>
     42#include <sys/stat.h>
     43#include <fcntl.h>
     44#include <ctype.h>
     45#include "xine_demux_sputext.h"
     46
     47#define LOG_MODULE "demux_sputext"
     48#define LOG_VERBOSE
     49/*
     50#define LOG
     51*/
     52
     53#define ERR           (void *)-1
     54#define LINE_LEN      1000
     55#define LINE_LEN_QUOT "1000"
     56
     57/*
     58 * Demuxer code start
     59 */
     60
     61#define FORMAT_UNKNOWN   -1
     62#define FORMAT_MICRODVD   0
     63#define FORMAT_SUBRIP     1
     64#define FORMAT_SUBVIEWER  2
     65#define FORMAT_SAMI       3
     66#define FORMAT_VPLAYER    4
     67#define FORMAT_RT         5
     68#define FORMAT_SSA        6 /* Sub Station Alpha */
     69#define FORMAT_PJS        7
     70#define FORMAT_MPSUB      8
     71#define FORMAT_AQTITLE    9
     72#define FORMAT_JACOBSUB   10
     73#define FORMAT_SUBVIEWER2 11
     74#define FORMAT_SUBRIP09   12
     75#define FORMAT_MPL2       13 /*Mplayer sub 2 ?*/
     76
     77static int eol(char p) {
     78  return (p=='\r' || p=='\n' || p=='\0');
     79}
     80
     81static inline void trail_space(char *s) {
     82  int i;
     83  while (isspace(*s)) {
     84    char *copy = s;
     85    do {
     86      copy[0] = copy[1];
     87      copy++;
     88    } while(*copy);
     89  }
     90  i = strlen(s) - 1;
     91  while (i > 0 && isspace(s[i]))
     92    s[i--] = '\0';
     93}
     94
     95/*
     96 * Reimplementation of fgets() using the input->read() method.
     97 */
     98static char *read_line_from_input(demux_sputext_t *demuxstr, char *line, off_t len) {
     99  off_t nread = 0;
     100  char *s;
     101  int linelen;
     102
     103  // Since our RemoteFile code sleeps 200ms whenever we get back less data
     104  // than requested, but this code just keeps trying to read until it gets
     105  // an error back, we check for empty reads so that we can stop reading
     106  // when there is no more data to read
     107  if (demuxstr->emptyReads == 0 && (len - demuxstr->buflen) > 512) {
     108    if((nread = demuxstr->rbuffer->Read(
     109            &demuxstr->buf[demuxstr->buflen],
     110            len - demuxstr->buflen)) < 0) {
     111      printf("read failed.\n");
     112      return NULL;
     113    }
     114  }
     115 
     116  if (!nread)
     117      demuxstr->emptyReads++;
     118
     119  demuxstr->buflen += nread;
     120  demuxstr->buf[demuxstr->buflen] = '\0';
     121
     122  s = strchr(demuxstr->buf, '\n');
     123
     124  if (line && (s || demuxstr->buflen)) {
     125   
     126    linelen = s ? (s - demuxstr->buf) + 1 : demuxstr->buflen;
     127   
     128    memcpy(line, demuxstr->buf, linelen);
     129    line[linelen] = '\0';
     130
     131    memmove(demuxstr->buf, &demuxstr->buf[linelen], SUB_BUFSIZE - linelen);
     132    demuxstr->buflen -= linelen;
     133
     134    return line;
     135  }
     136
     137  return NULL;
     138}
     139
     140
     141static subtitle_t *sub_read_line_sami(demux_sputext_t *demuxstr, subtitle_t *current) {
     142
     143  static char line[LINE_LEN + 1];
     144  static char *s = NULL;
     145  char text[LINE_LEN + 1], *p, *q;
     146  int state;
     147
     148  p = NULL;
     149  current->lines = current->start = 0;
     150  current->end = -1;
     151  state = 0;
     152 
     153  /* read the first line */
     154  if (!s)
     155    if (!(s = read_line_from_input(demuxstr, line, LINE_LEN))) return 0;
     156 
     157  do {
     158    switch (state) {
     159     
     160    case 0: /* find "START=" */
     161      s = strstr (s, "Start=");
     162      if (s) {
     163        current->start = strtol (s + 6, &s, 0) / 10;
     164        state = 1; continue;
     165      }
     166      break;
     167     
     168    case 1: /* find "<P" */
     169      if ((s = strstr (s, "<P"))) { s += 2; state = 2; continue; }
     170      break;
     171     
     172    case 2: /* find ">" */
     173      if ((s = strchr (s, '>'))) { s++; state = 3; p = text; continue; }
     174      break;
     175     
     176    case 3: /* get all text until '<' appears */
     177      if (*s == '\0') { break; }
     178      else if (*s == '<') { state = 4; }
     179      else if (!strncasecmp (s, "&nbsp;", 6)) { *p++ = ' '; s += 6; }
     180      else if (*s == '\r') { s++; }
     181      else if (!strncasecmp (s, "<br>", 4) || *s == '\n') {
     182        *p = '\0'; p = text; trail_space (text);
     183        if (text[0] != '\0')
     184          current->text[current->lines++] = strdup (text);
     185        if (*s == '\n') s++; else s += 4;
     186      }
     187      else *p++ = *s++;
     188      continue;
     189     
     190    case 4: /* get current->end or skip <TAG> */
     191      q = strstr (s, "Start=");
     192      if (q) {
     193        current->end = strtol (q + 6, &q, 0) / 10 - 1;
     194        *p = '\0'; trail_space (text);
     195        if (text[0] != '\0')
     196          current->text[current->lines++] = strdup (text);
     197        if (current->lines > 0) { state = 99; break; }
     198        state = 0; continue;
     199      }
     200      s = strchr (s, '>');
     201      if (s) { s++; state = 3; continue; }
     202      break;
     203    }
     204   
     205    /* read next line */
     206    if (state != 99 && !(s = read_line_from_input (demuxstr, line, LINE_LEN)))
     207      return 0;
     208   
     209  } while (state != 99);
     210 
     211  return current;
     212}
     213
     214
     215static char *sub_readtext(char *source, char **dest) {
     216  int len=0;
     217  char *p=source;
     218 
     219  while ( !eol(*p) && *p!= '|' ) {
     220    p++,len++;
     221  }
     222 
     223  if (!dest)
     224    return (char*)ERR;
     225
     226  *dest= (char *)malloc (len+1);
     227  if (!(*dest))
     228    return (char*)ERR;
     229 
     230  strncpy(*dest, source, len);
     231  (*dest)[len]=0;
     232 
     233  while (*p=='\r' || *p=='\n' || *p=='|')
     234    p++;
     235 
     236  if (*p)  return p;  /* not-last text field */
     237  else return (char*)NULL;   /* last text field     */
     238}
     239
     240static subtitle_t *sub_read_line_microdvd(demux_sputext_t *demuxstr, subtitle_t *current) {
     241
     242  char line[LINE_LEN + 1];
     243  char line2[LINE_LEN + 1];
     244  char *p, *next;
     245  int i;
     246 
     247  memset (current, 0, sizeof(subtitle_t));
     248 
     249  current->end=-1;
     250  do {
     251    if (!read_line_from_input (demuxstr, line, LINE_LEN)) return NULL;
     252  } while ((sscanf (line, "{%ld}{}%" LINE_LEN_QUOT "[^\r\n]", &(current->start), line2) !=2) &&
     253           (sscanf (line, "{%ld}{%ld}%" LINE_LEN_QUOT "[^\r\n]", &(current->start), &(current->end),line2) !=3)
     254          );
     255 
     256  p=line2;
     257 
     258  next=p, i=0;
     259  while ((next =sub_readtext (next, &(current->text[i])))) {
     260    if (current->text[i]==ERR) return (subtitle_t *)ERR;
     261    i++;
     262    if (i>=SUB_MAX_TEXT) {
     263      printf ("Too many lines in a subtitle\n");
     264      current->lines=i;
     265      return current;
     266    }
     267  }
     268  current->lines= ++i;
     269 
     270  return current;
     271}
     272
     273static subtitle_t *sub_read_line_subviewer(demux_sputext_t *demuxstr, subtitle_t *current) {
     274
     275  char line[LINE_LEN + 1];
     276  int a1,a2,a3,a4,b1,b2,b3,b4;
     277  char *p=NULL, *q=NULL;
     278  int len;
     279 
     280  memset (current, 0, sizeof(subtitle_t));
     281 
     282  while (1) {
     283    if (!read_line_from_input(demuxstr, line, LINE_LEN)) return NULL;
     284    if (sscanf (line, "%d:%d:%d.%d,%d:%d:%d.%d",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4) < 8) {
     285      if (sscanf (line, "%d:%d:%d,%d,%d:%d:%d,%d",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4) < 8)
     286        continue;
     287    }
     288    current->start = a1*360000+a2*6000+a3*100+a4;
     289    current->end   = b1*360000+b2*6000+b3*100+b4;
     290   
     291    if (!read_line_from_input(demuxstr, line, LINE_LEN))
     292      return NULL;
     293   
     294    p=q=line;
     295    for (current->lines=1; current->lines <= SUB_MAX_TEXT; current->lines++) {
     296      for (q=p,len=0; *p && *p!='\r' && *p!='\n' && *p!='|' && strncasecmp(p,"[br]",4); p++,len++);
     297      current->text[current->lines-1]=(char *)malloc (len+1);
     298      if (!current->text[current->lines-1]) return (subtitle_t *)ERR;
     299      strncpy (current->text[current->lines-1], q, len);
     300      current->text[current->lines-1][len]='\0';
     301      if (!*p || *p=='\r' || *p=='\n') break;
     302      if (*p=='[') while (*p++!=']');
     303      if (*p=='|') p++;
     304    }
     305    if (current->lines > SUB_MAX_TEXT) current->lines = SUB_MAX_TEXT;
     306    break;
     307  }
     308  return current;
     309}
     310
     311static subtitle_t *sub_read_line_subrip(demux_sputext_t *demuxstr,subtitle_t *current) {
     312  char line[LINE_LEN + 1];
     313  int a1,a2,a3,a4,b1,b2,b3,b4;
     314  int i,end_sub;
     315 
     316  memset(current,0,sizeof(subtitle_t));
     317  do {
     318    if(!read_line_from_input(demuxstr,line,LINE_LEN))
     319      return NULL;
     320    i = sscanf(line,"%d:%d:%d%*[,.]%d --> %d:%d:%d%*[,.]%d",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4);
     321  } while(i < 8);
     322  current->start = a1*360000+a2*6000+a3*100+a4/10;
     323  current->end   = b1*360000+b2*6000+b3*100+b4/10;
     324  i=0;
     325  end_sub=0;
     326  do {
     327    char *p; /* pointer to the curently read char */
     328    char temp_line[SUB_BUFSIZE]; /* subtitle line that will be transfered to current->text[i] */
     329    int temp_index; /* ... and its index wich 'points' to the first EMPTY place -> last read char is at temp_index-1 if temp_index>0 */
     330    temp_line[SUB_BUFSIZE-1]='\0'; /* just in case... */
     331    if(!read_line_from_input(demuxstr,line,LINE_LEN)) {
     332      if(i)
     333        break; /* if something was read, transmit it */
     334      else
     335        return NULL; /* if not, repport EOF */
     336    }
     337    for(temp_index=0,p=line;*p!='\0' && !end_sub && temp_index<SUB_BUFSIZE && i<SUB_MAX_TEXT;p++) {
     338      switch(*p) {
     339        case '\\':
     340          if(*(p+1)=='N' || *(p+1)=='n') {
     341            temp_line[temp_index++]='\0'; /* end of curent line */
     342            p++;
     343          } else
     344            temp_line[temp_index++]=*p;
     345          break;
     346        case '{':
     347#if 0 /* italic not implemented in renderer, ignore them for now */
     348          if(!strncmp(p,"{\\i1}",5) && temp_index+3<SUB_BUFSIZE) {
     349            temp_line[temp_index++]='<';
     350            temp_line[temp_index++]='i';
     351            temp_line[temp_index++]='>';
     352#else
     353          if(!strncmp(p,"{\\i1}",5)) {
     354#endif
     355            p+=4;
     356          }
     357#if 0 /* italic not implemented in renderer, ignore them for now */
     358          else if(!strncmp(p,"{\\i0}",5) && temp_index+4<SUB_BUFSIZE) {
     359            temp_line[temp_index++]='<';
     360            temp_line[temp_index++]='/';
     361            temp_line[temp_index++]='i';
     362            temp_line[temp_index++]='>';
     363#else
     364          else if(!strncmp(p,"{\\i0}",5)) {
     365#endif
     366            p+=4;
     367          }
     368          else
     369            temp_line[temp_index++]=*p;
     370          break;
     371        case '\r': /* just ignore '\r's */
     372          break;
     373        case '\n':
     374          temp_line[temp_index++]='\0';
     375          break;
     376        default:
     377          temp_line[temp_index++]=*p;
     378          break;
     379      }
     380      if(temp_index>0) {
     381        if(temp_index==SUB_BUFSIZE)
     382          printf("Too many characters in a subtitle line\n");
     383        if(temp_line[temp_index-1]=='\0' || temp_index==SUB_BUFSIZE) {
     384          if(temp_index>1) { /* more than 1 char (including '\0') -> that is a valid one */
     385            current->text[i]=(char *)malloc(temp_index);
     386            if(!current->text[i])
     387              return (subtitle_t *)ERR;
     388            strncpy(current->text[i],temp_line,temp_index); /* temp_index<=SUB_BUFSIZE is always true here */
     389            i++;
     390            temp_index=0;
     391          } else
     392            end_sub=1;
     393        }
     394      }
     395    }
     396  } while(i<SUB_MAX_TEXT && !end_sub);
     397  if(i>=SUB_MAX_TEXT)
     398    printf("Too many lines in a subtitle\n");
     399  current->lines=i;
     400  return current;
     401}
     402
     403static subtitle_t *sub_read_line_vplayer(demux_sputext_t *demuxstr,subtitle_t *current) {
     404  char line[LINE_LEN + 1];
     405  int a1,a2,a3,b1,b2,b3;
     406  char *p=NULL, *next, *p2;
     407  int i;
     408 
     409  memset (current, 0, sizeof(subtitle_t));
     410   
     411  while (!current->text[0]) {
     412    if( demuxstr->next_line[0] == '\0' ) { /* if the buffer is empty.... */
     413      if( !read_line_from_input(demuxstr, line, LINE_LEN) ) return NULL;
     414    } else {
     415      /* ... get the current line from buffer. */
     416      strncpy( line, demuxstr->next_line, LINE_LEN);
     417      line[LINE_LEN] = '\0'; /* I'm scared. demuxstr makes me feel better. */
     418      demuxstr->next_line[0] = '\0'; /* mark the buffer as empty. */
     419    }
     420    /* Initialize buffer with next line */
     421    if( ! read_line_from_input( demuxstr, demuxstr->next_line, LINE_LEN) ) {
     422      demuxstr->next_line[0] = '\0';
     423      return NULL;
     424    }
     425    if( (sscanf( line,            "%d:%d:%d:", &a1, &a2, &a3) < 3) ||
     426        (sscanf( demuxstr->next_line, "%d:%d:%d:", &b1, &b2, &b3) < 3) )
     427      continue;
     428    current->start = a1*360000+a2*6000+a3*100;
     429    current->end   = b1*360000+b2*6000+b3*100;
     430    if ((current->end - current->start) > LINE_LEN)
     431      current->end = current->start + LINE_LEN; /* not too long though.  */
     432    /* teraz czas na wkopiowanie stringu */
     433    p=line;
     434    /* finds the body of the subtitle_t */
     435    for (i=0; i<3; i++){             
     436      p2=strchr( p, ':');
     437      if( p2 == NULL ) break;
     438      p=p2+1;
     439    }
     440     
     441    next=p;
     442    i=0;
     443    while( (next = sub_readtext( next, &(current->text[i]))) ) {
     444      if (current->text[i]==ERR)
     445        return (subtitle_t *)ERR;
     446      i++;
     447      if (i>=SUB_MAX_TEXT) {
     448        printf("Too many lines in a subtitle\n");
     449        current->lines=i;
     450        return current;
     451      }
     452    }
     453    current->lines=++i;
     454  }
     455  return current;
     456}
     457
     458static subtitle_t *sub_read_line_rt(demux_sputext_t *demuxstr,subtitle_t *current) {
     459  /*
     460   * TODO: This format uses quite rich (sub/super)set of xhtml
     461   * I couldn't check it since DTD is not included.
     462   * WARNING: full XML parses can be required for proper parsing
     463   */
     464  char line[LINE_LEN + 1];
     465  int a1,a2,a3,a4,b1,b2,b3,b4;
     466  char *p=NULL,*next=NULL;
     467  int i,len,plen;
     468 
     469  memset (current, 0, sizeof(subtitle_t));
     470 
     471  while (!current->text[0]) {
     472    if (!read_line_from_input(demuxstr, line, LINE_LEN)) return NULL;
     473    /*
     474     * TODO: it seems that format of time is not easily determined, it may be 1:12, 1:12.0 or 0:1:12.0
     475     * to describe the same moment in time. Maybe there are even more formats in use.
     476     */
     477    if ((len=sscanf (line, "<Time Begin=\"%d:%d:%d.%d\" End=\"%d:%d:%d.%d\"",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4)) < 8)
     478     
     479      plen=a1=a2=a3=a4=b1=b2=b3=b4=0;
     480    if (
     481        ((len=sscanf (line, "<%*[tT]ime %*[bB]egin=\"%d:%d\" %*[Ee]nd=\"%d:%d\"%*[^<]<clear/>%n",&a2,&a3,&b2,&b3,&plen)) < 4) &&
     482        ((len=sscanf (line, "<%*[tT]ime %*[bB]egin=\"%d:%d\" %*[Ee]nd=\"%d:%d.%d\"%*[^<]<clear/>%n",&a2,&a3,&b2,&b3,&b4,&plen)) < 5) &&
     483        /*      ((len=sscanf (line, "<%*[tT]ime %*[bB]egin=\"%d:%d.%d\" %*[Ee]nd=\"%d:%d\"%*[^<]<clear/>%n",&a2,&a3,&a4,&b2,&b3,&plen)) < 5) && */
     484        ((len=sscanf (line, "<%*[tT]ime %*[bB]egin=\"%d:%d.%d\" %*[Ee]nd=\"%d:%d.%d\"%*[^<]<clear/>%n",&a2,&a3,&a4,&b2,&b3,&b4,&plen)) < 6) &&
     485        ((len=sscanf (line, "<%*[tT]ime %*[bB]egin=\"%d:%d:%d.%d\" %*[Ee]nd=\"%d:%d:%d.%d\"%*[^<]<clear/>%n",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4,&plen)) < 8)
     486        )
     487      continue;
     488    current->start = a1*360000+a2*6000+a3*100+a4/10;
     489    current->end   = b1*360000+b2*6000+b3*100+b4/10;
     490    p=line;     p+=plen;i=0;
     491    /* TODO: I don't know what kind of convention is here for marking multiline subs, maybe <br/> like in xml? */
     492    next = strstr(line,"<clear/>")+8;i=0;
     493    while ((next =sub_readtext (next, &(current->text[i])))) {
     494      if (current->text[i]==ERR)
     495        return (subtitle_t *)ERR;
     496      i++;
     497      if (i>=SUB_MAX_TEXT) {
     498        printf("Too many lines in a subtitle\n");
     499        current->lines=i;
     500        return current;
     501      }
     502    }
     503    current->lines=i+1;
     504  }
     505  return current;
     506}
     507
     508static subtitle_t *sub_read_line_ssa(demux_sputext_t *demuxstr,subtitle_t *current) {
     509  int comma;
     510  static int max_comma = 32; /* let's use 32 for the case that the */
     511  /*  amount of commas increase with newer SSA versions */
     512 
     513  int hour1, min1, sec1, hunsec1, hour2, min2, sec2, hunsec2, nothing;
     514  int num;
     515  char line[LINE_LEN + 1], line3[LINE_LEN + 1], *line2;
     516  char *tmp;
     517 
     518  do {
     519    if (!read_line_from_input(demuxstr, line, LINE_LEN)) return NULL;
     520  } while (sscanf (line, "Dialogue: Marked=%d,%d:%d:%d.%d,%d:%d:%d.%d,"
     521                   "%[^\n\r]", &nothing,
     522                   &hour1, &min1, &sec1, &hunsec1,
     523                   &hour2, &min2, &sec2, &hunsec2,
     524                   line3) < 9
     525           &&
     526           sscanf (line, "Dialogue: %d,%d:%d:%d.%d,%d:%d:%d.%d,"
     527                   "%[^\n\r]", &nothing,
     528                   &hour1, &min1, &sec1, &hunsec1,
     529                   &hour2, &min2, &sec2, &hunsec2,
     530                   line3) < 9       );
     531 
     532  line2=strchr(line3, ',');
     533  if (!line2)
     534    return NULL;
     535 
     536  for (comma = 4; comma < max_comma; comma ++)
     537    {
     538      tmp = line2;
     539      if(!(tmp=strchr(++tmp, ','))) break;
     540      if(*(++tmp) == ' ') break;
     541      /* a space after a comma means we're already in a sentence */
     542      line2 = tmp;
     543    }
     544 
     545  if(comma < max_comma)max_comma = comma;
     546  /* eliminate the trailing comma */
     547  if(*line2 == ',') line2++;
     548 
     549  current->lines=0;num=0;
     550  current->start = 360000*hour1 + 6000*min1 + 100*sec1 + hunsec1;
     551  current->end   = 360000*hour2 + 6000*min2 + 100*sec2 + hunsec2;
     552 
     553  while (((tmp=strstr(line2, "\\n")) != NULL) || ((tmp=strstr(line2, "\\N")) != NULL) ){
     554    current->text[num]=(char *)malloc(tmp-line2+1);
     555    strncpy (current->text[num], line2, tmp-line2);
     556    current->text[num][tmp-line2]='\0';
     557    line2=tmp+2;
     558    num++;
     559    current->lines++;
     560    if (current->lines >=  SUB_MAX_TEXT) return current;
     561  }
     562 
     563  current->text[num]=strdup(line2);
     564  current->lines++;
     565 
     566  return current;
     567}
     568
     569/* Sylvain "Skarsnik" Colinet <scolinet@gmail.com>
     570 * From MPlayer subreader.c :
     571 *
     572 * PJS subtitles reader.
     573 * That's the "Phoenix Japanimation Society" format.
     574 * I found some of them in http://www.scriptsclub.org/ (used for anime).
     575 * The time is in tenths of second.
     576 *
     577 * by set, based on code by szabi (dunnowhat sub format ;-)
     578 */
     579
     580static subtitle_t *sub_read_line_pjs (demux_sputext_t *demuxstr, subtitle_t *current) {
     581  char line[LINE_LEN + 1];
     582  char text[LINE_LEN + 1];
     583  char *s, *d;
     584 
     585  memset (current, 0, sizeof(subtitle_t));
     586 
     587  if (!read_line_from_input(demuxstr, line, LINE_LEN))
     588    return NULL;
     589  for (s = line; *s && isspace(*s); s++);
     590  if (*s == 0)
     591    return NULL;
     592  if (sscanf (line, "%ld,%ld,", &(current->start),
     593              &(current->end)) <2)
     594    return (subtitle_t *)ERR;
     595  /* the files I have are in tenths of second */
     596  current->start *= 10;
     597  current->end *= 10;
     598 
     599  /* walk to the beggining of the string */
     600  for (; *s; s++) if (*s==',') break;
     601  if (*s) {
     602      for (s++; *s; s++) if (*s==',') break;
     603      if (*s) s++;
     604  }
     605  if (*s!='"') {
     606       return (subtitle_t *)ERR;
     607  }
     608  /* copy the string to the text buffer */
     609  for (s++, d=text; *s && *s!='"'; s++, d++)
     610      *d=*s;
     611  *d=0;
     612  current->text[0] = strdup(text);
     613  current->lines = 1;
     614 
     615  return current;
     616}
     617
     618static subtitle_t *sub_read_line_mpsub (demux_sputext_t *demuxstr, subtitle_t *current) {
     619  char line[LINE_LEN + 1];
     620  float a,b;
     621  int num=0;
     622  char *p, *q;
     623 
     624  do {
     625    if (!read_line_from_input(demuxstr, line, LINE_LEN))
     626      return NULL;
     627  } while (sscanf (line, "%f %f", &a, &b) !=2);
     628
     629  demuxstr->mpsub_position += (a*100.0);
     630  current->start = (int) demuxstr->mpsub_position;
     631  demuxstr->mpsub_position += (b*100.0);
     632  current->end = (int) demuxstr->mpsub_position;
     633 
     634  while (num < SUB_MAX_TEXT) {
     635    if (!read_line_from_input(demuxstr, line, LINE_LEN))
     636      return NULL;
     637
     638    p=line;
     639    while (isspace(*p))
     640      p++;
     641
     642    if (eol(*p) && num > 0)
     643      return current;
     644
     645    if (eol(*p))
     646      return NULL;
     647   
     648    for (q=p; !eol(*q); q++);
     649    *q='\0';
     650    if (strlen(p)) {
     651      current->text[num]=strdup(p);
     652      printf(">%s<\n",p);
     653      current->lines = ++num;
     654    } else {
     655      if (num)
     656        return current;
     657      else
     658        return NULL;
     659    }
     660  }
     661
     662  return NULL;
     663}
     664
     665static subtitle_t *sub_read_line_aqt (demux_sputext_t *demuxstr, subtitle_t *current) {
     666  char line[LINE_LEN + 1];
     667
     668  memset (current, 0, sizeof(subtitle_t));
     669
     670  while (1) {
     671    /* try to locate next subtitle_t */
     672    if (!read_line_from_input(demuxstr, line, LINE_LEN))
     673      return NULL;
     674    if (!(sscanf (line, "-->> %ld", &(current->start)) <1))
     675      break;
     676  }
     677 
     678  if (!read_line_from_input(demuxstr, line, LINE_LEN))
     679    return NULL;
     680 
     681  sub_readtext((char *) &line,&current->text[0]);
     682  current->lines = 1;
     683  current->end = -1;
     684 
     685  if (!read_line_from_input(demuxstr, line, LINE_LEN))
     686    return current;;
     687 
     688  sub_readtext((char *) &line,&current->text[1]);
     689  current->lines = 2;
     690 
     691  if ((current->text[0][0]==0) && (current->text[1][0]==0)) {
     692    return NULL;
     693  }
     694 
     695  return current;
     696}
     697
     698static subtitle_t *sub_read_line_jacobsub(demux_sputext_t *demuxstr, subtitle_t *current) {
     699    char line1[LINE_LEN], line2[LINE_LEN], directive[LINE_LEN], *p, *q;
     700    unsigned a1, a2, a3, a4, b1, b2, b3, b4, comment = 0;
     701    static unsigned jacoTimeres = 30;
     702    static int jacoShift = 0;
     703
     704    memset(current, 0, sizeof(subtitle_t));
     705    memset(line1, 0, LINE_LEN);
     706    memset(line2, 0, LINE_LEN);
     707    memset(directive, 0, LINE_LEN);
     708    while (!current->text[0]) {
     709        if (!read_line_from_input(demuxstr, line1, LINE_LEN)) {
     710            return NULL;
     711        }
     712        if (sscanf
     713            (line1, "%u:%u:%u.%u %u:%u:%u.%u %" LINE_LEN_QUOT "[^\n\r]", &a1, &a2, &a3, &a4,
     714             &b1, &b2, &b3, &b4, line2) < 9) {
     715            if (sscanf(line1, "@%u @%u %" LINE_LEN_QUOT "[^\n\r]", &a4, &b4, line2) < 3) {
     716                if (line1[0] == '#') {
     717                    int hours = 0, minutes = 0, seconds, delta, inverter =
     718                        1;
     719                    unsigned units = jacoShift;
     720                    switch (toupper(line1[1])) {
     721                    case 'S':
     722                        if (isalpha(line1[2])) {
     723                            delta = 6;
     724                        } else {
     725                            delta = 2;
     726                        }
     727                        if (sscanf(&line1[delta], "%d", &hours)) {
     728                            if (hours < 0) {
     729                                hours *= -1;
     730                                inverter = -1;
     731                            }
     732                            if (sscanf(&line1[delta], "%*d:%d", &minutes)) {
     733                                if (sscanf
     734                                    (&line1[delta], "%*d:%*d:%d",
     735                                     &seconds)) {
     736                                    sscanf(&line1[delta], "%*d:%*d:%*d.%d",
     737                                           &units);
     738                                } else {
     739                                    hours = 0;
     740                                    sscanf(&line1[delta], "%d:%d.%d",
     741                                           &minutes, &seconds, &units);
     742                                    minutes *= inverter;
     743                                }
     744                            } else {
     745                                hours = minutes = 0;
     746                                sscanf(&line1[delta], "%d.%d", &seconds,
     747                                       &units);
     748                                seconds *= inverter;
     749                            }
     750                            jacoShift =
     751                                ((hours * 3600 + minutes * 60 +
     752                                  seconds) * jacoTimeres +
     753                                 units) * inverter;
     754                        }
     755                        break;
     756                    case 'T':
     757                        if (isalpha(line1[2])) {
     758                            delta = 8;
     759                        } else {
     760                            delta = 2;
     761                        }
     762                        sscanf(&line1[delta], "%u", &jacoTimeres);
     763                        break;
     764                    }
     765                }
     766                continue;
     767            } else {
     768                current->start =
     769                    (unsigned long) ((a4 + jacoShift) * 100.0 /
     770                                     jacoTimeres);
     771                current->end =
     772                    (unsigned long) ((b4 + jacoShift) * 100.0 /
     773                                     jacoTimeres);
     774            }
     775        } else {
     776            current->start =
     777                (unsigned
     778                 long) (((a1 * 3600 + a2 * 60 + a3) * jacoTimeres + a4 +
     779                         jacoShift) * 100.0 / jacoTimeres);
     780            current->end =
     781                (unsigned
     782                 long) (((b1 * 3600 + b2 * 60 + b3) * jacoTimeres + b4 +
     783                         jacoShift) * 100.0 / jacoTimeres);
     784        }
     785        current->lines = 0;
     786        p = line2;
     787        while ((*p == ' ') || (*p == '\t')) {
     788            ++p;
     789        }
     790        if (isalpha(*p)||*p == '[') {
     791            int cont, jLength;
     792
     793            if (sscanf(p, "%s %" LINE_LEN_QUOT "[^\n\r]", directive, line1) < 2)
     794                return (subtitle_t *)ERR;
     795            jLength = strlen(directive);
     796            for (cont = 0; cont < jLength; ++cont) {
     797                if (isalpha(*(directive + cont)))
     798                    *(directive + cont) = toupper(*(directive + cont));
     799            }
     800            if ((strstr(directive, "RDB") != NULL)
     801                || (strstr(directive, "RDC") != NULL)
     802                || (strstr(directive, "RLB") != NULL)
     803                || (strstr(directive, "RLG") != NULL)) {
     804                continue;
     805            }
     806            /* no alignment */
     807#if 0
     808            if (strstr(directive, "JL") != NULL) {
     809                current->alignment = SUB_ALIGNMENT_HLEFT;
     810            } else if (strstr(directive, "JR") != NULL) {
     811                current->alignment = SUB_ALIGNMENT_HRIGHT;
     812            } else {
     813                current->alignment = SUB_ALIGNMENT_HCENTER;
     814            }
     815#endif
     816            strcpy(line2, line1);
     817            p = line2;
     818        }
     819        for (q = line1; (!eol(*p)) && (current->lines < SUB_MAX_TEXT); ++p) {
     820            switch (*p) {
     821            case '{':
     822                comment++;
     823                break;
     824            case '}':
     825                if (comment) {
     826                    --comment;
     827                    /* the next line to get rid of a blank after the comment */
     828                    if ((*(p + 1)) == ' ')
     829                        p++;
     830                }
     831                break;
     832            case '~':
     833                if (!comment) {
     834                    *q = ' ';
     835                    ++q;
     836                }
     837                break;
     838            case ' ':
     839            case '\t':
     840                if ((*(p + 1) == ' ') || (*(p + 1) == '\t'))
     841                    break;
     842                if (!comment) {
     843                    *q = ' ';
     844                    ++q;
     845                }
     846                break;
     847            case '\\':
     848                if (*(p + 1) == 'n') {
     849                    *q = '\0';
     850                    q = line1;
     851                    current->text[current->lines++] = strdup(line1);
     852                    ++p;
     853                    break;
     854                }
     855                if ((toupper(*(p + 1)) == 'C')
     856                    || (toupper(*(p + 1)) == 'F')) {
     857                    ++p,++p;
     858                    break;
     859                }
     860                if ((*(p + 1) == 'B') || (*(p + 1) == 'b') ||
     861                    /* actually this means "insert current date here" */
     862                    (*(p + 1) == 'D') ||
     863                    (*(p + 1) == 'I') || (*(p + 1) == 'i') ||
     864                    (*(p + 1) == 'N') ||
     865                    /* actually this means "insert current time here" */
     866                    (*(p + 1) == 'T') ||       
     867                    (*(p + 1) == 'U') || (*(p + 1) == 'u')) {
     868                    ++p;
     869                    break;
     870                }
     871                if ((*(p + 1) == '\\') ||
     872                    (*(p + 1) == '~') || (*(p + 1) == '{')) {
     873                    ++p;
     874                } else if (eol(*(p + 1))) {
     875                    if (!read_line_from_input(demuxstr, directive, LINE_LEN))
     876                        return NULL;
     877                    trail_space(directive);
     878                    strncat(line2, directive,
     879                            (LINE_LEN > 511) ? LINE_LEN : 511);
     880                    break;
     881                }
     882            default:
     883                if (!comment) {
     884                    *q = *p;
     885                    ++q;
     886                }
     887            }
     888        }
     889        *q = '\0';
     890        current->text[current->lines] = strdup(line1);
     891    }
     892    current->lines++;
     893    return current;
     894}
     895
     896static subtitle_t *sub_read_line_subviewer2(demux_sputext_t *demuxstr, subtitle_t *current) {
     897    char line[LINE_LEN+1];
     898    int a1,a2,a3,a4;
     899    char *p=NULL;
     900    int i,len;
     901   
     902    while (!current->text[0]) {
     903        if (!read_line_from_input(demuxstr, line, LINE_LEN)) return NULL;
     904        if (line[0]!='{')
     905            continue;
     906        if ((len=sscanf (line, "{T %d:%d:%d:%d",&a1,&a2,&a3,&a4)) < 4)
     907            continue;
     908        current->start = a1*360000+a2*6000+a3*100+a4/10;
     909        for (i=0; i<SUB_MAX_TEXT;) {
     910            if (!read_line_from_input(demuxstr, line, LINE_LEN)) break;
     911            if (line[0]=='}') break;
     912            len=0;
     913            for (p=line; *p!='\n' && *p!='\r' && *p; ++p,++len);
     914            if (len) {
     915                current->text[i]=(char *)malloc (len+1);
     916                if (!current->text[i]) return (subtitle_t *)ERR;
     917                strncpy (current->text[i], line, len); current->text[i][len]='\0';
     918                ++i;
     919            } else {
     920                break;
     921            }
     922        }
     923        current->lines=i;
     924    }
     925    return current;
     926}
     927
     928static subtitle_t *sub_read_line_subrip09 (demux_sputext_t *demuxstr, subtitle_t *current) {
     929  char line[LINE_LEN + 1];
     930  char *next;
     931  int h, m, s;
     932  int i;
     933 
     934  memset (current, 0, sizeof(subtitle_t));
     935 
     936  do {
     937    if (!read_line_from_input (demuxstr, line, LINE_LEN)) return NULL;
     938  } while (sscanf (line, "[%d:%d:%d]", &h, &m, &s) != 3);
     939
     940  if (!read_line_from_input (demuxstr, line, LINE_LEN)) return NULL;
     941
     942  current->start = 360000 * h + 6000 * m + 100 * s;
     943  current->end = -1;
     944
     945  next=line;
     946  i=0;
     947  while ((next = sub_readtext (next, &(current->text[i])))) {
     948    if (current->text[i]==ERR) return (subtitle_t *)ERR;
     949    i++;
     950    if (i>=SUB_MAX_TEXT) {
     951      printf("Too many lines in a subtitle\n");
     952      current->lines=i;
     953      return current;
     954    }
     955  }
     956  current->lines= ++i;
     957 
     958  return current;
     959}
     960
     961/* Code from subreader.c of MPlayer
     962** Sylvain "Skarsnik" Colinet <scolinet@gmail.com>
     963*/
     964
     965static subtitle_t *sub_read_line_mpl2(demux_sputext_t *demuxstr, subtitle_t *current) {
     966  char line[LINE_LEN+1];
     967  char line2[LINE_LEN+1];
     968  char *p, *next;
     969  int i;
     970
     971  memset (current, 0, sizeof(subtitle_t));
     972  do {
     973     if (!read_line_from_input (demuxstr, line, LINE_LEN)) return NULL;
     974  } while ((sscanf (line,
     975                      "[%ld][%ld]%[^\r\n]",
     976                      &(current->start), &(current->end), line2) < 3));
     977  current->start *= 10;
     978  current->end *= 10;
     979  p=line2;
     980
     981  next=p, i=0;
     982  while ((next = sub_readtext (next, &(current->text[i])))) {
     983      if (current->text[i] == ERR) {return (subtitle_t *)ERR;}
     984      i++;
     985      if (i >= SUB_MAX_TEXT) {
     986        printf("Too many lines in a subtitle\n");
     987        current->lines = i;
     988        return current;
     989      }
     990    }
     991  current->lines= ++i;
     992
     993  return current;
     994}
     995
     996
     997static int sub_autodetect (demux_sputext_t *demuxstr) {
     998
     999  char line[LINE_LEN + 1];
     1000  int  i, j=0;
     1001  char p;
     1002 
     1003  while (j < 100) {
     1004    j++;
     1005    if (!read_line_from_input(demuxstr, line, LINE_LEN))
     1006      return FORMAT_UNKNOWN;
     1007
     1008    if ((sscanf (line, "{%d}{}", &i)==1) ||
     1009        (sscanf (line, "{%d}{%d}", &i, &i)==2)) {
     1010      demuxstr->uses_time=0;
     1011      return FORMAT_MICRODVD;
     1012    }
     1013
     1014    if (sscanf (line, "%d:%d:%d%*[,.]%d --> %d:%d:%d%*[,.]%d", &i, &i, &i, &i, &i, &i, &i, &i)==8) {
     1015      demuxstr->uses_time=1;
     1016      return FORMAT_SUBRIP;
     1017    }
     1018
     1019    if (sscanf (line, "%d:%d:%d.%d,%d:%d:%d.%d",     &i, &i, &i, &i, &i, &i, &i, &i)==8){
     1020      demuxstr->uses_time=1;
     1021      return FORMAT_SUBVIEWER;
     1022    }
     1023
     1024    if (sscanf (line, "%d:%d:%d,%d,%d:%d:%d,%d",     &i, &i, &i, &i, &i, &i, &i, &i)==8){
     1025      demuxstr->uses_time=1;
     1026      return FORMAT_SUBVIEWER;
     1027    }
     1028
     1029    if (strstr (line, "<SAMI>")) {
     1030      demuxstr->uses_time=1;
     1031      return FORMAT_SAMI;
     1032    }
     1033    if (sscanf (line, "%d:%d:%d:",     &i, &i, &i )==3) {
     1034      demuxstr->uses_time=1;
     1035      return FORMAT_VPLAYER;
     1036    }
     1037    /*
     1038     * A RealText format is a markup language, starts with <window> tag,
     1039     * options (behaviour modifiers) are possible.
     1040     */
     1041    if ( !strcasecmp(line, "<window") ) {
     1042      demuxstr->uses_time=1;
     1043      return FORMAT_RT;
     1044    }
     1045    if ((!memcmp(line, "Dialogue: Marked", 16)) || (!memcmp(line, "Dialogue: ", 10))) {
     1046      demuxstr->uses_time=1;
     1047      return FORMAT_SSA;
     1048    }
     1049    if (sscanf (line, "%d,%d,\"%c", &i, &i, (char *) &i) == 3) {
     1050      demuxstr->uses_time=0;
     1051      return FORMAT_PJS;
     1052    }
     1053    if (sscanf (line, "FORMAT=%d", &i) == 1) {
     1054      demuxstr->uses_time=0;
     1055      return FORMAT_MPSUB;
     1056    }
     1057    if (sscanf (line, "FORMAT=TIM%c", &p)==1 && p=='E') {
     1058      demuxstr->uses_time=1;
     1059      return FORMAT_MPSUB;
     1060    }
     1061    if (strstr (line, "-->>")) {
     1062      demuxstr->uses_time=0;
     1063      return FORMAT_AQTITLE;
     1064    }
     1065    if (sscanf(line, "@%d @%d", &i, &i) == 2 ||
     1066        sscanf(line, "%d:%d:%d.%d %d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i) == 8) {
     1067      demuxstr->uses_time = 1;
     1068      return FORMAT_JACOBSUB;
     1069    }
     1070    if (sscanf(line, "{T %d:%d:%d:%d",&i, &i, &i, &i) == 4) {
     1071      demuxstr->uses_time = 1;
     1072      return FORMAT_SUBVIEWER2;
     1073    }
     1074    if (sscanf(line, "[%d:%d:%d]", &i, &i, &i) == 3) {
     1075      demuxstr->uses_time = 1;
     1076      return FORMAT_SUBRIP09;
     1077    }
     1078 
     1079    if (sscanf (line, "[%d][%d]", &i, &i) == 2) {
     1080      demuxstr->uses_time = 1;
     1081      return FORMAT_MPL2;
     1082    }
     1083  }
     1084  return FORMAT_UNKNOWN;  /* too many bad lines */
     1085}
     1086
     1087subtitle_t *sub_read_file (demux_sputext_t *demuxstr) {
     1088
     1089  int n_max;
     1090  int timeout;
     1091  subtitle_t *first;
     1092  subtitle_t * (*func[])(demux_sputext_t *demuxstr,subtitle_t *dest)=
     1093  {
     1094    sub_read_line_microdvd,
     1095    sub_read_line_subrip,
     1096    sub_read_line_subviewer,
     1097    sub_read_line_sami,
     1098    sub_read_line_vplayer,
     1099    sub_read_line_rt,
     1100    sub_read_line_ssa,
     1101    sub_read_line_pjs,
     1102    sub_read_line_mpsub,
     1103    sub_read_line_aqt,
     1104    sub_read_line_jacobsub,
     1105    sub_read_line_subviewer2,
     1106    sub_read_line_subrip09,
     1107    sub_read_line_mpl2,
     1108  };
     1109
     1110  /* Rewind (sub_autodetect() needs to read input from the beginning) */
     1111  if(demuxstr->rbuffer->Seek(0, SEEK_SET) == -1) {
     1112    printf("seek failed.\n");
     1113    return NULL;
     1114  }
     1115  demuxstr->buflen = 0;
     1116  demuxstr->emptyReads = 0;
     1117
     1118  demuxstr->format=sub_autodetect (demuxstr);
     1119  if (demuxstr->format==FORMAT_UNKNOWN) {
     1120    return NULL;
     1121  }
     1122
     1123  /*printf("Detected subtitle file format: %d\n", demuxstr->format);*/
     1124   
     1125  /* Rewind */
     1126  if(demuxstr->rbuffer->Seek(0, SEEK_SET) == -1) {
     1127    printf("seek failed.\n");
     1128    return NULL;
     1129  }
     1130  demuxstr->buflen = 0;
     1131  demuxstr->emptyReads = 0;
     1132
     1133  demuxstr->num=0;n_max=32;
     1134  first = (subtitle_t *) malloc(n_max*sizeof(subtitle_t));
     1135  if(!first) return NULL;
     1136  timeout = MAX_TIMEOUT;
     1137
     1138  if (demuxstr->uses_time) timeout *= 100;
     1139  else timeout *= 10;
     1140
     1141  while(1) {
     1142    subtitle_t *sub;
     1143
     1144    if(demuxstr->num>=n_max){
     1145      n_max+=16;
     1146      first=(subtitle_t *)realloc(first,n_max*sizeof(subtitle_t));
     1147    }
     1148
     1149    sub = func[demuxstr->format] (demuxstr, &first[demuxstr->num]);
     1150
     1151    if (!sub)
     1152      break;   /* EOF */
     1153
     1154    if (sub==ERR)
     1155      ++demuxstr->errs;
     1156    else {
     1157      if (demuxstr->num > 0 && first[demuxstr->num-1].end == -1) {
     1158        /* end time not defined in the subtitle */
     1159        if (timeout > 0) {
     1160          /* timeout */
     1161          if (timeout > sub->start - first[demuxstr->num-1].start) {
     1162            first[demuxstr->num-1].end = sub->start;
     1163          } else
     1164            first[demuxstr->num-1].end = first[demuxstr->num-1].start + timeout;
     1165        } else {
     1166          /* no timeout */
     1167          first[demuxstr->num-1].end = sub->start;
     1168        }
     1169      }
     1170      ++demuxstr->num; /* Error vs. Valid */
     1171    }
     1172  }
     1173  /* timeout of last subtitle */
     1174  if (demuxstr->num > 0 && first[demuxstr->num-1].end == -1)
     1175    if (timeout > 0) {
     1176      first[demuxstr->num-1].end = first[demuxstr->num-1].start + timeout;
     1177    }
     1178
     1179#ifdef DEBUX_XINE_DEMUX_SPUTEXT
     1180  {
     1181    char buffer[1024];
     1182
     1183    sprintf(buffer, "Read %i subtitles", demuxstr->num);
     1184
     1185    if(demuxstr->errs)
     1186      sprintf(buffer + strlen(buffer), ", %i bad line(s).\n", demuxstr->errs);
     1187    else
     1188      strcat(buffer, "\n");
     1189   
     1190    printf("%s", buffer);
     1191  }
     1192#endif
     1193 
     1194  return first;
     1195}
     1196
  • libs/libmythtv/xine_demux_sputext.h

     
    11#ifndef XINE_DEMUX_SPUTEXT_H
    22#define XINE_DEMUX_SPUTEXT_H
    33
    4 #ifdef __cplusplus
    5 extern "C" {
    6 #endif
    7 
    84#include <ctype.h>
    95#include <stdio.h>
    106
     7#include "RingBuffer.h"
     8
    119#define SUB_BUFSIZE   1024
    1210#define SUB_MAX_TEXT  5
    1311#define MAX_TIMEOUT 4
     
    2624
    2725typedef struct {
    2826
    29   FILE*              file_ptr;
     27  RingBuffer*        rbuffer;
    3028
    3129  int                status;
    3230
    3331  char               buf[SUB_BUFSIZE];
    3432  off_t              buflen;
     33  off_t              emptyReads;
    3534
    3635  float              mpsub_position; 
    3736
     
    4847
    4948subtitle_t *sub_read_file (demux_sputext_t*);
    5049
    51 #ifdef __cplusplus
    52 }
    5350#endif
    54 
    55 #endif
  • libs/libmythtv/libmythtv.pro

     
    269269
    270270    # Text subtitle parser
    271271    HEADERS += textsubtitleparser.h     xine_demux_sputext.h
    272     SOURCES += textsubtitleparser.cpp   xine_demux_sputext.c
     272    SOURCES += textsubtitleparser.cpp   xine_demux_sputext.cpp
    273273
    274274    # A/V decoders
    275275    HEADERS += decoderbase.h
  • libs/libmythtv/playercontext.cpp

     
    11#include <math.h>
    22#include <qtimer.h>
    33#include <qpainter.h>
     4#include <QDir>
    45
    56#include "playercontext.h"
    67#include "NuppelVideoPlayer.h"
     
    1112#include "dialogbox.h"
    1213#include "util-osx-cocoa.h"
    1314#include "videoouttypes.h"
     15#include "storagegroup.h"
    1416
    1517#define LOC QString("playCtx: ")
    1618#define LOC_ERR QString("playCtx, Error: ")
     
    471473        _nvp->SetNoAudio();
    472474    else
    473475    {
    474         _nvp->LoadExternalSubtitles(buffer->GetFilename());
     476        LoadExternalSubtitles(_nvp, buffer->GetFilename());
    475477    }
    476478
    477479    if ((embedwinid > 0) && embedbounds)
     
    543545    return StartDecoderThread(maxWait);
    544546}
    545547
     548bool PlayerContext::LoadExternalSubtitles(NuppelVideoPlayer *nvp,
     549                               const QString &videoFile)
     550{
     551    if (videoFile.isEmpty())
     552        return false;
     553
     554    QString fileName = videoFile;
     555    QString dirName  = ".";
     556
     557    int dirPos = videoFile.lastIndexOf(QChar('/'));
     558    if (dirPos > 0)
     559    {
     560        fileName = videoFile.mid(dirPos + 1);
     561        dirName = videoFile.left(dirPos);
     562    }
     563
     564    QString baseName = fileName;
     565    int suffixPos = fileName.lastIndexOf(QChar('.'));
     566    if (suffixPos > 0)
     567        baseName = fileName.left(suffixPos);
     568
     569    VERBOSE(VB_IMPORTANT, LOC +
     570            QString("Parsing for %1 in %2.").arg(fileName).arg(dirName));
     571
     572    // The dir listing does not work if the filename has the following chars,
     573    // so we convert them to the wildcard '?'
     574    baseName = baseName.replace("[", "?").replace("]", "?");
     575    baseName = baseName.replace("(", "?").replace(")", "?");
     576
     577    // Some Qt versions do not accept paths in the search string of
     578    // entryList() so we have to set the dir first
     579    QDir dir;
     580    dir.setPath(dirName);
     581
     582    // Try to find files with the same base name, but ending with
     583    // '.srt', '.sub', or '.txt'
     584    QStringList el;
     585    el += baseName + ".srt";
     586    el += baseName + ".sub";
     587    el += baseName + ".txt";
     588    QStringList candidates = dir.entryList(el);
     589
     590    bool found = false;
     591    QString candidate = "";
     592
     593    if (dirName.startsWith("myth://"))
     594    {
     595        QString sgroup = "";
     596        if (dirName.indexOf('@') > -1)
     597            sgroup = dirName.mid(7, dirName.indexOf('@', 7) - 7);
     598        StorageGroup sg(sgroup);
     599        QStringList::const_iterator it = el.begin();
     600        for (; (it != el.end()) && !found; ++it)
     601        {
     602            found = sg.FileExists(*it);
     603            if (found = true)
     604            {
     605                QString subPath;
     606                candidate = *it;
     607                subPath = dirName + "/" + candidate;
     608                nvp->LoadExternalSubtitles(subPath);
     609            }
     610        }
     611    }
     612    else
     613    {
     614        QStringList::const_iterator it = candidates.begin();
     615        for (; (it != candidates.end()) && !found; ++it)
     616        {
     617            candidate = dirName + "/" + *it;
     618            if (nvp->LoadExternalSubtitles(candidate))
     619                found = true;
     620        }
     621    }
     622
     623    if (found)
     624    {
     625        VERBOSE(VB_PLAYBACK, LOC +
     626                QString("Loaded text subtitles from '%1'.").arg(candidate));
     627    }
     628
     629    return found;
     630}
     631
    546632/** \fn PlayerContext::StartDecoderThread(int)
    547633 *  \brief Starts player, must be called after StartRecorder().
    548634 *  \param maxWait How long to wait for NuppelVideoPlayer to start playing.
  • libs/libmythtv/playercontext.h

     
    4747    bool CreateNVP(TV *tv, QWidget *widget,
    4848                   TVState desiredState,
    4949                   WId embedwinid, const QRect *embedBounds);
     50    bool LoadExternalSubtitles(NuppelVideoPlayer *nvp,
     51                                              const QString &videoFile);
    5052    void TeardownPlayer(void);
    5153    bool StartDecoderThread(int maxWait = -1);
    5254    bool StartOSD(TV *tv);