summaryrefslogtreecommitdiffstats
path: root/demux
diff options
context:
space:
mode:
Diffstat (limited to 'demux')
-rw-r--r--demux/demux.c28
-rw-r--r--demux/demux.h1
-rw-r--r--demux/demux_disc.c9
-rw-r--r--demux/demux_lavf.c4
-rw-r--r--demux/demux_libass.c111
-rw-r--r--demux/demux_mkv.c3
-rw-r--r--demux/demux_subreader.c837
7 files changed, 30 insertions, 963 deletions
diff --git a/demux/demux.c b/demux/demux.c
index 3233541be2..dcad692be5 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -48,8 +48,6 @@ extern const demuxer_desc_t demuxer_desc_tv;
extern const demuxer_desc_t demuxer_desc_mf;
extern const demuxer_desc_t demuxer_desc_matroska;
extern const demuxer_desc_t demuxer_desc_lavf;
-extern const demuxer_desc_t demuxer_desc_libass;
-extern const demuxer_desc_t demuxer_desc_subreader;
extern const demuxer_desc_t demuxer_desc_playlist;
extern const demuxer_desc_t demuxer_desc_disc;
extern const demuxer_desc_t demuxer_desc_rar;
@@ -68,9 +66,6 @@ const demuxer_desc_t *const demuxer_list[] = {
#if HAVE_TV
&demuxer_desc_tv,
#endif
-#if HAVE_LIBASS
- &demuxer_desc_libass,
-#endif
&demuxer_desc_matroska,
#if HAVE_LIBARCHIVE
&demuxer_desc_libarchive,
@@ -79,8 +74,6 @@ const demuxer_desc_t *const demuxer_list[] = {
&demuxer_desc_lavf,
&demuxer_desc_mf,
&demuxer_desc_playlist,
- // Pretty aggressive, so should be last.
- &demuxer_desc_subreader,
NULL
};
@@ -128,6 +121,8 @@ struct demux_internal {
bool refresh_seeks_enabled;
bool start_refresh_seek;
+ double ts_offset; // timestamp offset to apply everything
+
// Cached state.
bool force_cache_update;
double time_length;
@@ -168,6 +163,8 @@ struct demux_stream {
#define MP_PTS_MIN(a, b) MPMIN(PTS_OR_DEF(a, b), PTS_OR_DEF(b, a))
#define MP_PTS_MAX(a, b) MPMAX(PTS_OR_DEF(a, b), PTS_OR_DEF(b, a))
+#define MP_ADD_PTS(a, b) ((a) == MP_NOPTS_VALUE ? (a) : ((a) + (b)))
+
static void demuxer_sort_chapters(demuxer_t *demuxer);
static void *demux_thread(void *pctx);
static void update_cache(struct demux_internal *in);
@@ -193,6 +190,14 @@ static void ds_flush(struct demux_stream *ds)
ds->last_pos = -1;
}
+void demux_set_ts_offset(struct demuxer *demuxer, double offset)
+{
+ struct demux_internal *in = demuxer->in;
+ pthread_mutex_lock(&in->lock);
+ in->ts_offset = offset;
+ pthread_mutex_unlock(&in->lock);
+}
+
struct sh_stream *new_sh_stream(demuxer_t *demuxer, enum stream_type type)
{
assert(demuxer == demuxer->in->d_thread);
@@ -607,6 +612,9 @@ static struct demux_packet *dequeue_packet(struct demux_stream *ds)
if (pkt->pos >= ds->in->d_user->filepos)
ds->in->d_user->filepos = pkt->pos;
+ pkt->pts = MP_ADD_PTS(pkt->pts, ds->in->ts_offset);
+ pkt->dts = MP_ADD_PTS(pkt->dts, ds->in->ts_offset);
+
return pkt;
}
@@ -668,7 +676,7 @@ double demux_get_next_pts(struct sh_stream *sh)
pthread_mutex_lock(&sh->ds->in->lock);
ds_get_packets(sh->ds);
if (sh->ds->head)
- res = sh->ds->head->pts;
+ res = MP_ADD_PTS(sh->ds->head->pts, sh->ds->in->ts_offset);
pthread_mutex_unlock(&sh->ds->in->lock);
}
return res;
@@ -1152,6 +1160,8 @@ int demux_seek(demuxer_t *demuxer, double rel_seek_secs, int flags)
in->seeking = true;
in->seek_flags = flags;
in->seek_pts = rel_seek_secs;
+ if ((flags & SEEK_ABSOLUTE) && !(flags & SEEK_FACTOR))
+ in->seek_pts = MP_ADD_PTS(in->seek_pts, -in->ts_offset);
if (!in->threading)
execute_seek(in);
@@ -1423,6 +1433,8 @@ static int cached_demux_control(struct demux_internal *in, int cmd, void *arg)
r->ts_duration = MPMAX(0, r->ts_range[1] - r->ts_range[0]);
if (!num_packets || in->seeking)
r->ts_duration = 0;
+ r->ts_range[0] = MP_ADD_PTS(r->ts_range[0], in->ts_offset);
+ r->ts_range[1] = MP_ADD_PTS(r->ts_range[1], in->ts_offset);
return DEMUXER_CTRL_OK;
}
}
diff --git a/demux/demux.h b/demux/demux.h
index 7823d50233..96717d5eeb 100644
--- a/demux/demux.h
+++ b/demux/demux.h
@@ -271,6 +271,7 @@ bool demux_cancel_test(struct demuxer *demuxer);
void demux_flush(struct demuxer *demuxer);
int demux_seek(struct demuxer *demuxer, double rel_seek_secs, int flags);
void demux_set_enable_refresh_seeks(struct demuxer *demuxer, bool enabled);
+void demux_set_ts_offset(struct demuxer *demuxer, double offset);
int demux_control(struct demuxer *demuxer, int cmd, void *arg);
diff --git a/demux/demux_disc.c b/demux/demux_disc.c
index a816a74fa8..b994b3cf11 100644
--- a/demux/demux_disc.c
+++ b/demux/demux_disc.c
@@ -93,17 +93,16 @@ static void add_dvd_streams(demuxer_t *demuxer)
// emulate the extradata
struct mp_csp_params csp = MP_CSP_PARAMS_DEFAULTS;
- csp.int_bits_in = 8;
- csp.int_bits_out = 8;
struct mp_cmat cmatrix;
- mp_get_yuv2rgb_coeffs(&csp, &cmatrix);
+ mp_get_csp_matrix(&csp, &cmatrix);
char *s = talloc_strdup(sh, "");
s = talloc_asprintf_append(s, "palette: ");
for (int i = 0; i < 16; i++) {
int color = info.palette[i];
- int c[3] = {(color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff};
- mp_map_int_color(&cmatrix, 8, c);
+ int y[3] = {(color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff};
+ int c[3];
+ mp_map_fixp_color(&cmatrix, 8, y, 8, c);
color = (c[2] << 16) | (c[1] << 8) | c[0];
if (i != 0)
diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c
index eeed7a1b9a..2d12f5cfa2 100644
--- a/demux/demux_lavf.c
+++ b/demux/demux_lavf.c
@@ -612,6 +612,10 @@ static void handle_stream(demuxer_t *demuxer, int i)
sh_sub->frame_based = 23.976;
}
}
+
+ if (matches_avinputformat_name(priv, "ass"))
+ sh_sub->is_utf8 = true;
+
break;
}
case AVMEDIA_TYPE_ATTACHMENT: {
diff --git a/demux/demux_libass.c b/demux/demux_libass.c
deleted file mode 100644
index ef09f042ed..0000000000
--- a/demux/demux_libass.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * This file is part of mpv.
- *
- * mpv 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.
- *
- * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
- */
-
-// Note: just wraps libass, and makes the subtitle track available though
-// sh_sub->track. It doesn't produce packets and doesn't support seeking.
-
-#include <ass/ass.h>
-#include <ass/ass_types.h>
-
-#include "options/options.h"
-#include "common/msg.h"
-#include "misc/charset_conv.h"
-#include "stream/stream.h"
-#include "demux.h"
-
-#define PROBE_SIZE (8 * 1024)
-
-static void message_callback(int level, const char *format, va_list va, void *ctx)
-{
- // ignore
-}
-
-static int d_check_file(struct demuxer *demuxer, enum demux_check check)
-{
- const char *user_cp = demuxer->opts->sub_cp;
- struct stream *s = demuxer->stream;
- struct mp_log *log = demuxer->log;
-
- if (!demuxer->params || !demuxer->params->expect_subtitle)
- return -1;
-
- if (check >= DEMUX_CHECK_UNSAFE) {
- ASS_Library *lib = ass_library_init();
- if (!lib)
- return -1;
- ass_set_message_cb(lib, message_callback, NULL);
-
- // Probe by loading a part of the beginning of the file with libass.
- // Incomplete scripts are usually ok, and we hope libass is not verbose
- // when dealing with (from its perspective) completely broken binary
- // garbage.
-
- bstr buf = stream_peek(s, PROBE_SIZE);
- // Older versions of libass will overwrite the input buffer, and despite
- // passing length, expect a 0 termination.
- void *tmp = talloc_size(NULL, buf.len + 1);
- memcpy(tmp, buf.start, buf.len);
- buf.start = tmp;
- buf.start[buf.len] = '\0';
- bstr cbuf = mp_charset_guess_and_conv_to_utf8(log, buf, user_cp,
- MP_ICONV_ALLOW_CUTOFF);
- if (cbuf.start == NULL)
- cbuf = buf;
- ASS_Track *track = ass_read_memory(lib, cbuf.start, cbuf.len, NULL);
- bool ok = !!track;
- if (cbuf.start != buf.start)
- talloc_free(cbuf.start);
- talloc_free(buf.start);
- if (track)
- ass_free_track(track);
- ass_library_done(lib);
- if (!ok)
- return -1;
- }
-
- // Actually load the full thing.
-
- bstr buf = stream_read_complete(s, NULL, 100000000);
- if (!buf.start) {
- MP_ERR(demuxer, "Refusing to load subtitle file "
- "larger than 100 MB: %s\n", demuxer->filename);
- return -1;
- }
- bstr cbuf = mp_charset_guess_and_conv_to_utf8(log, buf, user_cp,
- MP_ICONV_VERBOSE);
- if (cbuf.start == NULL)
- cbuf = buf;
- if (cbuf.start != buf.start)
- talloc_free(buf.start);
- talloc_steal(demuxer, cbuf.start);
-
- struct sh_stream *sh = new_sh_stream(demuxer, STREAM_SUB);
- sh->codec = "ass";
- sh->extradata = cbuf.start;
- sh->extradata_size = cbuf.len;
-
- demuxer->seekable = true;
- demuxer->fully_read = true;
-
- return 0;
-}
-
-const struct demuxer_desc demuxer_desc_libass = {
- .name = "libass",
- .desc = "ASS/SSA subtitles (libass)",
- .open = d_check_file,
-};
diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c
index 733e441feb..a11691b317 100644
--- a/demux/demux_mkv.c
+++ b/demux/demux_mkv.c
@@ -2659,8 +2659,7 @@ static int create_index_until(struct demuxer *demuxer, uint64_t timecode)
mkv_index_t *index = get_highest_index_entry(demuxer);
if (!index || index->timecode * mkv_d->tc_scale < timecode) {
- if (index)
- stream_seek(s, index->filepos);
+ stream_seek(s, index ? index->filepos : mkv_d->cluster_start);
MP_VERBOSE(demuxer, "creating index until TC %" PRIu64 "\n", timecode);
for (;;) {
int res;
diff --git a/demux/demux_subreader.c b/demux/demux_subreader.c
deleted file mode 100644
index ecceb5d13d..0000000000
--- a/demux/demux_subreader.c
+++ /dev/null
@@ -1,837 +0,0 @@
-/*
- * Subtitle reader with format autodetection
- *
- * Copyright (c) 2001 laaz
- * Some code cleanup & realloc() by A'rpi/ESP-team
- *
- * This file is part of mpv.
- *
- * mpv 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.
- *
- * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <dirent.h>
-
-#include <libavutil/common.h>
-#include <libavutil/avstring.h>
-
-#include "config.h"
-#include "common/msg.h"
-#include "common/common.h"
-#include "options/options.h"
-#include "stream/stream.h"
-#include "demux/demux.h"
-
-#define ERR ((void *) -1)
-
-// subtitle formats
-#define SUB_INVALID -1
-#define SUB_MICRODVD 0
-#define SUB_SUBRIP 1
-#define SUB_SUBVIEWER 2
-#define SUB_SSA 3
-#define SUB_SUBVIEWER2 4
-#define SUB_SUBRIP09 5
-#define SUB_MPL2 6
-
-#define SUB_MAX_TEXT 12
-#define SUB_ALIGNMENT_BOTTOMLEFT 1
-#define SUB_ALIGNMENT_BOTTOMCENTER 2
-#define SUB_ALIGNMENT_BOTTOMRIGHT 3
-#define SUB_ALIGNMENT_MIDDLELEFT 4
-#define SUB_ALIGNMENT_MIDDLECENTER 5
-#define SUB_ALIGNMENT_MIDDLERIGHT 6
-#define SUB_ALIGNMENT_TOPLEFT 7
-#define SUB_ALIGNMENT_TOPCENTER 8
-#define SUB_ALIGNMENT_TOPRIGHT 9
-
-typedef struct subtitle {
-
- int lines;
-
- unsigned long start;
- unsigned long end;
-
- char *text[SUB_MAX_TEXT];
- unsigned char alignment;
-} subtitle;
-
-typedef struct sub_data {
- const char *codec;
- subtitle *subtitles;
- int sub_uses_time;
- int sub_num; // number of subtitle structs
- int sub_errs;
- double fallback_fps;
-} sub_data;
-
-// Parameter struct for the format-specific readline functions
-struct readline_args {
- struct mp_log *log;
- int utf16;
- struct MPOpts *opts;
-
- // subtitle reader state used by some formats
-
- float mpsub_multiplier;
- float mpsub_position;
- int sub_slacktime;
-
- int uses_time;
-
- /*
- Some subtitling formats, namely AQT and Subrip09, define the end of a
- subtitle as the beginning of the following. Since currently we read one
- subtitle at time, for these format we keep two global *subtitle,
- previous_aqt_sub and previous_subrip09_sub, pointing to previous subtitle,
- so we can change its end when we read current subtitle starting time.
- We use a single global unsigned long,
- previous_sub_end, for both (and even future) formats, to store the end of
- the previous sub: it is initialized to 0 in sub_read_file and eventually
- modified by sub_read_aqt_line or sub_read_subrip09_line.
- */
- unsigned long previous_sub_end;
-};
-
-/* Maximal length of line of a subtitle */
-#define LINE_LEN 1000
-
-static double demux_packet_list_duration(struct demux_packet **pkts, int num_pkts)
-{
- if (num_pkts > 0)
- return pkts[num_pkts - 1]->pts + pkts[num_pkts - 1]->duration;
- return 0;
-}
-
-static void demux_packet_list_seek(struct demux_packet **pkts, int num_pkts,
- int *current, double rel_seek_secs, int flags)
-{
- double ref_time = 0;
- if (*current >= 0 && *current < num_pkts) {
- ref_time = pkts[*current]->pts;
- } else if (*current == num_pkts && num_pkts > 0) {
- ref_time = pkts[num_pkts - 1]->pts + pkts[num_pkts - 1]->duration;
- }
-
- if (flags & SEEK_ABSOLUTE)
- ref_time = 0;
-
- if (flags & SEEK_FACTOR) {
- ref_time += demux_packet_list_duration(pkts, num_pkts) * rel_seek_secs;
- } else {
- ref_time += rel_seek_secs;
- }
-
- // Could do binary search, but it's probably not worth the complexity.
- int last_index = 0;
- for (int n = 0; n < num_pkts; n++) {
- if (pkts[n]->pts > ref_time)
- break;
- last_index = n;
- }
- *current = last_index;
-}
-
-static struct demux_packet *demux_packet_list_fill(struct demux_packet **pkts,
- int num_pkts, int *current)
-{
- if (*current < 0)
- *current = 0;
- if (*current >= num_pkts)
- return NULL;
- struct demux_packet *new = talloc(NULL, struct demux_packet);
- *new = *pkts[*current];
- *current += 1;
- return new;
-}
-
-static int eol(char p) {
- return p=='\r' || p=='\n' || p=='\0';
-}
-
-static const char *sub_readtext(const char *source, char **dest) {
- int len=0;
- const char *p=source;
-
-// printf("src=%p dest=%p \n",source,dest);
-
- while ( !eol(*p) && *p!= '|' ) {
- p++,len++;
- }
-
- *dest= malloc (len+1);
- if (!*dest) {return ERR;}
-
- strncpy(*dest, source, len);
- (*dest)[len]=0;
-
- while (*p=='\r' || *p=='\n' || *p=='|') p++;
-
- if (*p) return p; // not-last text field
- else return NULL; // last text field
-}
-
-static subtitle *set_multiline_text(struct readline_args *arg, subtitle *current,
- const char *text, int start)
-{
- int i = start;
- while ((text = sub_readtext(text, current->text + i))) {
- if (current->text[i] == ERR) return ERR;
- i++;
- if (i >= SUB_MAX_TEXT) {
- MP_WARN(arg, "Too many lines in a subtitle\n");
- current->lines = i;
- return current;
- }
- }
- current->lines = i + 1;
- return current;
-}
-
-static subtitle *sub_read_line_microdvd(stream_t *st,subtitle *current,
- struct readline_args *args)
-{
- int utf16 = args->utf16;
- char line[LINE_LEN+1];
- char line2[LINE_LEN+1];
-
- do {
- if (!stream_read_line (st, line, LINE_LEN, utf16)) return NULL;
- } while ((sscanf (line,
- "{%ld}{}%[^\r\n]",
- &(current->start), line2) < 2) &&
- (sscanf (line,
- "{%ld}{%ld}%[^\r\n]",
- &(current->start), &(current->end), line2) < 3));
-
- return set_multiline_text(args, current, line2, 0);
-}
-
-static subtitle *sub_read_line_mpl2(stream_t *st,subtitle *current,
- struct readline_args *args)
-{
- int utf16 = args->utf16;
- char line[LINE_LEN+1];
- char line2[LINE_LEN+1];
-
- do {
- if (!stream_read_line (st, line, LINE_LEN, utf16)) return NULL;
- } while ((sscanf (line,
- "[%ld][%ld]%[^\r\n]",
- &(current->start), &(current->end), line2) < 3));
- current->start *= 10;
- current->end *= 10;
-
- return set_multiline_text(args, current, line2, 0);
-}
-
-static subtitle *sub_read_line_subrip(stream_t* st, subtitle *current,
- struct readline_args *args)
-{
- int utf16 = args->utf16;
- char line[LINE_LEN+1];
- int a1,a2,a3,a4,b1,b2,b3,b4;
- char *p=NULL, *q=NULL;
- int len;
-
- while (1) {
- if (!stream_read_line (st, line, LINE_LEN, utf16)) return NULL;
- 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 (!stream_read_line (st, line, LINE_LEN, utf16)) return NULL;
-
- p=q=line;
- for (current->lines=1; current->lines < SUB_MAX_TEXT; current->lines++) {
- for (q=p,len=0; *p && *p!='\r' && *p!='\n' && *p!='|' && strncmp(p,"[br]",4); p++,len++);
- current->text[current->lines-1]=malloc (len+1);
- if (!current->text[current->lines-1]) return ERR;
- strncpy (current->text[current->lines-1], q, len);
- current->text[current->lines-1][len]='\0';
- if (!*p || *p=='\r' || *p=='\n') break;
- if (*p=='|') p++;
- else while (*p++!=']');
- }
- break;
- }
- return current;
-}
-
-static subtitle *sub_read_line_subviewer(stream_t *st, subtitle *current,
- struct readline_args *args)
-{
- int utf16 = args->utf16;
- int a1, a2, a3, a4, b1, b2, b3, b4, j = 0;
-
- while (!current->text[0]) {
- char line[LINE_LEN + 1], full_line[LINE_LEN + 1];
- int i;
-
- /* Parse SubRip header */
- if (!stream_read_line(st, line, LINE_LEN, utf16))
- return NULL;
- if (sscanf(line, "%d:%d:%d%*1[,.:]%d --> %d:%d:%d%*1[,.:]%d",
- &a1, &a2, &a3, &a4, &b1, &b2, &b3, &b4) < 8)
- continue;
-
- current->start = a1 * 360000 + a2 * 6000 + a3 * 100 + a4 / 10;
- current->end = b1 * 360000 + b2 * 6000 + b3 * 100 + b4 / 10;
-
- /* Concatenate lines */
- full_line[0] = 0;
- for (i = 0; i < SUB_MAX_TEXT; i++) {
- int blank = 1, len = 0;
- char *p;
-
- if (!stream_read_line(st, line, LINE_LEN, utf16))
- break;
-
- for (p = line; *p != '\n' && *p != '\r' && *p; p++, len++)
- if (*p != ' ' && *p != '\t')
- blank = 0;
-
- if (blank)
- break;
-
- *p = 0;
-
- if (!(j + 1 + len < sizeof(full_line) - 1))
- break;
-
- if (j != 0)
- full_line[j++] = '\n';
- snprintf(&full_line[j], sizeof(full_line) - j, "%s", line);
- full_line[LINE_LEN] = '\0';
- j += len;
- }
-
- if (full_line[0]) {
- current->text[0] = strdup(full_line);
- current->lines = 1;
- }
- }
- return current;
-}
-
-static subtitle *sub_read_line_subviewer2(stream_t *st,subtitle *current,
- struct readline_args *args)
-{
- int utf16 = args->utf16;
- char line[LINE_LEN+1];
- int a1,a2,a3,a4;
- char *p=NULL;
- int i,len;
-
- while (!current->text[0]) {
- if (!stream_read_line (st, line, LINE_LEN, utf16)) return NULL;
- if (line[0]!='{')
- continue;
- if ((len=sscanf (line, "{T %d:%d:%d:%d",&a1,&a2,&a3,&a4)) < 4)
- continue;
- current->start = a1*360000+a2*6000+a3*100+a4/10;
- for (i=0; i<SUB_MAX_TEXT;) {
- if (!stream_read_line (st, line, LINE_LEN, utf16)) break;
- if (line[0]=='}') break;
- len=0;
- for (p=line; *p!='\n' && *p!='\r' && *p; ++p,++len);
- if (len) {
- current->text[i]=malloc (len+1);
- if (!current->text[i]) return ERR;
- strncpy (current->text[i], line, len); current->text[i][len]='\0';
- ++i;
- } else {
- break;
- }
- }
- current->lines=i;
- }
- return current;
-}
-
-static subtitle *sub_read_line_ssa(stream_t *st,subtitle *current,
- struct readline_args *args)
-{
- /* Instead of hardcoding the expected fields and their order on
- * each dialogue line, this code should parse the "Format: " line
- * which lists the fields used in the script. As is, this may not
- * work correctly with all scripts.
- */
-
- int utf16 = args->utf16;
- int comma;
-
- int hour1, min1, sec1, hunsec1,
- hour2, min2, sec2, hunsec2, nothing;
- int num;
-
- char line[LINE_LEN+1],
- line3[LINE_LEN+1],
- *line2;
- char *tmp;
-
- do {
- if (!stream_read_line (st, line, LINE_LEN, utf16)) 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 );
-
- line2=strchr(line3, ',');
- if (!line2) return NULL;
-
- for (comma = 3; comma < 9; comma ++)
- if (!(line2 = strchr(++line2, ',')))
- return NULL;
- line2++;
-
- current->lines=0;num=0;
- current->start = 360000*hour1 + 6000*min1 + 100*sec1 + hunsec1;
- current->end = 360000*hour2 + 6000*min2 + 100*sec2 + hunsec2;
-
- while (((tmp=strstr(line2, "\\n")) != NULL) || ((tmp=strstr(line2, "\\N")) != NULL) ){
- current->text[num]=malloc(tmp-line2+1);
- strncpy (current->text[num], line2, tmp-line2);
- current->text[num][tmp-line2]='\0';
- line2=tmp+2;
- num++;
- current->lines++;
- if (current->lines >= SUB_MAX_TEXT) return current;
- }
-
- current->text[num]=strdup(line2);
- current->lines++;
-
- return current;
-}
-
-static subtitle *sub_read_line_subrip09(stream_t *st,subtitle *current,
- struct readline_args *args)
-{
- int utf16 = args->utf16;
- char line[LINE_LEN+1];
- int a1,a2,a3;
- int len;
-
-retry:
- while (1) {
- // try to locate next subtitle
- if (!stream_read_line (st, line, LINE_LEN, utf16))
- return NULL;
- if (!((len=sscanf (line, "[%d:%d:%d]",&a1,&a2,&a3)) < 3))
- break;
- }
-
- current->start = a1*360000+a2*6000+a3*100;
-
- if (!args->previous_sub_end)
- args->previous_sub_end = (current->start) ? current->start - 1 : 0;
-
- if (!stream_read_line (st, line, LINE_LEN, utf16))
- return NULL;
-
- current->text[0]=""; // just to be sure that string is clear
-
- if (set_multiline_text(args, current, line, 0) == ERR)
- return ERR;
-
- if (!strlen(current->text[0]) && current->lines <= 1)
- goto retry;
-
- return current;
-}
-
-static int sub_autodetect (stream_t* st, int *uses_time, int utf16) {
- char line[LINE_LEN+1];
- int i,j=0;
-
- while (j < 100) {
- j++;
- if (!stream_read_line (st, line, LINE_LEN, utf16))
- return SUB_INVALID;
-
- if (sscanf (line, "{%d}{%d}", &i, &i)==2)
- {*uses_time=0;return SUB_MICRODVD;}
- if (sscanf (line, "{%d}{}", &i)==1)
- {*uses_time=0;return SUB_MICRODVD;}
- if (sscanf (line, "[%d][%d]", &i, &i)==2)
- {*uses_time=1;return SUB_MPL2;}
- if (sscanf (line, "%d:%d:%d.%d,%d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i)==8)
- {*uses_time=1;return SUB_SUBRIP;}
- if (sscanf (line, "%d:%d:%d%*1[,.:]%d --> %d:%d:%d%*1[,.:]%d", &i, &i, &i, &i, &i, &i, &i, &i) == 8)
- {*uses_time=1;return SUB_SUBVIEWER;}
- if (sscanf (line, "{T %d:%d:%d:%d",&i, &i, &i, &i)==4)
- {*uses_time=1;return SUB_SUBVIEWER2;}
- if (!memcmp(line, "Dialogue: Marked", 16))
- {*uses_time=1; return SUB_SSA;}
- if (!memcmp(line, "Dialogue: ", 10))
- {*uses_time=1; return SUB_SSA;}
- if (sscanf (line, "[%d:%d:%d]", &i, &i, &i)==3)
- {*uses_time=1;return SUB_SUBRIP09;}
- }
-
- return SUB_INVALID; // too many bad lines
-}
-
-struct subreader {
- subtitle * (*read)(stream_t *st, subtitle *dest,
- struct readline_args *args);
- void (*post)(subtitle *dest);
- const char *name;
- const char *codec_name;
- struct readline_args args;
-};
-
-static void adjust_subs_time(struct subreader *srp, subtitle* sub,
- float subtime, float fps,
- float sub_fps, int block,
- int sub_num, int sub_uses_time) {
- int n,m;
- subtitle* nextsub;
- int i = sub_num;
- unsigned long subfms = (sub_uses_time ? 100 : fps) * subtime;
-
- n=m=0;
- if (i) for (;;){
- if (sub->end <= sub->start){
- sub->end = sub->start + subfms;
- m++;
- n++;
- }
- if (!--i) break;
- nextsub = sub + 1;
- if(block){
- if (sub->end >= nextsub->start){
- sub->end = nextsub->start - 1;
- if (sub->end - sub->start > subfms)
- sub->end = sub->start + subfms;
- if (!m)
- n++;
- }
- }
-
- sub = nextsub;
- m = 0;
- }
- if (n) MP_VERBOSE(&srp->args, "Adjusted %d subtitle(s).\n", n);
-}
-
-static bool subreader_autodetect(stream_t *fd, struct MPOpts *opts,
- struct mp_log *log, struct subreader *out)
-{
- static const struct subreader sr[]=
- {
- { sub_read_line_microdvd, NULL, "microdvd", "microdvd" },
- { sub_read_line_subrip, NULL, "subviewer" },
- { sub_read_line_subviewer, NULL, "subrip", "subrip" },
- { sub_read_line_ssa, NULL, "ssa", "ass-text" },
- { sub_read_line_subviewer2, NULL, "subviewer2" },
- { sub_read_line_subrip09, NULL, "subrip9" },
- { sub_read_line_mpl2, NULL, "mpl2" }
- };
- const struct subreader *srp;
-
- int sub_format = SUB_INVALID;
- int utf16;
- int uses_time = 0;
- for (utf16 = 0; sub_format == SUB_INVALID && utf16 < 3; utf16++) {
- sub_format=sub_autodetect (fd, &uses_time, utf16);
- stream_seek(fd,0);
- }
- utf16--;
-
- if (sub_format==SUB_INVALID) {
- mp_verbose(log, "Could not determine file format\n");
- return false;
- }
- srp=sr+sub_format;
- mp_verbose(log, "Detected subtitle file format: %s\n", srp->name);
-
- *out = *srp;
- out->args = (struct readline_args) {
- .log = log,
- .utf16 = utf16,
- .opts = opts,
- .sub_slacktime = 20000, //20 sec
- .mpsub_multiplier = (uses_time ? 100.0 : 1.0),
- .uses_time = uses_time,
- };
-
- return true;
-}
-
-static sub_data* sub_read_file(stream_t *fd, struct subreader *srp)
-{
- struct MPOpts *opts = fd->opts;
- float fps = 23.976;
- int n_max, i, j;
- subtitle *first, *sub, *return_sub, *alloced_sub = NULL;
- sub_data *subt_data;
- int sub_num = 0, sub_errs = 0;
- struct readline_args args = srp->args;
-
- sub_num=0;n_max=32;
- first=malloc(n_max*sizeof(subtitle));
- if (!first)
- abort();
-
- alloced_sub =
- sub = malloc(sizeof(subtitle));
- //This is to deal with those formats (AQT & Subrip) which define the end of a subtitle
- //as the beginning of the following
- args.previous_sub_end = 0;
- while(1){
- if(sub_num>=n_max){
- n_max+=16;
- first=realloc(first,n_max*sizeof(subtitle));
- }
- memset(sub, '\0', sizeof(subtitle));
- sub=srp->read(fd, sub, &args);
- if(!sub) break; // EOF
-
- if ( sub == ERR )
- {
- free(first);
- free(alloced_sub);
- return NULL;
- }
- // Apply any post processing that needs recoding first
- if ((sub!=ERR) && srp->post) srp->post(sub);
- if(!sub_num || (first[sub_num - 1].start <= sub->start)){
- first[sub_num].start = sub->start;
- first[sub_num].end = sub->end;
- first[sub_num].lines = sub->lines;
- first[sub_num].alignment = sub->alignment;
- for(i = 0; i < sub->lines; ++i){
- first[sub_num].text[i] = sub->text[i];
- }
- if (args.previous_sub_end){
- first[sub_num - 1].end = args.previous_sub_end;
- args.previous_sub_end = 0;
- }
- } else {
- for(j = sub_num - 1; j >= 0; --j){
- first[j + 1].start = first[j].start;
- first[j + 1].end = first[j].end;
- first[j + 1].lines = first[j].lines;
- first[j + 1].alignment = first[j].alignment;
- for(i = 0; i < first[j].lines; ++i){
- first[j + 1].text[i] = first[j].text[i];
- }
- if(!j || (first[j - 1].start <= sub->start)){
- first[j].start = sub->start;
- first[j].end = sub->end;
- first[j].lines = sub->lines;
- first[j].alignment = sub->alignment;
- for(i = 0; i < SUB_MAX_TEXT; ++i){
- first[j].text[i] = sub->text[i];
- }
- if (args.previous_sub_end){
- first[j].end = first[j - 1].end;
- first[j - 1].end = args.previous_sub_end;
- args.previous_sub_end = 0;
- }
- break;
- }
- }
- }
- if(sub==ERR) ++sub_errs; else ++sub_num; // Error vs. Valid
- }
-
- free(alloced_sub);
-
-// printf ("Subtitle format %s time.\n", uses_time?"uses":"doesn't use");
- MP_VERBOSE(&srp->args, "Read %i subtitles, %i bad line(s).\n",
- sub_num, sub_errs);
-
- if(sub_num<=0){
- free(first);
- return NULL;
- }
-
- adjust_subs_time(srp, first, 6.0, fps, opts->sub_fps, 1, sub_num