summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/mplayer.c9
-rw-r--r--core/options.h1
-rw-r--r--demux/demux.c2
-rw-r--r--demux/demux.h1
-rw-r--r--demux/demux_subreader.c273
-rw-r--r--demux/stheader.h1
-rw-r--r--demux/subreader.h79
-rw-r--r--sub/dec_sub.c65
8 files changed, 229 insertions, 202 deletions
diff --git a/core/mplayer.c b/core/mplayer.c
index e0049a8bd0..f766246f63 100644
--- a/core/mplayer.c
+++ b/core/mplayer.c
@@ -71,7 +71,6 @@
#include "core/mplayer.h"
#include "core/m_property.h"
-#include "demux/subreader.h"
#include "sub/find_subfiles.h"
#include "sub/dec_sub.h"
#include "sub/sd.h"
@@ -1044,7 +1043,6 @@ struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename,
{
struct MPOpts *opts = &mpctx->opts;
struct ass_track *asst = NULL;
- sub_data *subd = NULL;
if (filename == NULL)
return NULL;
@@ -1055,17 +1053,14 @@ struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename,
// the weird special-cases.
#ifdef CONFIG_ASS
asst = mp_ass_read_stream(mpctx->ass_library, filename, opts->sub_cp);
- if (!asst)
- subd = sub_read_file(filename, fps, &mpctx->opts);
- if (asst || subd) {
+ if (asst) {
struct demuxer *d = new_sub_pseudo_demuxer(opts);
assert(d->num_streams == 1);
struct sh_stream *s = d->streams[0];
assert(s->type == STREAM_SUB);
- s->codec = asst ? "ass" : subd->codec;
+ s->codec = "ass";
s->sub->track = asst;
- s->sub->sub_data = subd;
struct sh_sub **pptr = talloc(d, struct sh_sub*);
*pptr = s->sub;
diff --git a/core/options.h b/core/options.h
index f925990a6c..c31d2063c9 100644
--- a/core/options.h
+++ b/core/options.h
@@ -147,7 +147,6 @@ typedef struct MPOpts {
// subreader.c
int suboverlap_enabled;
char *sub_cp;
- int sub_no_text_pp;
char *audio_stream;
int audio_stream_cache;
diff --git a/demux/demux.c b/demux/demux.c
index be00f38bd7..379a74f654 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -68,6 +68,7 @@ extern const demuxer_desc_t demuxer_desc_mpeg4_es;
extern const demuxer_desc_t demuxer_desc_h264_es;
extern const demuxer_desc_t demuxer_desc_mpeg_ts;
extern const demuxer_desc_t demuxer_desc_sub;
+extern const demuxer_desc_t demuxer_desc_subreader;
/* Please do not add any new demuxers here. If you want to implement a new
* demuxer, add it to libavformat, except for wrappers around external
@@ -83,6 +84,7 @@ const demuxer_desc_t *const demuxer_list[] = {
#endif
&demuxer_desc_matroska,
&demuxer_desc_lavf,
+ &demuxer_desc_subreader,
&demuxer_desc_avi,
&demuxer_desc_asf,
#ifdef CONFIG_MNG
diff --git a/demux/demux.h b/demux/demux.h
index bf16001c0f..9c10ca0201 100644
--- a/demux/demux.h
+++ b/demux/demux.h
@@ -71,6 +71,7 @@ enum demuxer_type {
DEMUXER_TYPE_MNG,
DEMUXER_TYPE_EDL,
DEMUXER_TYPE_CUE,
+ DEMUXER_TYPE_SUBREADER,
/* Values after this are for internal use and can not be selected
* as demuxer type by the user (-demuxer option). */
diff --git a/demux/demux_subreader.c b/demux/demux_subreader.c
index befac689a4..e95ffda976 100644
--- a/demux/demux_subreader.c
+++ b/demux/demux_subreader.c
@@ -28,14 +28,15 @@
#include <dirent.h>
#include <ctype.h>
+#include <libavutil/common.h>
+#include <libavutil/avstring.h>
+
#include "config.h"
#include "core/mp_msg.h"
-#include "subreader.h"
#include "core/mp_common.h"
#include "core/options.h"
#include "stream/stream.h"
-#include "libavutil/common.h"
-#include "libavutil/avstring.h"
+#include "demux/demux.h"
#ifdef CONFIG_ENCA
#include <enca.h>
@@ -47,6 +48,54 @@
#include <iconv.h>
#endif
+// subtitle formats
+#define SUB_INVALID -1
+#define SUB_MICRODVD 0
+#define SUB_SUBRIP 1
+#define SUB_SUBVIEWER 2
+#define SUB_SAMI 3
+#define SUB_VPLAYER 4
+#define SUB_RT 5
+#define SUB_SSA 6
+#define SUB_PJS 7
+#define SUB_MPSUB 8
+#define SUB_AQTITLE 9
+#define SUB_SUBVIEWER2 10
+#define SUB_SUBRIP09 11
+#define SUB_JACOSUB 12
+#define SUB_MPL2 13
+
+#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 {
int utf16;
@@ -58,6 +107,8 @@ struct readline_args {
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
@@ -171,7 +222,7 @@ static subtitle *sub_read_line_sami(stream_t* st, subtitle *current,
sami_add_line(current, text, &p);
s += 4;
}
- else if ((*s == '{') && !args->opts->sub_no_text_pp) { state = 5; ++s; continue; }
+ else if ((*s == '{')) { state = 5; ++s; continue; }
else if (*s == '<') { state = 4; }
else if (!strncasecmp (s, "&nbsp;", 6)) { *p++ = ' '; s += 6; }
else if (*s == '\t') { *p++ = ' '; s++; }
@@ -197,7 +248,7 @@ static subtitle *sub_read_line_sami(stream_t* st, subtitle *current,
if (s) { s++; state = 3; continue; }
break;
case 5: /* get rid of {...} text, but read the alignment code */
- if ((*s == '\\') && (*(s + 1) == 'a') && !args->opts->sub_no_text_pp) {
+ if ((*s == '\\') && (*(s + 1) == 'a')) {
if (stristr(s, "\\a1") != NULL) {
current->alignment = SUB_ALIGNMENT_BOTTOMLEFT;
s = s + 3;
@@ -1130,6 +1181,7 @@ struct subreader {
void (*post)(subtitle *dest);
const char *name;
const char *codec_name;
+ struct readline_args args;
};
#ifdef CONFIG_ENCA
@@ -1192,16 +1244,9 @@ static const char* guess_cp(stream_t *st, const char *preferred_language, const
#undef MAX_GUESS_BUFFER_SIZE
#endif
-static int sub_destroy(void *ptr);
-
-sub_data* sub_read_file(char *filename, float fps, struct MPOpts *opts)
+static bool subreader_autodetect(stream_t *fd, struct MPOpts *opts,
+ struct subreader *out)
{
- int utf16;
- stream_t* fd;
- int n_max, i, j;
- subtitle *first, *sub, *return_sub, *alloced_sub = NULL;
- sub_data *subt_data;
- int uses_time = 0, sub_num = 0, sub_errs = 0;
static const struct subreader sr[]=
{
{ sub_read_line_microdvd, NULL, "microdvd", "microdvd" },
@@ -1221,42 +1266,46 @@ sub_data* sub_read_file(char *filename, float fps, struct MPOpts *opts)
};
const struct subreader *srp;
- if(filename==NULL) return NULL; //qnx segfault
- fd=open_stream (filename, NULL, NULL); if (!fd) return NULL;
-
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--;
- struct readline_args args = {utf16, opts};
- args.sub_slacktime = 20000; //20 sec
- args.mpsub_multiplier = (uses_time ? 100.0 : 1.0);
-
if (sub_format==SUB_INVALID) {
- mp_msg(MSGT_SUBREADER,MSGL_WARN,"SUB: Could not determine file format\n");
- free_stream(fd);
- return NULL;
+ mp_msg(MSGT_SUBREADER,MSGL_V,"SUB: Could not determine file format\n");
+ return false;
}
srp=sr+sub_format;
mp_msg(MSGT_SUBREADER, MSGL_V, "SUB: Detected subtitle file format: %s\n", srp->name);
+ *out = *srp;
+ out->args = (struct readline_args) {
+ .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;
+
#ifdef CONFIG_ICONV
- iconv_t icdsc = (iconv_t)(-1);
- {
- int l,k;
- k = -1;
- if ((l=strlen(filename))>4){
- char *exts[] = {".utf", ".utf8", ".utf-8" };
- for (k=3;--k>=0;)
- if (l >= strlen(exts[k]) && !strcasecmp(filename+(l - strlen(exts[k])), exts[k])){
- break;
- }
- }
- if (k<0) icdsc = subcp_open(fd, opts->sub_cp);
- }
+ iconv_t icdsc = subcp_open(fd, opts->sub_cp);
#endif
sub_num=0;n_max=32;
@@ -1287,11 +1336,10 @@ sub_data* sub_read_file(char *filename, float fps, struct MPOpts *opts)
#endif
free(first);
free(alloced_sub);
- free_stream(fd);
return NULL;
}
// Apply any post processing that needs recoding first
- if ((sub!=ERR) && !args.opts->sub_no_text_pp && srp->post) srp->post(sub);
+ 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;
@@ -1333,8 +1381,6 @@ sub_data* sub_read_file(char *filename, float fps, struct MPOpts *opts)
if(sub==ERR) ++sub_errs; else ++sub_num; // Error vs. Valid
}
- free_stream(fd);
-
#ifdef CONFIG_ICONV
subcp_close(icdsc);
#endif
@@ -1349,15 +1395,13 @@ sub_data* sub_read_file(char *filename, float fps, struct MPOpts *opts)
return NULL;
}
- adjust_subs_time(first, 6.0, fps, opts->sub_fps, 1, sub_num, uses_time);/*~6 secs AST*/
+ adjust_subs_time(first, 6.0, fps, opts->sub_fps, 1, sub_num, args.uses_time);/*~6 secs AST*/
return_sub = first;
if (return_sub == NULL) return NULL;
subt_data = talloc_zero(NULL, sub_data);
- talloc_set_destructor(subt_data, sub_destroy);
subt_data->codec = srp->codec_name ? srp->codec_name : "text";
- subt_data->filename = strdup(filename);
- subt_data->sub_uses_time = uses_time;
+ subt_data->sub_uses_time = args.uses_time;
subt_data->sub_num = sub_num;
subt_data->sub_errs = sub_errs;
subt_data->subtitles = return_sub;
@@ -1365,14 +1409,145 @@ sub_data* sub_read_file(char *filename, float fps, struct MPOpts *opts)
return subt_data;
}
-static int sub_destroy(void *ptr)
+static void subdata_free(sub_data *subd)
{
- sub_data *subd = ptr;
int i, j;
for (i = 0; i < subd->sub_num; i++)
for (j = 0; j < subd->subtitles[i].lines; j++)
free( subd->subtitles[i].text[j] );
free( subd->subtitles );
- free( subd->filename );
- return 0;
+ talloc_free(subd);
}
+
+struct priv {
+ struct demux_packet **pkts;
+ int num_pkts;
+ int current;
+ struct sh_stream *sh;
+};
+
+static void add_sub_data(struct demuxer *demuxer, struct sub_data *subdata)
+{
+ struct priv *priv = demuxer->priv;
+
+ for (int i = 0; i < subdata->sub_num; i++) {
+ subtitle *st = &subdata->subtitles[i];
+ // subdata is in 10 ms ticks, pts is in seconds
+ double t = subdata->sub_uses_time ? 0.01 : (1 / subdata->fallback_fps);
+
+ int len = 0;
+ for (int j = 0; j < st->lines; j++)
+ len += st->text[j] ? strlen(st->text[j]) : 0;
+
+ len += 2 * st->lines; // '\N', including the one after the last line
+ len += 6; // {\anX}
+ len += 1; // '\0'
+
+ char *data = talloc_array(NULL, char, len);
+
+ char *p = data;
+ char *end = p + len;
+
+ if (st->alignment)
+ p += snprintf(p, end - p, "{\\an%d}", st->alignment);
+
+ for (int j = 0; j < st->lines; j++)
+ p += snprintf(p, end - p, "%s\\N", st->text[j]);
+
+ if (st->lines > 0)
+ p -= 2; // remove last "\N"
+ *p = 0;
+
+ struct demux_packet *pkt = talloc_ptrtype(priv, pkt);
+ *pkt = (struct demux_packet) {
+ .pts = st->start * t,
+ .duration = (st->end - st->start) * t,
+ .buffer = talloc_steal(pkt, data),
+ .len = strlen(data),
+ };
+
+ MP_TARRAY_APPEND(priv, priv->pkts, priv->num_pkts, pkt);
+ }
+}
+
+static struct stream *read_probe_stream(struct stream *s, int max)
+{
+ // Very roundabout, but only needed for initial probing.
+ bstr probe = stream_peek(s, max);
+ return open_memory_stream(probe.start, probe.len);
+}
+
+#define PROBE_SIZE FFMIN(32 * 1024, STREAM_MAX_BUFFER_SIZE)
+
+static int d_check_file(struct demuxer *demuxer)
+{
+ struct stream *ps = read_probe_stream(demuxer->stream, PROBE_SIZE);
+
+ struct subreader sr;
+ bool res = subreader_autodetect(ps, demuxer->opts, &sr);
+
+ free_stream(ps);
+
+ if (!res)
+ return 0;
+
+ sub_data *sd = sub_read_file(demuxer->stream, &sr);
+ if (!sd)
+ return 0;
+
+ struct priv *p = talloc_zero(demuxer, struct priv);
+ demuxer->priv = p;
+
+ p->sh = new_sh_stream(demuxer, STREAM_SUB);
+ p->sh->codec = sd->codec;
+
+ add_sub_data(demuxer, sd);
+ subdata_free(sd);
+
+ demuxer->accurate_seek = true;
+
+ return DEMUXER_TYPE_SUBREADER;
+}
+
+static int d_fill_buffer(struct demuxer *demuxer, struct demux_stream *ds)
+{
+ struct priv *p = demuxer->priv;
+ struct demux_packet *dp = demux_packet_list_fill(p->pkts, p->num_pkts,
+ &p->current);
+ return demuxer_add_packet(demuxer, p->sh, dp);
+}
+
+static void d_seek(struct demuxer *demuxer, float secs, float audio_delay,
+ int flags)
+{
+ struct priv *p = demuxer->priv;
+ demux_packet_list_seek(p->pkts, p->num_pkts, &p->current, secs, flags);
+}
+
+static int d_control(struct demuxer *demuxer, int cmd, void *arg)
+{
+ struct priv *p = demuxer->priv;
+ switch (cmd) {
+ case DEMUXER_CTRL_CORRECT_PTS:
+ return DEMUXER_CTRL_OK;
+ case DEMUXER_CTRL_GET_TIME_LENGTH:
+ *((double *) arg) = demux_packet_list_duration(p->pkts, p->num_pkts);
+ return DEMUXER_CTRL_OK;
+ default:
+ return DEMUXER_CTRL_NOTIMPL;
+ }
+}
+
+const struct demuxer_desc demuxer_desc_subreader = {
+ .info = "Deprecated MPlayer subtitle reader",
+ .name = "subreader",
+ .shortdesc = "Deprecated Subreader",
+ .author = "",
+ .comment = "",
+ .type = DEMUXER_TYPE_SUBREADER,
+ .safe_check = 1,
+ .check_file = d_check_file,
+ .fill_buffer = d_fill_buffer,
+ .seek = d_seek,
+ .control = d_control,
+};
diff --git a/demux/stheader.h b/demux/stheader.h
index 421dfaf857..14418accb0 100644
--- a/demux/stheader.h
+++ b/demux/stheader.h
@@ -164,7 +164,6 @@ typedef struct sh_sub {
unsigned char *extradata; // extra header data passed from demuxer
int extradata_len;
struct ass_track *track; // loaded by libass
- struct sub_data *sub_data; // loaded by subreader.c
struct dec_sub *dec_sub; // decoder context
} sh_sub_t;
diff --git a/demux/subreader.h b/demux/subreader.h
deleted file mode 100644
index 3b2e53efd8..0000000000
--- a/demux/subreader.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * This file is part of MPlayer.
- *
- * MPlayer 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.
- *
- * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef MPLAYER_SUBREADER_H
-#define MPLAYER_SUBREADER_H
-
-#include <stdio.h>
-#include <stdbool.h>
-
-#include "config.h"
-
-// subtitle formats
-#define SUB_INVALID -1
-#define SUB_MICRODVD 0
-#define SUB_SUBRIP 1
-#define SUB_SUBVIEWER 2
-#define SUB_SAMI 3
-#define SUB_VPLAYER 4
-#define SUB_RT 5
-#define SUB_SSA 6
-#define SUB_PJS 7
-#define SUB_MPSUB 8
-#define SUB_AQTITLE 9
-#define SUB_SUBVIEWER2 10
-#define SUB_SUBRIP09 11
-#define SUB_JACOSUB 12
-#define SUB_MPL2 13
-
-#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;
- char *filename;
- int sub_uses_time;
- int sub_num; // number of subtitle structs
- int sub_errs;
- double fallback_fps;
-} sub_data;
-
-struct MPOpts;
-sub_data* sub_read_file (char *filename, float pts, struct MPOpts *opts);
-
-#endif /* MPLAYER_SUBREADER_H */
diff --git a/sub/dec_sub.c b/sub/dec_sub.c
index bfd6d90d03..dd1168d0ad 100644
--- a/sub/dec_sub.c
+++ b/sub/dec_sub.c
@@ -25,7 +25,6 @@
#include "sd.h"
#include "sub.h"
#include "dec_sub.h"
-#include "demux/subreader.h"
#include "core/options.h"
#include "core/mp_msg.h"
@@ -138,68 +137,6 @@ static void print_chain(struct dec_sub *sub)
mp_msg(MSGT_OSD, MSGL_V, "\n");
}
-// Subtitles read with subreader.c
-static void read_sub_data(struct dec_sub *sub, struct sub_data *subdata)
-{
- assert(sub_accept_packets_in_advance(sub));
- char *temp = NULL;
-
- struct sd *sd = sub_get_last_sd(sub);
-
- sd->no_remove_duplicates = true;
-
- for (int i = 0; i < subdata->sub_num; i++) {
- subtitle *st = &subdata->subtitles[i];
- // subdata is in 10 ms ticks, pts is in seconds
- double t = subdata->sub_uses_time ? 0.01 : (1 / subdata->fallback_fps);
-
- int len = 0;
- for (int j = 0; j < st->lines; j++)
- len += st->text[j] ? strlen(st->text[j]) : 0;
-
- len += 2 * st->lines; // '\N', including the one after the last line
- len += 6; // {\anX}
- len += 1; // '\0'
-
- if (talloc_get_size(temp) < len) {
- talloc_free(temp);
- temp = talloc_array(NULL, char, len);
- }
-
- char *p = temp;
- char *end = p + len;
-
- if (st->alignment)
- p += snprintf(p, end - p, "{\\an%d}", st->alignment);
-
- for (int j = 0; j < st->lines; j++)
- p += snprintf(p, end - p, "%s\\N", st->text[j]);
-
- if (st->lines > 0)
- p -= 2; // remove last "\N"
- *p = 0;
-
- struct demux_packet pkt = {0};
- pkt.pts = st->start * t;
- pkt.duration = (st->end - st->start) * t;
- pkt.buffer = temp;
- pkt.len = strlen(temp);
-
- sub_decode(sub, &pkt);
- }
-
- // Hack for broken FFmpeg packet format: make sd_ass keep the subtitle
- // events on reset(), even though broken FFmpeg ASS packets were received
- // (from sd_lavc_conv.c). Normally, these events are removed on seek/reset,
- // but this is obviously unwanted in this case.
- if (sd && sd->driver->fix_events)
- sd->driver->fix_events(sd);
-
- sd->no_remove_duplicates = false;
-
- talloc_free(temp);
-}
-
static int sub_init_decoder(struct dec_sub *sub, struct sd *sd)
{
sd->driver = NULL;
@@ -242,8 +179,6 @@ void sub_init_from_sh(struct dec_sub *sub, struct sh_sub *sh)
// Try adding new converters until a decoder is reached
if (sd->driver->get_bitmaps || sd->driver->get_text) {
print_chain(sub);
- if (sh->sub_data)
- read_sub_data(sub, sh->sub_data);
return;
}
init_sd = (struct sd) {