summaryrefslogtreecommitdiff
path: root/src/libsputext
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsputext')
-rw-r--r--src/libsputext/Makefile.am14
-rw-r--r--src/libsputext/demux_sputext.c1493
-rw-r--r--src/libsputext/xine_sputext_decoder.c1215
3 files changed, 0 insertions, 2722 deletions
diff --git a/src/libsputext/Makefile.am b/src/libsputext/Makefile.am
deleted file mode 100644
index ad6c1b776..000000000
--- a/src/libsputext/Makefile.am
+++ /dev/null
@@ -1,14 +0,0 @@
-include $(top_builddir)/misc/Makefile.plugins
-include $(top_srcdir)/misc/Makefile.common
-
-AM_LDFLAGS = $(xineplug_ldflags)
-
-xineplug_LTLIBRARIES = xineplug_decode_sputext.la xineplug_dmx_sputext.la
-
-xineplug_dmx_sputext_la_SOURCES = demux_sputext.c
-xineplug_dmx_sputext_la_LIBADD = $(XINE_LIB) $(LTLIBINTL)
-xineplug_dmx_sputext_la_CFLAGS = $(VISIBILITY_FLAG)
-
-xineplug_decode_sputext_la_SOURCES = xine_sputext_decoder.c
-xineplug_decode_sputext_la_LIBADD = $(XINE_LIB) $(LTLIBINTL)
-xineplug_decode_sputext_la_CFLAGS = $(VISIBILITY_FLAG)
diff --git a/src/libsputext/demux_sputext.c b/src/libsputext/demux_sputext.c
deleted file mode 100644
index dd5958044..000000000
--- a/src/libsputext/demux_sputext.c
+++ /dev/null
@@ -1,1493 +0,0 @@
-/*
- * Copyright (C) 2000-2003 the xine project
- *
- * This file is part of xine, a free video player.
- *
- * xine 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.
- *
- * xine 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, USA
- *
- * code based on old libsputext/xine_decoder.c
- *
- * code based on mplayer module:
- *
- * Subtitle reader with format autodetection
- *
- * Written by laaz
- * Some code cleanup & realloc() by A'rpi/ESP-team
- * dunnowhat sub format by szabi
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <ctype.h>
-
-#define LOG_MODULE "demux_sputext"
-#define LOG_VERBOSE
-/*
-#define LOG
-*/
-
-#include "xine_internal.h"
-#include "xineutils.h"
-#include "../demuxers/demux.h"
-
-#define ERR (void *)-1
-#define SUB_MAX_TEXT 5
-#define SUB_BUFSIZE 1024
-#define LINE_LEN 1000
-#define LINE_LEN_QUOT "1000"
-
-/*
- * Demuxer typedefs
- */
-
-typedef struct {
-
- int lines;
-
- long start; /* csecs */
- long end; /* csecs */
-
- char *text[SUB_MAX_TEXT];
-
-} subtitle_t;
-
-
-typedef struct {
-
- demux_plugin_t demux_plugin;
- xine_stream_t *stream;
- input_plugin_t *input;
-
- int status;
-
- char buf[SUB_BUFSIZE];
- off_t buflen;
-
- float mpsub_position;
-
- int uses_time;
- int errs;
- subtitle_t *subtitles;
- int num; /* number of subtitle structs */
- int cur; /* current subtitle */
- int format; /* constants see below */
- char next_line[SUB_BUFSIZE]; /* a buffer for next line read from file */
-
-} demux_sputext_t;
-
-typedef struct demux_sputext_class_s {
-
- demux_class_t demux_class;
-
- int max_timeout; /* default timeout of hidding subtitles */
-
-} demux_sputext_class_t;
-
-/*
- * Demuxer code start
- */
-
-#define FORMAT_UNKNOWN -1
-#define FORMAT_MICRODVD 0
-#define FORMAT_SUBRIP 1
-#define FORMAT_SUBVIEWER 2
-#define FORMAT_SAMI 3
-#define FORMAT_VPLAYER 4
-#define FORMAT_RT 5
-#define FORMAT_SSA 6 /* Sub Station Alpha */
-#define FORMAT_PJS 7
-#define FORMAT_MPSUB 8
-#define FORMAT_AQTITLE 9
-#define FORMAT_JACOBSUB 10
-#define FORMAT_SUBVIEWER2 11
-#define FORMAT_SUBRIP09 12
-#define FORMAT_MPL2 13 /*Mplayer sub 2 ?*/
-
-static int eol(char p) {
- return (p=='\r' || p=='\n' || p=='\0');
-}
-
-static inline void trail_space(char *s) {
- while (isspace(*s)) {
- char *copy = s;
- do {
- copy[0] = copy[1];
- copy++;
- } while(*copy);
- }
- size_t i = strlen(s) - 1;
- while (i > 0 && isspace(s[i]))
- s[i--] = '\0';
-}
-
-/*
- * Reimplementation of fgets() using the input->read() method.
- */
-static char *read_line_from_input(demux_sputext_t *this, char *line, off_t len) {
- off_t nread = 0;
-
- if ((len - this->buflen) > 512 && len < SUB_BUFSIZE) {
- if((nread = this->input->read(this->input,
- &this->buf[this->buflen], len - this->buflen)) < 0) {
- xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "read failed.\n");
- return NULL;
- }
- }
-
- this->buflen += nread;
- this->buf[this->buflen] = '\0';
-
- char *s = strchr(this->buf, '\n');
-
- if (line && (s || this->buflen)) {
-
- size_t linelen = s ? (s - this->buf) + 1 : this->buflen;
-
- memcpy(line, this->buf, linelen);
- line[linelen] = '\0';
-
- memmove(this->buf, &this->buf[linelen], SUB_BUFSIZE - linelen);
- this->buflen -= linelen;
-
- return line;
- }
-
- return NULL;
-}
-
-
-static subtitle_t *sub_read_line_sami(demux_sputext_t *this, subtitle_t *current) {
-
- static char line[LINE_LEN + 1];
- static char *s = NULL;
- char text[LINE_LEN + 1];
-
- char *p = NULL;
- current->lines = current->start = 0;
- current->end = -1;
- int state = 0;
-
- /* read the first line */
- if (!s)
- if (!(s = read_line_from_input(this, line, LINE_LEN))) return 0;
-
- do {
- switch (state) {
-
- case 0: /* find "START=" */
- s = strstr (s, "Start=");
- if (s) {
- current->start = strtol (s + 6, &s, 0) / 10;
- state = 1; continue;
- }
- break;
-
- case 1: /* find "<P" */
- if ((s = strstr (s, "<P"))) { s += 2; state = 2; continue; }
- break;
-
- case 2: /* find ">" */
- if ((s = strchr (s, '>'))) { s++; state = 3; p = text; continue; }
- break;
-
- case 3: /* get all text until '<' appears */
- if (*s == '\0') { break; }
- else if (*s == '<') { state = 4; }
- else if (!strncasecmp (s, "&nbsp;", 6)) { *p++ = ' '; s += 6; }
- else if (*s == '\r') { s++; }
- else if (!strncasecmp (s, "<br>", 4) || *s == '\n') {
- *p = '\0'; p = text; trail_space (text);
- if (text[0] != '\0')
- current->text[current->lines++] = strdup (text);
- if (*s == '\n') s++; else s += 4;
- }
- else *p++ = *s++;
- continue;
-
- case 4: /* get current->end or skip <TAG> */
- {
- char *q = strstr (s, "Start=");
- if (q) {
- current->end = strtol (q + 6, &q, 0) / 10 - 1;
- *p = '\0'; trail_space (text);
- if (text[0] != '\0')
- current->text[current->lines++] = strdup (text);
- if (current->lines > 0) { state = 99; break; }
- state = 0; continue;
- }
- }
- s = strchr (s, '>');
- if (s) { s++; state = 3; continue; }
- break;
- }
-
- /* read next line */
- if (state != 99 && !(s = read_line_from_input (this, line, LINE_LEN)))
- return 0;
-
- } while (state != 99);
-
- return current;
-}
-
-
-static char *sub_readtext(char *source, char **dest) {
- size_t len=0;
- char *p=source;
-
- while ( !eol(*p) && *p!= '|' ) {
- p++,len++;
- }
-
- *dest = strndup(source, len);
-
- while (*p=='\r' || *p=='\n' || *p=='|')
- p++;
-
- if (*p) return p; /* not-last text field */
- else return NULL; /* last text field */
-}
-
-static subtitle_t *sub_read_line_microdvd(demux_sputext_t *this, subtitle_t *current) {
-
- char line[LINE_LEN + 1];
- char line2[LINE_LEN + 1];
-
- memset (current, 0, sizeof(subtitle_t));
-
- current->end=-1;
- do {
- if (!read_line_from_input (this, line, LINE_LEN)) return NULL;
- } while ((sscanf (line, "{%ld}{}%" LINE_LEN_QUOT "[^\r\n]", &(current->start), line2) !=2) &&
- (sscanf (line, "{%ld}{%ld}%" LINE_LEN_QUOT "[^\r\n]", &(current->start), &(current->end),line2) !=3)
- );
-
- char *p=line2;
-
- char *next=p;
- size_t i=0;
- while ((next =sub_readtext (next, &(current->text[i])))) {
- if (current->text[i]==ERR) return ERR;
- i++;
- if (i>=SUB_MAX_TEXT) {
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "Too many lines in a subtitle\n");
- current->lines=i;
- return current;
- }
- }
- current->lines= ++i;
-
- return current;
-}
-
-static subtitle_t *sub_read_line_subviewer(demux_sputext_t *this, subtitle_t *current) {
- char line[LINE_LEN + 1];
-
- memset (current, 0, sizeof(subtitle_t));
-
- while (1) {
- if (!read_line_from_input(this, line, LINE_LEN)) return NULL;
-
- {
- int a1,a2,a3,a4,b1,b2,b3,b4;
- if (sscanf (line, "%d:%d:%d.%d,%d:%d:%d.%d",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4) < 8) {
- if (sscanf (line, "%d:%d:%d,%d,%d:%d:%d,%d",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4) < 8)
- continue;
- }
-
- current->start = a1*360000+a2*6000+a3*100+a4;
- current->end = b1*360000+b2*6000+b3*100+b4;
- }
-
- if (!read_line_from_input(this, line, LINE_LEN))
- return NULL;
-
- char *p = line, *q = line;
- for (current->lines=1; current->lines <= SUB_MAX_TEXT; current->lines++) {
- size_t len;
- for (q=p,len=0; *p && *p!='\r' && *p!='\n' && *p!='|' && strncasecmp(p,"[br]",4); p++,len++);
- current->text[current->lines-1] = strndup(q, len);
- if (!current->text[current->lines-1]) return ERR;
- if (!*p || *p=='\r' || *p=='\n') break;
- if (*p=='[') while (*p++!=']');
- if (*p=='|') p++;
- }
- if (current->lines > SUB_MAX_TEXT) current->lines = SUB_MAX_TEXT;
- break;
- }
- return current;
-}
-
-static subtitle_t *sub_read_line_subrip(demux_sputext_t *this,subtitle_t *current) {
- memset(current,0,sizeof(subtitle_t));
-
- {
- int a1,a2,a3,a4,b1,b2,b3,b4,i;
- do {
- char line[LINE_LEN + 1];
- if(!read_line_from_input(this,line,LINE_LEN))
- return NULL;
- i = sscanf(line,"%d:%d:%d%*[,.]%d --> %d:%d:%d%*[,.]%d",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4);
- } while(i < 8);
- current->start = a1*360000+a2*6000+a3*100+a4/10;
- current->end = b1*360000+b2*6000+b3*100+b4/10;
- }
-
- int i=0;
- int end_sub=0;
- do {
- char *p; /* pointer to the curently read char */
- char line[LINE_LEN + 1];
- char temp_line[SUB_BUFSIZE] = { 0, }; /* subtitle line that will be transfered to current->text[i] */
- size_t temp_index; /* ... and its index wich 'points' to the first EMPTY place -> last read char is at temp_index-1 if temp_index>0 */
- if(!read_line_from_input(this,line,LINE_LEN)) {
- if(i)
- break; /* if something was read, transmit it */
- else
- return NULL; /* if not, repport EOF */
- }
- for(temp_index=0,p=line;*p!='\0' && !end_sub && temp_index<SUB_BUFSIZE && i<SUB_MAX_TEXT;p++) {
- switch(*p) {
- case '\\':
- if(*(p+1)=='N' || *(p+1)=='n') {
- temp_line[temp_index++]='\0'; /* end of curent line */
- p++;
- } else
- temp_line[temp_index++]=*p;
- break;
- case '\r': /* just ignore '\r's */
- break;
- case '\n':
- temp_line[temp_index++]='\0';
- break;
- default:
- temp_line[temp_index++]=*p;
- break;
- }
- if(temp_index>0) {
- if(temp_index==SUB_BUFSIZE)
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "Too many characters in a subtitle line\n");
- if(temp_line[temp_index-1]=='\0' || temp_index==SUB_BUFSIZE) {
- if(temp_index>1) { /* more than 1 char (including '\0') -> that is a valid one */
- /* temp_index<=SUB_BUFSIZE is always true here */
- current->text[i] = strndup(temp_line, temp_index);
- if(!current->text[i])
- return ERR;
- i++;
- temp_index=0;
- } else
- end_sub=1;
- }
- }
- }
- } while(i<SUB_MAX_TEXT && !end_sub);
- if(i>=SUB_MAX_TEXT)
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "Too many lines in a subtitle\n");
- current->lines=i;
- return current;
-}
-
-static subtitle_t *sub_read_line_vplayer(demux_sputext_t *this,subtitle_t *current) {
- char line[LINE_LEN + 1];
-
- memset (current, 0, sizeof(subtitle_t));
-
- while (!current->text[0]) {
- if( this->next_line[0] == '\0' ) { /* if the buffer is empty.... */
- if( !read_line_from_input(this, line, LINE_LEN) ) return NULL;
- } else {
- /* ... get the current line from buffer. */
- strncpy( line, this->next_line, LINE_LEN);
- line[LINE_LEN] = '\0'; /* I'm scared. This makes me feel better. */
- this->next_line[0] = '\0'; /* mark the buffer as empty. */
- }
- /* Initialize buffer with next line */
- if( ! read_line_from_input( this, this->next_line, LINE_LEN) ) {
- this->next_line[0] = '\0';
- return NULL;
- }
-
- {
- int a1,a2,a3,b1,b2,b3;
- if( (sscanf( line, "%d:%d:%d:", &a1, &a2, &a3) < 3) ||
- (sscanf( this->next_line, "%d:%d:%d:", &b1, &b2, &b3) < 3) )
- continue;
- current->start = a1*360000+a2*6000+a3*100;
- current->end = b1*360000+b2*6000+b3*100;
- }
-
- if ((current->end - current->start) > LINE_LEN)
- current->end = current->start + LINE_LEN; /* not too long though. */
- /* teraz czas na wkopiowanie stringu */
- char *p=line;
- /* finds the body of the subtitle_t */
- {
- int i;
- for (i=0; i<3; i++){
- char *p2=strchr( p, ':');
- if( p2 == NULL ) break;
- p=p2+1;
- }
- }
-
- char *next=p;
- int i=0;
- while( (next = sub_readtext( next, &(current->text[i]))) ) {
- if (current->text[i]==ERR)
- return ERR;
- i++;
- if (i>=SUB_MAX_TEXT) {
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "Too many lines in a subtitle\n");
- current->lines=i;
- return current;
- }
- }
- current->lines=++i;
- }
- return current;
-}
-
-static subtitle_t *sub_read_line_rt(demux_sputext_t *this,subtitle_t *current) {
- /*
- * TODO: This format uses quite rich (sub/super)set of xhtml
- * I couldn't check it since DTD is not included.
- * WARNING: full XML parses can be required for proper parsing
- */
- memset (current, 0, sizeof(subtitle_t));
-
- while (!current->text[0]) {
- char line[LINE_LEN + 1];
- if (!read_line_from_input(this, line, LINE_LEN)) return NULL;
-
- char *p = line;
- /*
- * TODO: it seems that format of time is not easily determined, it may be 1:12, 1:12.0 or 0:1:12.0
- * to describe the same moment in time. Maybe there are even more formats in use.
- */
- {
- int a1,a2,a3,a4,b1,b2,b3,b4,len,plen;
- if ((len=sscanf (line, "<Time Begin=\"%d:%d:%d.%d\" End=\"%d:%d:%d.%d\"",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4)) < 8)
-
- a1=a2=a3=a4=b1=b2=b3=b4=0;
- if (
- ((len=sscanf (line, "<%*[tT]ime %*[bB]egin=\"%d:%d\" %*[Ee]nd=\"%d:%d\"%*[^<]<clear/>%n",&a2,&a3,&b2,&b3,&plen)) < 4) &&
- ((len=sscanf (line, "<%*[tT]ime %*[bB]egin=\"%d:%d\" %*[Ee]nd=\"%d:%d.%d\"%*[^<]<clear/>%n",&a2,&a3,&b2,&b3,&b4,&plen)) < 5) &&
- /* ((len=sscanf (line, "<%*[tT]ime %*[bB]egin=\"%d:%d.%d\" %*[Ee]nd=\"%d:%d\"%*[^<]<clear/>%n",&a2,&a3,&a4,&b2,&b3,&plen)) < 5) && */
- ((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) &&
- ((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)
- )
- continue;
-
- current->start = a1*360000+a2*6000+a3*100+a4/10;
- current->end = b1*360000+b2*6000+b3*100+b4/10;
-
- p += plen;
- }
-
- int i=0;
- /* TODO: I don't know what kind of convention is here for marking multiline subs, maybe <br/> like in xml? */
- char *next = strstr(line,"<clear/>")+8;i=0;
- while ((next =sub_readtext (next, &(current->text[i])))) {
- if (current->text[i]==ERR)
- return ERR;
- i++;
- if (i>=SUB_MAX_TEXT) {
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "Too many lines in a subtitle\n");
- current->lines=i;
- return current;
- }
- }
- current->lines=i+1;
- }
- return current;
-}
-
-static subtitle_t *sub_read_line_ssa(demux_sputext_t *this,subtitle_t *current) {
- static int max_comma = 32; /* let's use 32 for the case that the */
- /* amount of commas increase with newer SSA versions */
-
- int hour1, min1, sec1, hunsec1, hour2, min2, sec2, hunsec2, nothing;
- char line3[LINE_LEN + 1];
-
- {
- char line[LINE_LEN + 1];
- do {
- if (!read_line_from_input(this, line, LINE_LEN)) return NULL;
- } while (sscanf (line, "Dialogue: Marked=%d,%d:%d:%d.%d,%d:%d:%d.%d,"
- "%[^\n\r]", &nothing,
- &hour1, &min1, &sec1, &hunsec1,
- &hour2, &min2, &sec2, &hunsec2,
- line3) < 9
- &&
- sscanf (line, "Dialogue: %d,%d:%d:%d.%d,%d:%d:%d.%d,"
- "%[^\n\r]", &nothing,
- &hour1, &min1, &sec1, &hunsec1,
- &hour2, &min2, &sec2, &hunsec2,
- line3) < 9 );
- }
-
- char *line2=strchr(line3, ',');
- if (!line2)
- return NULL;
-
- int comma;
- for (comma = 4; comma < max_comma; comma ++) {
- char *tmp = line2;
- if(!(tmp=strchr(++tmp, ','))) break;
- if(*(++tmp) == ' ') break;
- /* a space after a comma means we're already in a sentence */
- line2 = tmp;
- }
-
- if(comma < max_comma)max_comma = comma;
- /* eliminate the trailing comma */
- if(*line2 == ',') line2++;
-
- current->lines=0;
- current->start = 360000*hour1 + 6000*min1 + 100*sec1 + hunsec1;
- current->end = 360000*hour2 + 6000*min2 + 100*sec2 + hunsec2;
-
- int num=0;
- char *tmp;
- while (((tmp=strstr(line2, "\\n")) != NULL) || ((tmp=strstr(line2, "\\N")) != NULL) ){
- current->text[num] = strndup(line2, tmp-line2);
- line2=tmp+2;
- num++;
- current->lines++;
- if (current->lines >= SUB_MAX_TEXT) return current;
- }
-
- current->text[num]=strdup(line2);
- current->lines++;
-
- return current;
-}
-
-/* Sylvain "Skarsnik" Colinet <scolinet@gmail.com>
- * From MPlayer subreader.c :
- *
- * PJS subtitles reader.
- * That's the "Phoenix Japanimation Society" format.
- * I found some of them in http://www.scriptsclub.org/ (used for anime).
- * The time is in tenths of second.
- *
- * by set, based on code by szabi (dunnowhat sub format ;-)
- */
-
-static subtitle_t *sub_read_line_pjs (demux_sputext_t *this, subtitle_t *current) {
- char line[LINE_LEN + 1];
- char *s;
-
- memset (current, 0, sizeof(subtitle_t));
-
- if (!read_line_from_input(this, line, LINE_LEN))
- return NULL;
- for (s = line; *s && isspace(*s); s++);
- if (*s == 0)
- return NULL;
- if (sscanf (line, "%ld,%ld,", &(current->start),
- &(current->end)) <2)
- return ERR;
- /* the files I have are in tenths of second */
- current->start *= 10;
- current->end *= 10;
-
- /* walk to the beggining of the string */
- for (; *s; s++) if (*s==',') break;
- if (*s) {
- for (s++; *s; s++) if (*s==',') break;
- if (*s) s++;
- }
- if (*s!='"') {
- return ERR;
- }
- /* copy the string to the text buffer */
- char text[LINE_LEN + 1];
- char *d = NULL;
- for (s++, d=text; *s && *s!='"'; s++, d++)
- *d=*s;
- *d=0;
- current->text[0] = strdup(text);
- current->lines = 1;
-
- return current;
-}
-
-static subtitle_t *sub_read_line_mpsub (demux_sputext_t *this, subtitle_t *current) {
- char line[LINE_LEN + 1];
-
- {
- float a,b;
- do {
- if (!read_line_from_input(this, line, LINE_LEN))
- return NULL;
- } while (sscanf (line, "%f %f", &a, &b) !=2);
-
- this->mpsub_position += (a*100.0);
- current->start = (int) this->mpsub_position;
- this->mpsub_position += (b*100.0);
- current->end = (int) this->mpsub_position;
- }
-
- int num = 0;
- while (num < SUB_MAX_TEXT) {
- if (!read_line_from_input(this, line, LINE_LEN))
- return NULL;
-
- char *p=line;
- while (isspace(*p))
- p++;
-
- if (eol(*p) && num > 0)
- return current;
-
- if (eol(*p))
- return NULL;
-
- char *q;
- for (q=p; !eol(*q); q++);
- *q='\0';
- if (*p) {
- current->text[num]=strdup(p);
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, ">%s<\n",p);
- current->lines = ++num;
- } else {
- return num ? current : NULL;
- }
- }
-
- return NULL;
-}
-
-static subtitle_t *sub_read_line_aqt (demux_sputext_t *this, subtitle_t *current) {
- memset (current, 0, sizeof(subtitle_t));
-
- while (1) {
- char line[LINE_LEN + 1];
- /* try to locate next subtitle_t */
- if (!read_line_from_input(this, line, LINE_LEN))
- return NULL;
- if (!(sscanf (line, "-->> %ld", &(current->start)) <1))
- break;
- }
-
- char line[LINE_LEN + 1];
- if (!read_line_from_input(this, line, LINE_LEN))
- return NULL;
-
- sub_readtext((char *) &line,&current->text[0]);
- current->lines = 1;
- current->end = -1;
-
- if (!read_line_from_input(this, line, LINE_LEN))
- return current;;
-
- sub_readtext((char *) &line,&current->text[1]);
- current->lines = 2;
-
- if ((current->text[0][0]==0) && (current->text[1][0]==0)) {
- return NULL;
- }
-
- return current;
-}
-
-static subtitle_t *sub_read_line_jacobsub(demux_sputext_t *this, subtitle_t *current) {
- char line1[LINE_LEN] = { 0, }, line2[LINE_LEN] = { 0, }, directive[LINE_LEN] = { 0, }, *p, *q;
- unsigned a1, a2, a3, a4, b1, b2, b3, b4, comment = 0;
- static unsigned jacoTimeres = 30;
- static int jacoShift = 0;
-
- memset(current, 0, sizeof(subtitle_t));
- while (!current->text[0]) {
- if (!read_line_from_input(this, line1, LINE_LEN)) {
- return NULL;
- }
- if (sscanf
- (line1, "%u:%u:%u.%u %u:%u:%u.%u %" LINE_LEN_QUOT "[^\n\r]", &a1, &a2, &a3, &a4,
- &b1, &b2, &b3, &b4, line2) < 9) {
- if (sscanf(line1, "@%u @%u %" LINE_LEN_QUOT "[^\n\r]", &a4, &b4, line2) < 3) {
- if (line1[0] == '#') {
- int hours = 0, minutes = 0, seconds, delta, inverter =
- 1;
- unsigned units = jacoShift;
- switch (toupper(line1[1])) {
- case 'S':
- if (isalpha(line1[2])) {
- delta = 6;
- } else {
- delta = 2;
- }
- if (sscanf(&line1[delta], "%d", &hours)) {
- if (hours < 0) {
- hours *= -1;
- inverter = -1;
- }
- if (sscanf(&line1[delta], "%*d:%d", &minutes)) {
- if (sscanf
- (&line1[delta], "%*d:%*d:%d",
- &seconds)) {
- sscanf(&line1[delta], "%*d:%*d:%*d.%d",
- &units);
- } else {
- hours = 0;
- sscanf(&line1[delta], "%d:%d.%d",
- &minutes, &seconds, &units);
- minutes *= inverter;
- }
- } else {
- hours = minutes = 0;
- sscanf(&line1[delta], "%d.%d", &seconds,
- &units);
- seconds *= inverter;
- }
- jacoShift =
- ((hours * 3600 + minutes * 60 +
- seconds) * jacoTimeres +
- units) * inverter;
- }
- break;
- case 'T':
- if (isalpha(line1[2])) {
- delta = 8;
- } else {
- delta = 2;
- }
- sscanf(&line1[delta], "%u", &jacoTimeres);
- break;
- }
- }
- continue;
- } else {
- current->start =
- (unsigned long) ((a4 + jacoShift) * 100.0 /
- jacoTimeres);
- current->end =
- (unsigned long) ((b4 + jacoShift) * 100.0 /
- jacoTimeres);
- }
- } else {
- current->start =
- (unsigned
- long) (((a1 * 3600 + a2 * 60 + a3) * jacoTimeres + a4 +
- jacoShift) * 100.0 / jacoTimeres);
- current->end =
- (unsigned
- long) (((b1 * 3600 + b2 * 60 + b3) * jacoTimeres + b4 +
- jacoShift) * 100.0 / jacoTimeres);
- }
- current->lines = 0;
- p = line2;
- while ((*p == ' ') || (*p == '\t')) {
- ++p;
- }
- if (isalpha(*p)||*p == '[') {
- if (sscanf(p, "%s %" LINE_LEN_QUOT "[^\n\r]", directive, line1) < 2)
- return ERR;
- if ((strcasestr(directive, "RDB") != NULL)
- || (strcasestr(directive, "RDC") != NULL)
- || (strcasestr(directive, "RLB") != NULL)
- || (strcasestr(directive, "RLG") != NULL)) {
- continue;
- }
- /* no alignment */
-#if 0
- if (strcasestr(directive, "JL") != NULL) {
- current->alignment = SUB_ALIGNMENT_HLEFT;
- } else if (strcasestr(directive, "JR") != NULL) {
- current->alignment = SUB_ALIGNMENT_HRIGHT;
- } else {
- current->alignment = SUB_ALIGNMENT_HCENTER;
- }
-#endif
- strcpy(line2, line1);
- p = line2;
- }
- for (q = line1; (!eol(*p)) && (current->lines < SUB_MAX_TEXT); ++p) {
- switch (*p) {
- case '{':
- comment++;
- break;
- case '}':
- if (comment) {
- --comment;
- /* the next line to get rid of a blank after the comment */
- if ((*(p + 1)) == ' ')
- p++;
- }
- break;
- case '~':
- if (!comment) {
- *q = ' ';
- ++q;
- }
- break;
- case ' ':
- case '\t':
- if ((*(p + 1) == ' ') || (*(p + 1) == '\t'))
- break;
- if (!comment) {
- *q = ' ';
- ++q;
- }
- break;
- case '\\':
- if (*(p + 1) == 'n') {
- *q = '\0';
- q = line1;
- current->text[current->lines++] = strdup(line1);
- ++p;
- break;
- }
- if ((toupper(*(p + 1)) == 'C')
- || (toupper(*(p + 1)) == 'F')) {
- ++p,++p;
- break;
- }
- if ((*(p + 1) == 'B') || (*(p + 1) == 'b') ||
- /* actually this means "insert current date here" */
- (*(p + 1) == 'D') ||
- (*(p + 1) == 'I') || (*(p + 1) == 'i') ||
- (*(p + 1) == 'N') ||
- /* actually this means "insert current time here" */
- (*(p + 1) == 'T') ||
- (*(p + 1) == 'U') || (*(p + 1) == 'u')) {
- ++p;
- break;
- }
- if ((*(p + 1) == '\\') ||
- (*(p + 1) == '~') || (*(p + 1) == '{')) {
- ++p;
- } else if (eol(*(p + 1))) {
- if (!read_line_from_input(this, directive, LINE_LEN))
- return NULL;
- trail_space(directive);
- strncat(line2, directive,
- ((LINE_LEN > 511) ? LINE_LEN-1 : 511)
- - strlen(line2));
- break;
- }
- default:
- if (!comment) {
- *q = *p;
- ++q;
- }
- }
- }
- *q = '\0';
- if (current->lines < SUB_MAX_TEXT)
- current->text[current->lines] = strdup(line1);
- else
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "Too many lines in a subtitle\n");
- }
- current->lines++;
- return current;
-}
-
-static subtitle_t *sub_read_line_subviewer2(demux_sputext_t *this, subtitle_t *current) {
- char *p=NULL;
-
- while (!current->text[0]) {
- char line[LINE_LEN+1];
- if (!read_line_from_input(this, line, LINE_LEN)) return NULL;
- if (line[0]!='{')
- continue;
-
- {
- int a1,a2,a3,a4;
- const int len = sscanf (line, "{T %d:%d:%d:%d",&a1,&a2,&a3,&a4);
- if (len < 4)
- continue;
- current->start = a1*360000+a2*6000+a3*100+a4/10;
- }
-
- int i;
- for (i=0; i<SUB_MAX_TEXT;) {
- if (!read_line_from_input(this, line, LINE_LEN)) break;
- if (line[0]=='}') break;
- size_t len=0;
- for (p=line; *p!='\n' && *p!='\r' && *p; ++p,++len);
- if (len) {
- current->text[i] = strndup(line, len);
- if (!current->text[i]) return ERR;
- ++i;
- } else {
- break;
- }
- }
- current->lines=i;
- }
- return current;
-}
-
-static subtitle_t *sub_read_line_subrip09 (demux_sputext_t *this, subtitle_t *current) {
- memset (current, 0, sizeof(subtitle_t));
-
- int h, m, s;
- {
- char line[LINE_LEN + 1];
- do {
- if (!read_line_from_input (this, line, LINE_LEN)) return NULL;
- } while (sscanf (line, "[%d:%d:%d]", &h, &m, &s) != 3);
- }
-
- char line[LINE_LEN + 1];
- if (!read_line_from_input (this, line, LINE_LEN)) return NULL;
-
- current->start = 360000 * h + 6000 * m + 100 * s;
- current->end = -1;
-
- char *next = line;
- int i=0;
- while ((next = sub_readtext (next, &(current->text[i])))) {
- if (current->text[i]==ERR) return ERR;
- i++;
- if (i>=SUB_MAX_TEXT) {
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "Too many lines in a subtitle\n");
- current->lines=i;
- return current;
- }
- }
- current->lines= ++i;
-
- return current;
-}
-
-/* Code from subreader.c of MPlayer
-** Sylvain "Skarsnik" Colinet <scolinet@gmail.com>
-*/
-
-static subtitle_t *sub_read_line_mpl2(demux_sputext_t *this, subtitle_t *current) {
- char line2[LINE_LEN+1];
-
- memset (current, 0, sizeof(subtitle_t));
-
- {
- char line[LINE_LEN+1];
- long start, end;
-
- do {
- if (!read_line_from_input (this, line, LINE_LEN)) return NULL;
- } while ((sscanf (line,
- "[%ld][%ld]%[^\r\n]",
- &start, &end, line2) < 3));
-
- current->start = start * 10;
- current->end = end * 10;
- }
-
- char *p = line2, *next = p;
- int i = 0;
-
- while ((next = sub_readtext (next, &(current->text[i])))) {
- if (current->text[i] == ERR) {return ERR;}
- i++;
- if (i >= SUB_MAX_TEXT) {
- xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "Too many lines in a subtitle\n");
- current->lines = i;
- return current;
- }
- }
- current->lines= ++i;
-
- return current;
-}
-
-
-
-static int sub_autodetect (demux_sputext_t *this) {
- int j;
- for(j = 1; j < 100; j++) {
- char line[LINE_LEN + 1];
- if (!read_line_from_input(this, line, LINE_LEN))
- return FORMAT_UNKNOWN;
-
- int i;
- if ((sscanf (line, "{%d}{}", &i)==1) ||
- (sscanf (line, "{%d}{%d}", &i, &i)==2)) {
- this->uses_time=0;
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "microdvd subtitle format detected\n");
- return FORMAT_MICRODVD;
- }
-
- if (sscanf (line, "%d:%d:%d%*[,.]%d --> %d:%d:%d%*[,.]%d", &i, &i, &i, &i, &i, &i, &i, &i)==8) {
- this->uses_time=1;
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "subrip subtitle format detected\n");
- return FORMAT_SUBRIP;
- }
-
- if (sscanf (line, "%d:%d:%d.%d,%d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i)==8){
- this->uses_time=1;
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "subviewer subtitle format detected\n");
- return FORMAT_SUBVIEWER;
- }
-
- if (sscanf (line, "%d:%d:%d,%d,%d:%d:%d,%d", &i, &i, &i, &i, &i, &i, &i, &i)==8){
- this->uses_time=1;
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "subviewer subtitle format detected\n");
- return FORMAT_SUBVIEWER;
- }
-
- if (strstr (line, "<SAMI>")) {
- this->uses_time=1;
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "sami subtitle format detected\n");
- return FORMAT_SAMI;
- }
- if (sscanf (line, "%d:%d:%d:", &i, &i, &i )==3) {
- this->uses_time=1;
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "vplayer subtitle format detected\n");
- return FORMAT_VPLAYER;
- }
- /*
- * A RealText format is a markup language, starts with <window> tag,
- * options (behaviour modifiers) are possible.
- */
- if ( !strcasecmp(line, "<window") ) {
- this->uses_time=1;
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "rt subtitle format detected\n");
- return FORMAT_RT;
- }
- if ((!memcmp(line, "Dialogue: Marked", 16)) || (!memcmp(line, "Dialogue: ", 10))) {
- this->uses_time=1;
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "ssa subtitle format detected\n");
- return FORMAT_SSA;
- }
- if (sscanf (line, "%d,%d,\"%c", &i, &i, (char *) &i) == 3) {
- this->uses_time=0;
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "pjs subtitle format detected\n");
- return FORMAT_PJS;
- }
- if (sscanf (line, "FORMAT=%d", &i) == 1) {
- this->uses_time=0;
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "mpsub subtitle format detected\n");
- return FORMAT_MPSUB;
- }
-
- char p;
- if (sscanf (line, "FORMAT=TIM%c", &p)==1 && p=='E') {
- this->uses_time=1;
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "mpsub subtitle format detected\n");
- return FORMAT_MPSUB;
- }
-
- if (strstr (line, "-->>")) {
- this->uses_time=0;
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "aqtitle subtitle format detected\n");
- return FORMAT_AQTITLE;
- }
- if (sscanf(line, "@%d @%d", &i, &i) == 2 ||
- sscanf(line, "%d:%d:%d.%d %d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i) == 8) {
- this->uses_time = 1;
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "jacobsub subtitle format detected\n");
- return FORMAT_JACOBSUB;
- }
- if (sscanf(line, "{T %d:%d:%d:%d",&i, &i, &i, &i) == 4) {
- this->uses_time = 1;
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "subviewer 2.0 subtitle format detected\n");
- return FORMAT_SUBVIEWER2;
- }
- if (sscanf(line, "[%d:%d:%d]", &i, &i, &i) == 3) {
- this->uses_time = 1;
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "subrip 0.9 subtitle format detected\n");
- return FORMAT_SUBRIP09;
- }
-
- if (sscanf (line, "[%d][%d]", &i, &i) == 2) {
- this->uses_time = 1;
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "mpl2 subtitle format detected\n");
- return FORMAT_MPL2;
- }
- }
- return FORMAT_UNKNOWN; /* too many bad lines */
-}
-
-static subtitle_t *sub_read_file (demux_sputext_t *this) {
-
- subtitle_t * (*func[])(demux_sputext_t *this,subtitle_t *dest)=
- {
- sub_read_line_microdvd,
- sub_read_line_subrip,
- sub_read_line_subviewer,
- sub_read_line_sami,
- sub_read_line_vplayer,
- sub_read_line_rt,
- sub_read_line_ssa,
- sub_read_line_pjs,
- sub_read_line_mpsub,
- sub_read_line_aqt,
- sub_read_line_jacobsub,
- sub_read_line_subviewer2,
- sub_read_line_subrip09,
- sub_read_line_mpl2,
- };
-
- /* Rewind (sub_autodetect() needs to read input from the beginning) */
- if(this->input->seek(this->input, 0, SEEK_SET) == -1) {
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "seek failed.\n");
- return NULL;
- }
- this->buflen = 0;
-
- this->format=sub_autodetect (this);
- if (this->format==FORMAT_UNKNOWN) {
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "Could not determine file format\n");
- return NULL;
- }
-
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "Detected subtitle file format: %d\n",this->format);
-
- /* Rewind */
- if(this->input->seek(this->input, 0, SEEK_SET) == -1) {
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "seek failed.\n");
- return NULL;
- }
- this->buflen = 0;
-
- this->num=0;
- int n_max=32;
- subtitle_t *first = calloc(n_max, sizeof(subtitle_t));
- if(!first) return NULL;
-
- const int timeout =
- (((demux_sputext_class_t *)
- (this->demux_plugin.demux_class))->max_timeout) *
- (this->uses_time ? 100 : 10);
-
- while(1) {
- if(this->num>=n_max){
- n_max+=16;
- first=realloc(first,n_max*sizeof(subtitle_t));
- }
-
- subtitle_t *sub = func[this->format] (this, &first[this->num]);
-
- if (!sub)
- break; /* EOF */
-
- if (sub==ERR)
- ++this->errs;
- else {
- if (this->num > 0 && first[this->num-1].end == -1) {
- /* end time not defined in the subtitle */
- if (timeout > 0) {
- /* timeout */
- if (timeout > sub->start - first[this->num-1].start) {
- first[this->num-1].end = sub->start;
- } else
- first[this->num-1].end = first[this->num-1].start + timeout;
- } else {
- /* no timeout */
- first[this->num-1].end = sub->start;
- }
- }
- ++this->num; /* Error vs. Valid */
- }
- }
- /* timeout of last subtitle */
- if (this->num > 0 && first[this->num-1].end == -1)
- if (timeout > 0) {
- first[this->num-1].end = first[this->num-1].start + timeout;
- }
-
- if(this->stream->xine->verbosity >= XINE_VERBOSITY_DEBUG) {
- char buffer[1024];
-
- sprintf(buffer, "Read %i subtitles", this->num);
-
- if(this->errs)
- sprintf(buffer + strlen(buffer), ", %i bad line(s).\n", this->errs);
- else
- strcat(buffer, "\n");
-
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "%s", buffer);
- }
-
- return first;
-}
-
-static int demux_sputext_next (demux_sputext_t *this_gen) {
- demux_sputext_t *this = (demux_sputext_t *) this_gen;
-
- if (this->cur >= this->num)
- return 0;
-
- subtitle_t *sub = &this->subtitles[this->cur];
-
- buf_element_t *buf = this->stream->video_fifo->buffer_pool_alloc(this->stream->video_fifo);
- buf->type = BUF_SPU_TEXT;
- buf->pts = 0;
-
- uint32_t *val = (uint32_t * )buf->content;
- *val++ = sub->lines;
- *val++ = this->uses_time;
- *val++ = (this->uses_time) ? sub->start * 10 : sub->start;
- *val++ = (this->uses_time) ? sub->end * 10 : sub->end;
- char *str = (char *)val;
-
- /** @FIXME The way this works seems wrong, SUB_BUFSIZE-1 is not the
- right maximum, I think. */
- int line;
- for (line = 0; line < sub->lines; line++, str+=strlen(str)+1) {
- strncpy(str, sub->text[line], SUB_BUFSIZE-1);
- str[SUB_BUFSIZE-1] = '\0';
- }
-
- this->stream->video_fifo->put(this->stream->video_fifo, buf);
- this->cur++;
-
- return 1;
-}
-
-static void demux_sputext_dispose (demux_plugin_t *this_gen) {
- demux_sputext_t *this = (demux_sputext_t *) this_gen;
-
- int i;
- for (i = 0; i < this->num; i++) {
- int l;
- for (l = 0; l < this->subtitles[i].lines; l++)
- free(this->subtitles[i].text[l]);
- }
- free(this->subtitles);
- free(this);
-}
-
-static int demux_sputext_get_status (demux_plugin_t *this_gen) {
- demux_sputext_t *this = (demux_sputext_t *) this_gen;
- return this->status;
-}
-
-static int demux_sputext_get_stream_length (demux_plugin_t *this_gen) {
- demux_sputext_t *this = (demux_sputext_t *) this_gen;
-
- return ( this->uses_time && this->num ) ?
- this->subtitles[this->num-1].end * 10 :
- 0;
-}
-
-static int demux_sputext_send_chunk (demux_plugin_t *this_gen) {
- demux_sputext_t *this = (demux_sputext_t *) this_gen;
-
- if (!demux_sputext_next (this)) {
- this->status = DEMUX_FINISHED;
- }
-
- return this->status;
-}
-
-static int demux_sputext_seek (demux_plugin_t *this_gen,
- off_t start_pos, int start_time, int playing) {
- demux_sputext_t *this = (demux_sputext_t*)this_gen;
-
- lprintf("seek() called\n");
-
- /* simple seeking approach: just go back to start.
- * decoder will discard subtitles until the desired position.
- */
- this->cur = 0;
- this->status = DEMUX_OK;
-
- _x_demux_flush_engine (this->stream);
- _x_demux_control_newpts(this->stream, 0, 0);
-
- return this->status;
-}
-
-static void demux_sputext_send_headers(demux_plugin_t *this_gen) {
- demux_sputext_t *this = (demux_sputext_t*)this_gen;
-
- lprintf("send_headers() called\n");
-
- _x_demux_control_start(this->stream);
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, 0);
- _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, 0);
-
- /* enable the SPU channel */
- buf_element_t *buf = this->stream->video_fifo->buffer_pool_alloc(this->stream->video_fifo);
- buf->type = BUF_CONTROL_SPU_CHANNEL;
- buf->decoder_info[0] = buf->decoder_info[1] = buf->decoder_info[2] = 0;
- this->stream->video_fifo->put(this->stream->video_fifo, buf);
-
- this->status = DEMUX_OK;
-}
-
-static uint32_t demux_sputext_get_capabilities(demux_plugin_t *this_gen) {
- return DEMUX_CAP_NOCAP;
-}
-
-static int demux_sputext_get_optional_data(demux_plugin_t *this_gen,
- void *data, int data_type) {
- int channel = *((int *)data);
-
- switch (data_type) {
- case DEMUX_OPTIONAL_DATA_SPULANG:
- if (channel == -1 || channel == 0) {
- strcpy(data, "sub");
- return DEMUX_OPTIONAL_SUCCESS;
- }
- default:
- return DEMUX_OPTIONAL_UNSUPPORTED;
- }
-}
-
-static demux_plugin_t *open_demux_plugin (demux_class_t *class_gen, xine_stream_t *stream,
- input_plugin_t *input_gen) {
-
- input_plugin_t *input = (input_plugin_t *) input_gen;
- demux_sputext_t *this;
-
- lprintf("open_plugin() called\n");
-
- this = calloc(1, sizeof (demux_sputext_t));
- this->stream = stream;
- this->input = input;
-
- this->demux_plugin.send_headers = demux_sputext_send_headers;
- this->demux_plugin.send_chunk = demux_sputext_send_chunk;
- this->demux_plugin.seek = demux_sputext_seek;
- this->demux_plugin.dispose = demux_sputext_dispose;
- this->demux_plugin.get_status = demux_sputext_get_status;
- this->demux_plugin.get_stream_length = demux_sputext_get_stream_length;
- this->demux_plugin.get_capabilities = demux_sputext_get_capabilities;
- this->demux_plugin.get_optional_data = demux_sputext_get_optional_data;
- this->demux_plugin.demux_class = class_gen;
-
- this->buflen = 0;
-
- switch (stream->content_detection_method) {
- case METHOD_BY_EXTENSION:
- {
- const char *const mrl = input->get_mrl(input);
- const char *const ending = strrchr(mrl, '.');
-
- if (!ending || (
- (strncasecmp(ending, ".asc", 4) != 0) &&
- (strncasecmp(ending, ".txt", 4) != 0) &&
- (strncasecmp(ending, ".sub", 4) != 0) &&
- (strncasecmp(ending, ".srt", 4) != 0) &&
- (strncasecmp(ending, ".smi", 4) != 0) &&
- (strncasecmp(ending, ".ssa", 4) != 0) &&
- (strncasecmp(ending, ".ass", 4) != 0))) {
- free (this);
- return NULL;
- }
- }
- /* falling through is intended */
-
- case METHOD_EXPLICIT:
- /* case METHOD_BY_CONTENT: */
-
- /* FIXME: for now this demuxer only works when requested explicitly
- * to make sure it does not interfere with others;
- * If this is found too inconvenient, this may be changed after making
- * sure the content detection does not produce any false positives.
- */
-
- if ((input->get_capabilities(input) & INPUT_CAP_SEEKABLE) != 0) {
-
- this->subtitles = sub_read_file (this);
-
- this->cur = 0;
-
- if (this->subtitles) {
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "subtitle format %s time.\n",
- this->uses_time ? "uses" : "doesn't use");
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
- "read %i subtitles, %i errors.\n", this->num, this->errs);
- return &this->demux_plugin;
- }
- }
- /* falling through is intended */
- }
-
- free (this);
- return NULL;
-}
-
-static const char *get_demux_description (demux_class_t *this_gen) {
- return "sputext demuxer plugin";
-}
-
-static const char *get_demux_identifier (demux_class_t *this_gen) {
- return "sputext";
-}
-
-static const char *get_demux_extensions (demux_class_t *this_gen) {
- return "asc txt sub srt smi ssa ass";
-}
-
-static const char *get_demux_mimetypes (demux_class_t *this_gen) {
- return NULL;
-
- /* do not report this mimetype, it might confuse browsers. */
- /* "text/plain: asc txt sub srt: VIDEO subtitles;" */
-}
-
-static void demux_class_dispose (demux_class_t *this_gen) {
- demux_sputext_class_t *this = (demux_sputext_class_t *) this_gen;
-
- free (this);
-}
-
-static void config_timeout_cb(void *this_gen, xine_cfg_entry_t *entry) {
- demux_sputext_class_t *this = (demux_sputext_class_t *)this_gen;
-
- this->max_timeout = entry->num_value;
-}
-
-static void *init_sputext_demux_class (xine_t *xine, void *data) {
-
- demux_sputext_class_t *this ;
-
- lprintf("initializing\n");
-
- this = calloc(1, sizeof (demux_sputext_class_t));
-
- this->demux_class.open_plugin = open_demux_plugin;
- this->demux_class.get_description = get_demux_description;
- this->demux_class.get_identifier = get_demux_identifier;
- this->demux_class.get_mimetypes = get_demux_mimetypes;
- this->demux_class.get_extensions = get_demux_extensions;
- this->demux_class.dispose = demux_class_dispose;
-
- /*
- * Some subtitling formats, namely AQT and Subrip09, define the end of a
- * subtitle as the beginning of the following. From end-user view it's
- * better define timeout of hidding. Setting to zero means "no timeout".
- */
- this->max_timeout = xine->config->register_num(xine->config,
- "subtitles.separate.timeout", 4,
- _("default duration of subtitle display in seconds"),
- _("Some subtitle formats do not explicitly give a duration for each subtitle. "
- "For these, you can set a default duration here. Setting to zero will result "
- "in the subtitle being shown until the next one takes over."),
- 20, config_timeout_cb, this);
-
- return this;
-}
-
-const plugin_info_t xine_plugin_info[] EXPORTED = {
- /* type, API, "name", version, special_info, init_function */
- { PLUGIN_DEMUX, 26, "sputext", XINE_VERSION_CODE, NULL, &init_sputext_demux_class },
- { PLUGIN_NONE, 0, "", 0, NULL, NULL }
-};
diff --git a/src/libsputext/xine_sputext_decoder.c b/src/libsputext/xine_sputext_decoder.c
deleted file mode 100644
index e2e37bc37..000000000
--- a/src/libsputext/xine_sputext_decoder.c
+++ /dev/null
@@ -1,1215 +0,0 @@
-/*
- * Copyright (C) 2000-2004 the xine project
- *
- * This file is part of xine, a free video player.
- *
- * xine 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.
- *
- * xine 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, USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <ctype.h>
-
-#define LOG_MODULE "libsputext"
-#define LOG_VERBOSE
-/*
-#define LOG
-*/
-
-#include "buffer.h"
-#include "xine_internal.h"
-#include "xineutils.h"
-#include "osd.h"
-
-#define SUB_MAX_TEXT 5 /* lines */
-#define SUB_BUFSIZE 256 /* chars per line */
-
-/* alignment in SSA codes */
-#define ALIGN_LEFT 1
-#define ALIGN_CENTER 2
-#define ALIGN_RIGHT 3
-#define ALIGN_BOTTOM 0
-#define ALIGN_TOP 4
-#define ALIGN_MIDDLE 8
-#define GET_X_ALIGNMENT(a) ((a) & 3)
-#define GET_Y_ALIGNMENT(a) ((a) - ((a) & 3))
-
-/* subtitles projection */
-/* for subrip file with SSA tags, those values are always correct.*/
-/* But for SSA files, those values are the default ones. we have */
-/* to use PlayResX and PlayResY defined in [Script Info] section. */
-/* not implemented yet... */
-#define SPU_PROJECTION_X 384
-#define SPU_PROJECTION_Y 288
-
-
-
-#define rgb2yuv(R,G,B) ((((((66*R+129*G+25*B+128)>>8)+16)<<8)|(((112*R-94*G-18*B+128)>>8)+128))<<8|(((-38*R-74*G+112*B+128)>>8)+128))
-
-static const uint32_t sub_palette[22]={
-/* RED */
- rgb2yuv(0,0,0),
- rgb2yuv(0,0,0),
- rgb2yuv(0,0,0),
- rgb2yuv(0,0,0),
- rgb2yuv(0,0,0),
- rgb2yuv(0,0,0),
- rgb2yuv(0,0,0),
- rgb2yuv(50,10,10),
- rgb2yuv(120,20,20),
- rgb2yuv(185,50,50),
- rgb2yuv(255,70,70),
-/* BLUE */
- rgb2yuv(0,0,0),
- rgb2yuv(0,0,0),
- rgb2yuv(0,0,0),
- rgb2yuv(0,0,0),
- rgb2yuv(0,0,0),
- rgb2yuv(0,0,0),
- rgb2yuv(0,0,0),
- rgb2yuv(0,30,50),
- rgb2yuv(0,90,120),
- rgb2yuv(0,140,185),
- rgb2yuv(0,170,255)
-};
-
-static const uint8_t sub_trans[22]={
- 0, 0, 3, 6, 8, 10, 12, 14, 15, 15, 15,
- 0, 0, 3, 6, 8, 10, 12, 14, 15, 15, 15
-};
-
-typedef enum {
- SUBTITLE_SIZE_TINY = 0,
- SUBTITLE_SIZE_SMALL,
- SUBTITLE_SIZE_NORMAL,
- SUBTITLE_SIZE_LARGE,
- SUBTITLE_SIZE_VERY_LARGE,
- SUBTITLE_SIZE_HUGE,
-
- SUBTITLE_SIZE_NUM /* number of values in enum */
-} subtitle_size;
-
-#define FONTNAME_SIZE 100
-
-typedef struct sputext_class_s {
- spu_decoder_class_t class;
-
- subtitle_size subtitle_size; /* size of subtitles */
- int vertical_offset;
- char font[FONTNAME_SIZE]; /* subtitle font */
-#ifdef HAVE_FT2
- char font_ft[FILENAME_MAX]; /* subtitle font */
- int use_font_ft; /* use Freetype */
-#endif
- const char *src_encoding; /* encoding of subtitle file */
- int use_unscaled; /* use unscaled OSD if possible */
-
- xine_t *xine;
-
-} sputext_class_t;
-
-
-/* Convert subtiles coordinates in window coordinates. */
-/* (a, b) --> (x + a * dx, y + b * dy) */
-typedef struct video2wnd_s {
- int x;
- int y;
- double dx;
- double dy;
-} video2wnd_t;
-
-typedef struct sputext_decoder_s {
- spu_decoder_t spu_decoder;
-
- sputext_class_t *class;
- xine_stream_t *stream;
-
- int ogm;
- int lines;
- char text[SUB_MAX_TEXT][SUB_BUFSIZE];
-
- /* below 3 variables are the same from class. use to detect
- * when something changes.
- */
- subtitle_size subtitle_size; /* size of subtitles */
- int vertical_offset;
- char font[FILENAME_MAX]; /* subtitle font */
- char *buf_encoding; /* encoding of subtitle buffer */
-
- int width; /* frame width */
- int height; /* frame height */
- int font_size;
- int line_height;
- int started;
- int finished;
-
- osd_renderer_t *renderer;
- osd_object_t *osd;
- int current_osd_text;
- uint32_t spu_palette[OVL_PALETTE_SIZE];
- uint8_t spu_trans[OVL_PALETTE_SIZE];
-
- int64_t img_duration;
- int64_t last_subtitle_end; /* no new subtitle before this vpts */
- int unscaled; /* use unscaled OSD */
-
- int last_y; /* location of the previous subtitle */
- int last_lines; /* number of lines of the previous subtitle */
- video2wnd_t video2wnd;
-} sputext_decoder_t;
-
-static inline char *get_font (sputext_class_t *class)
-{
-#ifdef HAVE_FT2
- return class->use_font_ft ? class->font_ft : class->font;
-#else
- return class->font;
-#endif
-}
-
-static void update_font_size (sputext_decoder_t *this, int force_update) {
- static const int sizes[SUBTITLE_SIZE_NUM] = { 16, 20, 24, 32, 48, 64 };
-
- if ((this->subtitle_size != this->class->subtitle_size) ||
- (this->vertical_offset != this->class->vertical_offset) ||
- force_update) {
-
- this->subtitle_size = this->class->subtitle_size;
- this->vertical_offset = this->class->vertical_offset;
- this->last_lines = 0;
-
- this->font_size = sizes[this->class->subtitle_size];
-
- this->line_height = this->font_size + 10;
-
- /* Create a full-window OSD */
- if( this->osd )
- this->renderer->free_object (this->osd);
-
- this->osd = this->renderer->new_object (this->renderer,
- this->width,
- this->height);
-
- this->renderer->set_font (this->osd, get_font (this->class), this->font_size);
-
- this->renderer->set_position (this->osd, 0, 0);
- }
-}
-
-static void update_output_size (sputext_decoder_t *this) {
- const int unscaled = this->class->use_unscaled &&
- (this->stream->video_out->get_capabilities(this->stream->video_out) &
- VO_CAP_UNSCALED_OVERLAY);
-
- if( unscaled != this->unscaled ) {
- this->unscaled = unscaled;
- this->width = 0; /* force update */
- }
-
- /* initialize decoder if needed */
- if( this->unscaled ) {
- if( this->width != this->stream->video_out->get_property(this->stream->video_out,
- VO_PROP_WINDOW_WIDTH) ||
- this->height != this->stream->video_out->get_property(this->stream->video_out,
- VO_PROP_WINDOW_HEIGHT) ||
- !this->img_duration || !this->osd ) {
-
- int width = 0, height = 0;
-
- this->stream->video_out->status(this->stream->video_out, NULL,
- &width, &height, &this->img_duration );
- if( width && height ) {
-
- this->width = this->stream->video_out->get_property(this->stream->video_out,
- VO_PROP_WINDOW_WIDTH);
- this->height = this->stream->video_out->get_property(this->stream->video_out,
- VO_PROP_WINDOW_HEIGHT);
-
- if(!this->osd || (this->width && this->height)) {
-
- /* in unscaled mode, we have to convert subtitle position in window coordinates. */
- /* we have a scale factor because video may be zommed */
- /* and a displacement factor because video may have blacks lines. */
- int output_width, output_height, output_xoffset, output_yoffset;
-
- output_width = this->stream->video_out->get_property(this->stream->video_out,
- VO_PROP_OUTPUT_WIDTH);
- output_height = this->stream->video_out->get_property(this->stream->video_out,
- VO_PROP_OUTPUT_HEIGHT);
- output_xoffset = this->stream->video_out->get_property(this->stream->video_out,
- VO_PROP_OUTPUT_XOFFSET);
- output_yoffset = this->stream->video_out->get_property(this->stream->video_out,
- VO_PROP_OUTPUT_YOFFSET);
-
- /* driver don't seen to be capable to give us those values */
- /* fallback to a default full-window values */
- if (output_width <= 0 || output_height <= 0) {
- output_width = this->width;
- output_height = this->height;
- output_xoffset = 0;
- output_yoffset = 0;
- }
-
- this->video2wnd.x = output_xoffset;
- this->video2wnd.y = output_yoffset;
- this->video2wnd.dx = (double)output_width / SPU_PROJECTION_X;
- this->video2wnd.dy = (double)output_height / SPU_PROJECTION_Y;
-
- this->renderer = this->stream->osd_renderer;
- update_font_size (this, 1);
- }
- }
- }
- } else {
- if( !this->width || !this->height || !this->img_duration || !this->osd ) {
-
- this->width = 0;
- this->height = 0;
-
- this->stream->video_out->status(this->stream->video_out, NULL,
- &this->width, &this->height, &this->img_duration );
-
- if(!this->osd || ( this->width && this->height)) {
- this->renderer = this->stream->osd_renderer;
-
- /* in scaled mode, we have to convert subtitle position in film coordinates. */
- this->video2wnd.x = 0;
- this->video2wnd.y = 0;
- this->video2wnd.dx = (double)this->width / SPU_PROJECTION_X;
- this->video2wnd.dy = (double)this->height / SPU_PROJECTION_Y;
-
- update_font_size (this, 1);
- }
- }
- }
-}
-
-static int parse_utf8_size(const uint8_t *c)
-{
- if ( c[0]<0x80 )
- return 1;
-
- if( c[1]==0 )
- return 1;
- if ( (c[0]>=0xC2 && c[0]<=0xDF) && (c[1]>=0x80 && c[1]<=0xBF) )
- return 2;
-
- if( c[2]==0 )
- return 2;
- else if ( c[0]==0xE0 && (c[1]>=0xA0 && c[1]<=0xBF) && (c[2]>=0x80 && c[1]<=0xBF) )
- return 3;
- else if ( (c[0]>=0xE1 && c[0]<=0xEC) && (c[1]>=0x80 && c[1]<=0xBF) && (c[2]>=0x80 && c[1]<=0xBF) )
- return 3;
- else if ( c[0]==0xED && (c[1]>=0x80 && c[1]<=0x9F) && (c[2]>=0x80 && c[1]<=0xBF) )
- return 3;
- else if ( c[0]==0xEF && (c[1]>=0xA4 && c[1]<=0xBF) && (c[2]>=0x80 && c[1]<=0xBF) )
- return 3;
- else
- return 1;
-}
-
-static int ogm_render_line_internal(sputext_decoder_t *this, int x, int y, const char *text, int render)
-{
- const size_t length = strlen (text);
- size_t i = 0;
-
- while (i <= length) {
-
- if (text[i] == '<') {
- if (!strncmp("<b>", text+i, 3)) {
- /* enable Bold color */
- if (render)
- this->current_osd_text = OSD_TEXT2;
- i=i+3;
- continue;
- } else if (!strncmp("</b>", text+i, 4)) {
- /* disable BOLD */
- if (render)
- this->current_osd_text = OSD_TEXT1;
- i=i+4;
- continue;
- } else if (!strncmp("<i>", text+i, 3)) {
- /* enable italics color */
- if (render)
- this->current_osd_text = OSD_TEXT3;
- i=i+3;
- continue;
- } else if (!strncmp("</i>", text+i, 4)) {
- /* disable italics */
- if (render)
- this->current_osd_text = OSD_TEXT1;
- i=i+4;
- continue;
- } else if (!strncmp("<font>", text+i, 6)) {
- /*Do somethink to disable typing
- fixme - no teststreams*/
- i=i+6;
- continue;
- } else if (!strncmp("</font>", text+i, 7)) {
- /*Do somethink to enable typing
- fixme - no teststreams*/
- i=i+7;
- continue;
- }
- }
- if (text[i] == '{') {
-
- if (!strncmp("{\\", text+i, 2)) {
- int value;
-
- if (sscanf(text+i, "{\\b%d}", &value) == 1) {
- if (render) {
- if (value)
- this->current_osd_text = OSD_TEXT2;
- else
- this->current_osd_text = OSD_TEXT1;
- }
- } else if (sscanf(text+i, "{\\i%d}", &value) == 1) {
- if (render) {
- if (value)
- this->current_osd_text = OSD_TEXT3;
- else
- this->current_osd_text = OSD_TEXT1;
- }
- }
- char *const end = strstr(text+i+2, "}");
- if (end) {
- i=end-text+1;
- continue;
- }
- }
- }
-
- char letter[5];
- const char *const encoding = this->buf_encoding ? : this->class->src_encoding;
- const int isutf8 = !strcmp(encoding, "utf-8");
- const size_t shift = isutf8 ? parse_utf8_size (&text[i]) : 1;
- memcpy(letter,&text[i],shift);
- letter[shift]=0;
-
- if (render)
- this->renderer->render_text(this->osd, x, y, letter, this->current_osd_text);
-
- int w, dummy;
- this->renderer->get_text_size(this->osd, letter, &w, &dummy);
- x += w;
- i += shift;
- }
-
- return x;
-}
-
-static inline int ogm_get_width(sputext_decoder_t *this, char* text) {
- return ogm_render_line_internal (this, 0, 0, text, 0);
-}
-
-static inline void ogm_render_line(sputext_decoder_t *this, int x, int y, char* text) {
- ogm_render_line_internal (this, x, y, text, 1);
-}
-
-/* read SSA tags at begening of text. Suported tags are : */
-/* \a : alignment in SSA code (see #defines) */
-/* \an : alignment in 'numpad code' */
-/* \pos : absolute position of subtitles. Alignment define origin. */
-static void read_ssa_tag(sputext_decoder_t *this, const char* text,
- int* alignment, int* sub_x, int* sub_y, int* max_width) {
-
- int in_tag = 0;
-
- (*alignment) = 2;
- (*sub_x) = -1;
- (*sub_y) = -1;
-
- while (*text) {
-
- /* wait for tag begin, allow space and tab */
- if (in_tag == 0) {
- if (*text == '{') in_tag = 1;
- else if ((*text != ' ') && (*text != '\t')) break;
-
- /* parse SSA command */
- } else {
- if (*text == '\\') {
- if (sscanf(text, "\\pos(%d,%d)", sub_x, sub_y) == 2) {
- text += 8; /* just for speed up, 8 is the minimal with */
- }
-
- if (sscanf(text, "\\a%d", alignment) == 1) {
- text += 2;
- }
-
- if (sscanf(text, "\\an%d", alignment) == 1) {
- text += 3;
- if ((*alignment) > 6) (*alignment) = (*alignment) - 2;
- else if ((*alignment) > 3) (*alignment) = (*alignment) + 5;
- }
- }
-
- if (*text == '}') in_tag = 0;
- }
-
- text++;
- }
-
-
- /* check alignment validity */
- if ((*alignment) < 1 || (*alignment) > 11) {
- (*alignment) = 2;
- }
-
- /* convert to window coordinates */
- if ((*sub_x) >= 0 && (*sub_y) >= 0) {
- (*sub_x) = this->video2wnd.x + this->video2wnd.dx * (*sub_x);
- (*sub_y) = this->video2wnd.y + this->video2wnd.dy * (*sub_y);
- }
-
- /* check validity, compute max width */
- if ( (*sub_x) < 0 || (*sub_x) >= this->width ||
- (*sub_y) < 0 || (*sub_y) >= this->height ) {
- (*sub_x) = -1;
- (*sub_y) = -1;
- (*max_width) = this->width;
- } else {
- switch (GET_X_ALIGNMENT(*alignment)) {
- case ALIGN_LEFT:
- (*max_width) = this->width - (*sub_x);
- break;
- case ALIGN_CENTER:
- (*max_width) = this->width;
- break;
- case ALIGN_RIGHT:
- (*max_width) = (*sub_x);
- break;
- }
- }
-
- xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
- "libsputext: position : (%d, %d), max width : %d, alignment : %d\n",
- (*sub_x), (*sub_y), (*max_width), (*alignment));
-}
-
-static int is_cjk_encoding(const char *enc) {
- /* CJK charset strings defined in iconvdata/gconv-modules of glibc */
- static const char cjk_encoding_strings[][16] = {
- "SJIS",
- "CP932",
- "EUC-KR",
- "UHC",
- "JOHAB",
- "BIG5",
- "BIG5HKSCS",
- "EUC-JP-MS",
- "EUC-JP",
- "EUC-CN",
- "GBBIG5",
- "GBK",
- "GBGBK",
- "EUC-TW",
- "ISO-2022-JP",
- "ISO-2022-JP-2",
- "ISO-2022-JP-3",
- "ISO-2022-KR",
- "ISO-2022-CN",
- "ISO-2022-CN-EXT",
- "GB18030",
- "EUC-JISX0213",
- "SHIFT_JISX0213",
- };
-
- int pstr;
-
- /* return 1 if encoding string is one of the CJK(Chinese,Jananese,Korean)
- * character set strings. */
- for (pstr = 0; pstr < sizeof (cjk_encoding_strings) / sizeof (cjk_encoding_strings[0]); pstr++)
- if (strcasecmp (enc, cjk_encoding_strings[pstr]) == 0)
- return 1;
-
- return 0;
-}
-
-static void draw_subtitle(sputext_decoder_t *this, int64_t sub_start, int64_t sub_end ) {
-
- int y;
- int sub_x, sub_y, max_width = this->width;
- int alignment;
-
- _x_assert(this->renderer != NULL);
- if ( ! this->renderer )
- return;
-
- read_ssa_tag(this, this->text[0], &alignment, &sub_x, &sub_y, &max_width);
-
- update_font_size(this, 0);
-
- const char *const font = get_font (this->class);
- if( strcmp(this->font, font) ) {
- strncpy(this->font, font, FILENAME_MAX);
- this->font[FILENAME_MAX - 1] = '\0';
- this->renderer->set_font (this->osd, font, this->font_size);
- }
-
- int font_size = this->font_size;
-
- const char *const encoding = this->buf_encoding ? : this->class->src_encoding;
- this->renderer->set_encoding(this->osd, encoding);
-
- int rebuild_all = 0;
- int line;
- for (line = 0; line < this->lines; line++) {
- int line_width = ogm_get_width(this, this->text[line]);
-
- /* line too long */
- if (line_width > max_width) {
- char *current_cut, *best_cut;
- int a;
-
- xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
- "libsputext: Line too long: %d > %d, split at max size.\n",
- line_width, max_width);
-
- /* can't fit with keeping existing lines */
- if (this->lines + 1 > SUB_MAX_TEXT) {
- xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
- "libsputext: Can't fit with keeping existing line, we have to rebuild all the subtitle\n");
- rebuild_all = 1;
- break;
- }
-
- /* find the longest sequence witch fit */
- line_width = 0;
- current_cut = this->text[line];
- best_cut = NULL;
- while (line_width < max_width) {
- while (*current_cut && *current_cut != ' ') current_cut++;
- if (*current_cut == ' ') {
- *current_cut = 0;
- line_width = ogm_get_width(this, this->text[line]);
- *current_cut = ' ';
- if (line_width < max_width) best_cut = current_cut;
- current_cut++;
- } else {
- break; /* end of line */
- }
- }
-
- if (best_cut == NULL) {
- xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
- "libsputext: Can't wrap line: a word is too long, abort.\n");
- break;
- }
-
- /* move other lines */
- for (a = this->lines - 1; a > line; a--)
- memcpy(this->text[a + 1], this->text[a], SUB_BUFSIZE);
-
- /* split current one */
- strncpy(this->text[line + 1], best_cut + 1, SUB_BUFSIZE);
- *best_cut = 0;
-
- this->lines = this->lines + 1;
- }
- }
-
- /* regenerate all the lines to find something that better fits */
- if (rebuild_all) {
- char buf[SUB_BUFSIZE * SUB_MAX_TEXT] = { 0, };
-
- int line;
- for(line = 0; line < this->lines; line++) {
- const size_t len = strlen(buf);
- if (len)
- buf[len] = ' ';
-
- strncat(buf, this->text[line], SUB_BUFSIZE-len-1);
- }
-
- char *stream = buf;
- this->lines = 0;
-
- char *current_cut, *best_cut;
- do {
-
- if (this->lines + 1 < SUB_MAX_TEXT) {
-
- /* find the longest sequence witch fit */
- int line_width = 0;
- current_cut = stream;
- best_cut = NULL;
- while (line_width < max_width) {
- while (*current_cut && *current_cut != ' ') current_cut++;
- if (*current_cut == ' ') {
- *current_cut = 0;
- line_width = ogm_get_width(this, stream);
- *current_cut = ' ';
- if (line_width < max_width) best_cut = current_cut;
- current_cut++;
- } else {
- line_width = ogm_get_width(this, stream);
- if (line_width < max_width) best_cut = current_cut;
- break; /* end of line */
- }
- }
- }
-
- /* line maybe too long, but we have reached last subtitle line */
- else {
- best_cut = current_cut = stream + strlen(stream);
- }
-
- /* copy current line */
- if (best_cut != NULL) *best_cut = 0;
- strncpy(this->text[this->lines], stream, SUB_BUFSIZE);
- this->lines = this->lines + 1;
-
- stream = best_cut + 1;
-
- } while (best_cut != current_cut);
-
- }
-
-
- /* Erase subtitle : use last_y and last_lines saved last turn. */
- if (this->last_lines) {
- this->renderer->filled_rect (this->osd, 0, this->last_y,
- this->width - 1, this->last_y + this->last_lines * this->line_height,
- 0);
- }
-
- switch (GET_Y_ALIGNMENT(alignment)) {
- case ALIGN_TOP:
- if (sub_y >= 0) y = sub_y;
- else y = 5;
- break;
-
- case ALIGN_MIDDLE:
- if (sub_y >= 0) y = sub_y - (this->lines * this->line_height) / 2;
- else y = (this->height - this->lines * this->line_height) / 2;
- break;
-
- case ALIGN_BOTTOM:
- default:
- if (sub_y >= 0) y = sub_y - this->lines * this->line_height;
- else y = this->height - this->lines * this->line_height - this->class->vertical_offset;
- break;
- }
- if (y < 0 || y >= this->height)
- y = this->height - this->line_height * this->lines;
-
- this->last_lines = this->lines;
- this->last_y = y;
-
-
- for (line = 0; line < this->lines; line++) {
- int w, x;
-
- while(1) {
- w = ogm_get_width( this, this->text[line]);
-
- switch (GET_X_ALIGNMENT(alignment)) {
- case ALIGN_LEFT:
- if (sub_x >= 0) x = sub_x;
- else x = 5;
- break;
-
- case ALIGN_RIGHT:
- if (sub_x >= 0) x = sub_x - w;
- else x = max_width - w - 5;
- break;
-
- case ALIGN_CENTER:
- default:
- if (sub_x >= 0) x = sub_x - w / 2;
- else x = (max_width - w) / 2;
- break;
- }
-
-
- if( w > max_width && font_size > 16 ) {
- font_size -= 4;
- this->renderer->set_font (this->osd, get_font (this->class), font_size);
- } else {
- break;
- }
- }
-
- if( is_cjk_encoding(encoding) ) {
- this->renderer->render_text (this->osd, x, y + line * this->line_height,
- this->text[line], OSD_TEXT1);
- } else {
- ogm_render_line(this, x, y + line*this->line_height, this->text[line]);
- }
- }
-
- if( font_size != this->font_size )
- this->renderer->set_font (this->osd, get_font (this->class), this->font_size);
-
- if( this->last_subtitle_end && sub_start < this->last_subtitle_end ) {
- sub_start = this->last_subtitle_end;
- }
- this->last_subtitle_end = sub_end;
-
- this->renderer->set_text_palette (this->osd, -1, OSD_TEXT1);
- this->renderer->get_palette(this->osd, this->spu_palette, this->spu_trans);
- /* append some colors for colored typeface tag */
- memcpy(this->spu_palette+OSD_TEXT2, sub_palette, sizeof(sub_palette));
- memcpy(this->spu_trans+OSD_TEXT2, sub_trans, sizeof(sub_trans));
- this->renderer->set_palette(this->osd, this->spu_palette, this->spu_trans);
-
- if (this->unscaled)
- this->renderer->show_unscaled (this->osd, sub_start);
- else
- this->renderer->show (this->osd, sub_start);
-
- this->renderer->hide (this->osd, sub_end);
-
- lprintf ("scheduling subtitle >%s< at %"PRId64" until %"PRId64", current time is %"PRId64"\n",
- this->text[0], sub_start, sub_end,
- this->stream->xine->clock->get_current_time (this->stream->xine->clock));
-}
-
-
-static void spudec_decode_data (spu_decoder_t *this_gen, buf_element_t *buf) {
-
- sputext_decoder_t *this = (sputext_decoder_t *) this_gen;
- int uses_time;
- int32_t start, end, diff;
- int64_t start_vpts, end_vpts;
- int64_t spu_offset;
- int i;
- uint32_t *val;
- char *str;
- extra_info_t extra_info;
- int master_status, slave_status;
- int vo_discard;
-
- /* filter unwanted streams */
- if (buf->decoder_flags & BUF_FLAG_HEADER) {
- return;
- }
- if (buf->decoder_flags & BUF_FLAG_PREVIEW)
- return;
-
- if ((this->stream->spu_channel & 0x1f) != (buf->type & 0x1f))
- return;
-
- if ( (buf->decoder_flags & BUF_FLAG_SPECIAL) &&
- (buf->decoder_info[1] == BUF_SPECIAL_CHARSET_ENCODING) )
- this->buf_encoding = buf->decoder_info_ptr[2];
- else
- this->buf_encoding = NULL;
-
- this->current_osd_text = OSD_TEXT1;
-
- if( (buf->type & 0xFFFF0000) == BUF_SPU_OGM ) {
-
- this->ogm = 1;
- uses_time = 1;
- val = (uint32_t * )buf->content;
- start = *val++;
- end = *val++;
- str = (char *)val;
-
- if (!*str) return;
- /* Empty ogm packets (as created by ogmmux) clears out old messages. We already respect the end time. */
-
- this->lines = 0;
-
- i = 0;
- while (*str && (this->lines < SUB_MAX_TEXT) && (i < SUB_BUFSIZE)) {
- if (*str == '\r' || *str == '\n') {
- if (i) {
- this->text[ this->lines ][i] = 0;
- this->lines++;
- i = 0;
- }
- } else {
- this->text[ this->lines ][i] = *str;
- if (i < SUB_BUFSIZE-1)
- i++;
- }
- str++;
- }
- if (i == SUB_BUFSIZE)
- i--;
-
- if (i) {
- this->text[ this->lines ][i] = 0;
- this->lines++;
- }
-
- } else {
-
- this->ogm = 0;
- val = (uint32_t * )buf->content;
-
- this->lines = *val++;
- uses_time = *val++;
- start = *val++;
- end = *val++;
- str = (char *)val;
- for (i = 0; i < this->lines; i++, str += strlen(str) + 1) {
- strncpy( this->text[i], str, SUB_BUFSIZE - 1);
- this->text[i][SUB_BUFSIZE - 1] = '\0';
- }
-
- }
-
- xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
- "libsputext: decoder data [%s]\n", this->text[0]);
- xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
- "libsputext: mode %d timing %d->%d\n", uses_time, start, end);
-
- if( end <= start ) {
- xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
- "libsputext: discarding subtitle with invalid timing\n");
- return;
- }
-
- spu_offset = this->stream->master->metronom->get_option (this->stream->master->metronom,
- METRONOM_SPU_OFFSET);
- if( uses_time ) {
- start += (spu_offset / 90);
- end += (spu_offset / 90);
- } else {
- if( this->osd && this->img_duration ) {
- start += spu_offset / this->img_duration;
- end += spu_offset / this->img_duration;
- }
- }
-
- while( !this->finished ) {
-
- master_status = xine_get_status (this->stream->master);
- slave_status = xine_get_status (this->stream);
- vo_discard = this->stream->video_out->get_property(this->stream->video_out,
- VO_PROP_DISCARD_FRAMES);
-
- _x_get_current_info (this->stream->master, &extra_info, sizeof(extra_info) );
-
- lprintf("master: %d slave: %d input_normpos: %d vo_discard: %d\n",
- master_status, slave_status, extra_info.input_normpos, vo_discard);
-
- if( !this->started && (master_status == XINE_STATUS_PLAY &&
- slave_status == XINE_STATUS_PLAY &&
- extra_info.input_normpos) ) {
- lprintf("started\n");
-
- this->width = this->height = 0;
-
- update_output_size( this );
- if( this->width && this->height ) {
- this->started = 1;
- }
- }
-
- if( this->started ) {
-
- if( master_status != XINE_STATUS_PLAY ||
- slave_status != XINE_STATUS_PLAY ||
- vo_discard ) {
- lprintf("finished\n");
-
- this->width = this->height = 0;
- this->finished = 1;
- return;
- }
-
- if( this->osd ) {
-
- /* try to use frame number mode */
- if( !uses_time && extra_info.frame_number ) {
-
- diff = end - extra_info.frame_number;
-
- /* discard old subtitles */
- if( diff < 0 ) {
- xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
- "libsputext: discarding old subtitle\n");
- return;
- }
-
- diff = start - extra_info.frame_number;
-
- start_vpts = extra_info.vpts + diff * this->img_duration;
- end_vpts = start_vpts + (end-start) * this->img_duration;
-
- } else {
-
- if( !uses_time ) {
- start = start * this->img_duration / 90;
- end = end * this->img_duration / 90;
- uses_time = 1;
- }
-
- diff = end - extra_info.input_time;
-
- /* discard old subtitles */
- if( diff < 0 ) {
- xprintf(this->class->xine, XINE_VERBOSITY_DEBUG,
- "libsputext: discarding old subtitle\n");
- return;
- }
-
- diff = start - extra_info.input_time;
-
- start_vpts = extra_info.vpts + diff * 90;
- end_vpts = start_vpts + (end-start) * 90;
- }
-
- _x_spu_decoder_sleep(this->stream, start_vpts);
- update_output_size( this );
- draw_subtitle(this, start_vpts, end_vpts);
-
- return;
- }
- }
-
- if (_x_spu_decoder_sleep(this->stream, 0))
- xine_usec_sleep (50000);
- else
- return;
- }
-}
-
-
-static void spudec_reset (spu_decoder_t *this_gen) {
- sputext_decoder_t *this = (sputext_decoder_t *) this_gen;
-
- lprintf("i guess we just seeked\n");
- this->width = this->height = 0;
- this->started = this->finished = 0;
- this->last_subtitle_end = 0;
-}
-
-static void spudec_discontinuity (spu_decoder_t *this_gen) {
- /* sputext_decoder_t *this = (sputext_decoder_t *) this_gen; */
-
-}
-
-static void spudec_dispose (spu_decoder_t *this_gen) {
- sputext_decoder_t *this = (sputext_decoder_t *) this_gen;
-
- if (this->osd) {
- this->renderer->free_object (this->osd);
- this->osd = NULL;
- }
- free(this);
-}
-
-static void update_vertical_offset(void *class_gen, xine_cfg_entry_t *entry)
-{
- sputext_class_t *class = (sputext_class_t *)class_gen;
-
- class->vertical_offset = entry->num_value;
-}
-
-static void update_osd_font(void *class_gen, xine_cfg_entry_t *entry)
-{
- sputext_class_t *class = (sputext_class_t *)class_gen;
-
- strncpy(class->font, entry->str_value, FONTNAME_SIZE);
- class->font[FONTNAME_SIZE - 1] = '\0';
-
- xprintf(class->xine, XINE_VERBOSITY_DEBUG, "libsputext: spu_font = %s\n", class->font );
-}
-
-#ifdef HAVE_FT2
-static void update_osd_font_ft(void *class_gen, xine_cfg_entry_t *entry)
-{
- sputext_class_t *class = (sputext_class_t *)class_gen;
-
- strncpy(class->font_ft, entry->str_value, FILENAME_MAX);
- class->font_ft[FILENAME_MAX - 1] = '\0';
-
- xprintf(class->xine, XINE_VERBOSITY_DEBUG, "libsputext: spu_font_ft = %s\n", class->font_ft);
-}
-
-static void update_osd_use_font_ft(void *class_gen, xine_cfg_entry_t *entry)
-{
- sputext_class_t *class = (sputext_class_t *)class_gen;
-
- class->use_font_ft = entry->num_value;
-
- xprintf(class->xine, XINE_VERBOSITY_DEBUG, "libsputext: spu_use_font_ft = %d\n", class->use_font_ft);
-}
-#endif
-
-static void update_subtitle_size(void *class_gen, xine_cfg_entry_t *entry)
-{
- sputext_class_t *class = (sputext_class_t *)class_gen;
-
- class->subtitle_size = entry->num_value;
-}
-
-static void update_use_unscaled(void *class_gen, xine_cfg_entry_t *entry)
-{
- sputext_class_t *class = (sputext_class_t *)class_gen;
-
- class->use_unscaled = entry->num_value;
-}
-
-static spu_decoder_t *sputext_class_open_plugin (spu_decoder_class_t *class_gen, xine_stream_t *stream) {
-
- sputext_class_t *class = (sputext_class_t *)class_gen;
- sputext_decoder_t *this ;
-
- this = (sputext_decoder_t *) calloc(1, sizeof(sputext_decoder_t));
-
- this->spu_decoder.decode_data = spudec_decode_data;
- this->spu_decoder.reset = spudec_reset;
- this->spu_decoder.discontinuity = spudec_discontinuity;
- this->spu_decoder.get_interact_info = NULL;
- this->spu_decoder.set_button = NULL;
- this->spu_decoder.dispose = spudec_dispose;
-
- this->class = class;
- this->stream = stream;
-
- return (spu_decoder_t *) this;
-}
-
-static void sputext_class_dispose (spu_decoder_class_t *class_gen) {
- sputext_class_t *this = (sputext_class_t *)class_gen;
-
- this->xine->config->unregister_callback(this->xine->config,
- "subtitles.separate.src_encoding");
- this->xine->config->unregister_callback(this->xine->config,
- "subtitles.separate.subtitle_size");
- this->xine->config->unregister_callback(this->xine->config,
- "subtitles.separate.vertical_offset");
- this->xine->config->unregister_callback(this->xine->config,
- "subtitles.separate.use_unscaled_osd");
- free (this);
-}
-
-static char *sputext_class_get_identifier (spu_decoder_class_t *this) {
- return "sputext";
-}
-
-static char *sputext_class_get_description (spu_decoder_class_t *this) {
- return "external subtitle decoder plugin";
-}
-
-static void update_src_encoding(void *class_gen, xine_cfg_entry_t *entry)
-{
- sputext_class_t *class = (sputext_class_t *)class_gen;
-
- class->src_encoding = entry->str_value;
- xprintf(class->xine, XINE_VERBOSITY_DEBUG, "libsputext: spu_src_encoding = %s\n", class->src_encoding );
-}
-
-static void *init_spu_decoder_plugin (xine_t *xine, void *data) {
-
- static const char *subtitle_size_strings[] = {
- "tiny", "small", "normal", "large", "very large", "huge", NULL
- };
- sputext_class_t *this ;
-
- lprintf("init class\n");
-
- this = (sputext_class_t *) calloc(1, sizeof(sputext_class_t));
-
- this->class.open_plugin = sputext_class_open_plugin;
- this->class.get_identifier = sputext_class_get_identifier;
- this->class.get_description = sputext_class_get_description;
- this->class.dispose = sputext_class_dispose;
-
- this->xine = xine;
-
- this->subtitle_size = xine->config->register_enum(xine->config,
- "subtitles.separate.subtitle_size",
- 1,
- subtitle_size_strings,
- _("subtitle size"),
- _("You can adjust the subtitle size here. The setting will "
- "be evaluated relative to the window size."),
- 0, update_subtitle_size, this);
- this->vertical_offset = xine->config->register_num(xine->config,
- "subtitles.separate.vertical_offset",
- 0,
- _("subtitle vertical offset"),
- _("You can adjust the vertical position of the subtitle. "
- "The setting will be evaluated relative to the window size."),
- 0, update_vertical_offset, this);
- strncpy(this->font, xine->config->register_string(xine->config,
- "subtitles.separate.font",
- "sans",
- _("font for subtitles"),
- _("A font from the xine font directory to be used for the "
- "subtitle text."),
- 10, update_osd_font, this), FONTNAME_SIZE);
- this->font[FONTNAME_SIZE - 1] = '\0';
-#ifdef HAVE_FT2
- strncpy(this->font_ft, xine->config->register_filename(xine->config,
- "subtitles.separate.font_freetype",
- "", XINE_CONFIG_STRING_IS_FILENAME,
- _("font for subtitles"),
- _("An outline font file (e.g. a .ttf) to be used for the subtitle text."),
- 10, update_osd_font_ft, this), FILENAME_MAX);
- this->font_ft[FILENAME_MAX - 1] = '\0';
- this->use_font_ft = xine->config->register_bool(xine->config,
- "subtitles.separate.font_use_freetype",
- 0,
- _("whether to use a freetype font"),
- NULL,
- 10, update_osd_use_font_ft, this);
-#endif
- this->src_encoding = xine->config->register_string(xine->config,
- "subtitles.separate.src_encoding",
- xine_guess_spu_encoding(),
- _("encoding of the subtitles"),
- _("The encoding of the subtitle text in the stream. This setting "
- "is used to render non-ASCII characters correctly. If non-ASCII "
- "characters are not displayed as you expect, ask the "
- "creator of the subtitles what encoding was used."),
- 10, update_src_encoding, this);
- this->use_unscaled = xine->config->register_bool(xine->config,
- "subtitles.separate.use_unscaled_osd",
- 1,
- _("use unscaled OSD if possible"),
- _("The unscaled OSD will be rendered independently of the video "
- "frame and will always be sharp, even if the video is magnified. "
- "This will look better, but does not work with all graphics "
- "hardware. The alternative is the scaled OSD, which will become "
- "blurry, if you enlarge a low resolution video to fullscreen, but "
- "it works with all graphics cards."),
- 10, update_use_unscaled, this);
-
- return &this->class;
-}
-
-
-/* plugin catalog information */
-static uint32_t supported_types[] = { BUF_SPU_TEXT, BUF_SPU_OGM, 0 };
-
-static const decoder_info_t spudec_info = {
- supported_types, /* supported types */
- 1 /* priority */
-};
-
-const plugin_info_t xine_plugin_info[] EXPORTED = {
- /* type, API, "name", version, special_info, init_function */
- { PLUGIN_SPU_DECODER | PLUGIN_MUST_PRELOAD, 16, "sputext", XINE_VERSION_CODE, &spudec_info, &init_spu_decoder_plugin },
- { PLUGIN_NONE, 0, "", 0, NULL, NULL }
-};