summaryrefslogtreecommitdiffstats
path: root/sub
diff options
context:
space:
mode:
Diffstat (limited to 'sub')
-rw-r--r--sub/ass_mp.c129
-rw-r--r--sub/ass_mp.h9
-rw-r--r--sub/dec_sub.c370
-rw-r--r--sub/dec_sub.h38
-rw-r--r--sub/find_sub.c174
-rw-r--r--sub/find_subfiles.c9
-rw-r--r--sub/osd_libass.c20
-rw-r--r--sub/sd.h74
-rw-r--r--sub/sd_ass.c247
-rw-r--r--sub/sd_lavc.c49
-rw-r--r--sub/sd_lavc_conv.c165
-rw-r--r--sub/sd_microdvd.c346
-rw-r--r--sub/sd_movtext.c55
-rw-r--r--sub/sd_spu.c102
-rw-r--r--sub/sd_srt.c (renamed from sub/subassconvert.c)277
-rw-r--r--sub/spudec.c33
-rw-r--r--sub/spudec.h4
-rw-r--r--sub/sub.c64
-rw-r--r--sub/sub.h26
-rw-r--r--sub/subassconvert.h27
-rw-r--r--sub/subreader.c334
-rw-r--r--sub/subreader.h24
22 files changed, 1456 insertions, 1120 deletions
diff --git a/sub/ass_mp.c b/sub/ass_mp.c
index 497e307953..258dd57688 100644
--- a/sub/ass_mp.c
+++ b/sub/ass_mp.c
@@ -38,7 +38,9 @@
#include "stream/stream.h"
#include "core/options.h"
-void mp_ass_set_style(ASS_Style *style, struct osd_style_opts *opts)
+// res_y should be track->PlayResY
+// It determines scaling of font sizes and more.
+void mp_ass_set_style(ASS_Style *style, int res_y, struct osd_style_opts *opts)
{
if (opts->font) {
free(style->FontName);
@@ -46,9 +48,9 @@ void mp_ass_set_style(ASS_Style *style, struct osd_style_opts *opts)
style->treat_fontname_as_pattern = 1;
}
- // libass_font_size = FontSize * (window_height / MP_ASS_FONT_PLAYRESY)
- // scale translates parameters from PlayResY=720 to MP_ASS_FONT_PLAYRESY
- double scale = MP_ASS_FONT_PLAYRESY / 720.0;
+ // libass_font_size = FontSize * (window_height / res_y)
+ // scale translates parameters from PlayResY=720 to res_y
+ double scale = res_y / 720.0;
style->FontSize = opts->font_size * scale;
style->PrimaryColour = MP_ASS_COLOR(opts->color);
@@ -74,129 +76,40 @@ void mp_ass_set_style(ASS_Style *style, struct osd_style_opts *opts)
#endif
}
-ASS_Track *mp_ass_default_track(ASS_Library *library, struct MPOpts *opts)
+// Add default styles, if the track does not have any styles yet.
+// Apply style overrides if the user provides any.
+void mp_ass_add_default_styles(ASS_Track *track, struct MPOpts *opts)
{
- ASS_Track *track = ass_new_track(library);
-
- track->track_type = TRACK_TYPE_ASS;
- track->Timer = 100.;
- track->PlayResY = MP_ASS_FONT_PLAYRESY;
- track->WrapStyle = 0;
-
if (opts->ass_styles_file && opts->ass_style_override)
- ass_read_styles(track, opts->ass_styles_file, sub_cp);
+ ass_read_styles(track, opts->ass_styles_file, opts->sub_cp);
if (track->n_styles == 0) {
+ if (!track->PlayResY) {
+ track->PlayResY = MP_ASS_FONT_PLAYRESY;
+ track->PlayResX = track->PlayResY * 4 / 3;
+ }
track->Kerning = true;
int sid = ass_alloc_style(track);
track->default_style = sid;
ASS_Style *style = track->styles + sid;
style->Name = strdup("Default");
style->Alignment = 2;
- mp_ass_set_style(style, opts->sub_text_style);
+ mp_ass_set_style(style, track->PlayResY, opts->sub_text_style);
}
if (opts->ass_style_override)
ass_process_force_style(track);
-
- return track;
}
-static int check_duplicate_plaintext_event(ASS_Track *track)
-{
- int i;
- ASS_Event *evt = track->events + track->n_events - 1;
-
- for (i = 0; i < track->n_events - 1; ++i) // ignoring last event, it is the one we are comparing with
- if (track->events[i].Start == evt->Start &&
- track->events[i].Duration == evt->Duration &&
- strcmp(track->events[i].Text, evt->Text) == 0)
- return 1;
- return 0;
-}
-
-/**
- * \brief Convert subtitle to ASS_Events for the given track
- * \param track track
- * \param sub subtitle to convert
- * \return event id
- * note: assumes that subtitle is _not_ fps-based; caller must manually correct
- * Start and Duration in other case.
- **/
-static int ass_process_subtitle(ASS_Track *track, subtitle *sub)
+ASS_Track *mp_ass_default_track(ASS_Library *library, struct MPOpts *opts)
{
- int eid;
- ASS_Event *event;
- int len = 0, j;
- char *p;
- char *end;
-
- eid = ass_alloc_event(track);
- event = track->events + eid;
-
- event->Start = sub->start * 10;
- event->Duration = (sub->end - sub->start) * 10;
- event->Style = track->default_style;
-
- for (j = 0; j < sub->lines; ++j)
- len += sub->text[j] ? strlen(sub->text[j]) : 0;
-
- len += 2 * sub->lines; // '\N', including the one after the last line
- len += 6; // {\anX}
- len += 1; // '\0'
-
- event->Text = malloc(len);
- end = event->Text + len;
- p = event->Text;
-
- if (sub->alignment)
- p += snprintf(p, end - p, "{\\an%d}", sub->alignment);
-
- for (j = 0; j < sub->lines; ++j)
- p += snprintf(p, end - p, "%s\\N", sub->text[j]);
-
- if (sub->lines > 0)
- p -= 2; // remove last "\N"
- *p = 0;
-
- if (check_duplicate_plaintext_event(track)) {
- ass_free_event(track, eid);
- track->n_events--;
- return -1;
- }
-
- mp_msg(MSGT_ASS, MSGL_V,
- "plaintext event at %" PRId64 ", +%" PRId64 ": %s \n",
- (int64_t) event->Start, (int64_t) event->Duration, event->Text);
-
- return eid;
-}
-
+ ASS_Track *track = ass_new_track(library);
-/**
- * \brief Convert subdata to ASS_Track
- * \param subdata subtitles struct from subreader
- * \param fps video framerate
- * \return newly allocated ASS_Track, filled with subtitles from subdata
- */
-ASS_Track *mp_ass_read_subdata(ASS_Library *library, struct MPOpts *opts,
- sub_data *subdata, double fps)
-{
- ASS_Track *track;
- int i;
+ track->track_type = TRACK_TYPE_ASS;
+ track->Timer = 100.;
- track = mp_ass_default_track(library, opts);
- track->name = subdata->filename ? strdup(subdata->filename) : 0;
+ mp_ass_add_default_styles(track, opts);
- for (i = 0; i < subdata->sub_num; ++i) {
- int eid = ass_process_subtitle(track, subdata->subtitles + i);
- if (eid < 0)
- continue;
- if (!subdata->sub_uses_time) {
- track->events[eid].Start *= 100. / fps;
- track->events[eid].Duration *= 100. / fps;
- }
- }
return track;
}
@@ -244,7 +157,7 @@ void mp_ass_configure(ASS_Renderer *priv, struct MPOpts *opts,
if (opts->ass_style_override) {
set_use_margins = opts->ass_use_margins;
#if LIBASS_VERSION >= 0x01010000
- set_sub_pos = 100 - sub_pos;
+ set_sub_pos = 100 - opts->sub_pos;
#endif
set_line_spacing = opts->ass_line_spacing;
set_font_scale = opts->sub_scale;
diff --git a/sub/ass_mp.h b/sub/ass_mp.h
index 0f67b17fe1..9f40b34166 100644
--- a/sub/ass_mp.h
+++ b/sub/ass_mp.h
@@ -27,7 +27,8 @@
#include "config.h"
#include "subreader.h"
-// font sizes and explicit tags in subassconvert.c assume this size (?)
+// This is probably arbitrary.
+// sd_lavc_conv might indirectly still assume this PlayResY, though.
#define MP_ASS_FONT_PLAYRESY 288
#define MP_ASS_RGBA(r, g, b, a) \
@@ -44,11 +45,11 @@ struct MPOpts;
struct mp_osd_res;
struct osd_style_opts;
-void mp_ass_set_style(ASS_Style *style, struct osd_style_opts *opts);
+void mp_ass_set_style(ASS_Style *style, int res_y, struct osd_style_opts *opts);
+
+void mp_ass_add_default_styles(ASS_Track *track, struct MPOpts *opts);
ASS_Track *mp_ass_default_track(ASS_Library *library, struct MPOpts *opts);
-ASS_Track *mp_ass_read_subdata(ASS_Library *library, struct MPOpts *opts,
- sub_data *subdata, double fps);
ASS_Track *mp_ass_read_stream(ASS_Library *library, const char *fname,
char *charset);
diff --git a/sub/dec_sub.c b/sub/dec_sub.c
index d3cedea80d..b72630470c 100644
--- a/sub/dec_sub.c
+++ b/sub/dec_sub.c
@@ -22,105 +22,351 @@
#include "config.h"
#include "demux/stheader.h"
-#include "sub/sd.h"
-#include "sub/sub.h"
-#include "sub/dec_sub.h"
+#include "sd.h"
+#include "sub.h"
+#include "dec_sub.h"
+#include "subreader.h"
#include "core/options.h"
+#include "core/mp_msg.h"
extern const struct sd_functions sd_ass;
extern const struct sd_functions sd_lavc;
+extern const struct sd_functions sd_spu;
+extern const struct sd_functions sd_movtext;
+extern const struct sd_functions sd_srt;
+extern const struct sd_functions sd_microdvd;
+extern const struct sd_functions sd_lavc_conv;
-bool is_text_sub(const char *t)
+static const struct sd_functions *sd_list[] = {
+#ifdef CONFIG_ASS
+ &sd_ass,
+#endif
+ &sd_lavc,
+ &sd_spu,
+ &sd_movtext,
+ &sd_srt,
+ &sd_microdvd,
+ &sd_lavc_conv,
+ NULL
+};
+
+#define MAX_NUM_SD 3
+
+struct dec_sub {
+ struct MPOpts *opts;
+ struct sd init_sd;
+
+ struct sd *sd[MAX_NUM_SD];
+ int num_sd;
+};
+
+struct dec_sub *sub_create(struct MPOpts *opts)
{
- return t && (is_ass_sub(t) ||
- strcmp(t, "text") == 0 ||
- strcmp(t, "subrip") == 0 ||
- strcmp(t, "mov_text") == 0);
+ struct dec_sub *sub = talloc_zero(NULL, struct dec_sub);
+ sub->opts = opts;
+ return sub;
}
-bool is_ass_sub(const char *t)
+static void sub_uninit(struct dec_sub *sub)
{
- return t && (strcmp(t, "ass") == 0 ||
- strcmp(t, "ssa") == 0);
+ sub_reset(sub);
+ for (int n = 0; n < sub->num_sd; n++) {
+ if (sub->sd[n]->driver->uninit)
+ sub->sd[n]->driver->uninit(sub->sd[n]);
+ talloc_free(sub->sd[n]);
+ }
+ sub->num_sd = 0;
}
-bool is_dvd_sub(const char *t)
+void sub_destroy(struct dec_sub *sub)
{
- return t && strcmp(t, "dvd_subtitle") == 0;
+ if (!sub)
+ return;
+ sub_uninit(sub);
+ talloc_free(sub);
}
-void sub_init(struct sh_sub *sh, struct osd_state *osd)
+bool sub_is_initialized(struct dec_sub *sub)
{
- struct MPOpts *opts = sh->opts;
+ return !!sub->num_sd;
+}
- assert(!osd->sh_sub);
- if (sd_lavc.probe(sh))
- sh->sd_driver = &sd_lavc;
-#ifdef CONFIG_ASS
- if (opts->ass_enabled && sd_ass.probe(sh))
- sh->sd_driver = &sd_ass;
-#endif
- if (sh->sd_driver) {
- if (sh->sd_driver->init(sh, osd) < 0)
+struct sd *sub_get_last_sd(struct dec_sub *sub)
+{
+ return sub->num_sd ? sub->sd[sub->num_sd - 1] : NULL;
+}
+
+void sub_set_video_res(struct dec_sub *sub, int w, int h)
+{
+ sub->init_sd.sub_video_w = w;
+ sub->init_sd.sub_video_h = h;
+}
+
+void sub_set_extradata(struct dec_sub *sub, void *data, int data_len)
+{
+ sub->init_sd.extradata = data_len ? talloc_memdup(sub, data, data_len) : NULL;
+ sub->init_sd.extradata_len = data_len;
+}
+
+void sub_set_ass_renderer(struct dec_sub *sub, struct ass_library *ass_library,
+ struct ass_renderer *ass_renderer)
+{
+ sub->init_sd.ass_library = ass_library;
+ sub->init_sd.ass_renderer = ass_renderer;
+}
+
+static void print_chain(struct dec_sub *sub)
+{
+ mp_msg(MSGT_OSD, MSGL_V, "Subtitle filter chain: ");
+ for (int n = 0; n < sub->num_sd; n++) {
+ struct sd *sd = sub->sd[n];
+ mp_msg(MSGT_OSD, MSGL_V, "%s%s (%s)", n > 0 ? " -> " : "",
+ sd->driver->name, sd->codec);
+ }
+ 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;
+ for (int n = 0; sd_list[n]; n++) {
+ if (sd_list[n]->supports_format(sd->codec)) {
+ sd->driver = sd_list[n];
+ break;
+ }
+ }
+
+ if (!sd->driver)
+ return -1;
+
+ if (sd->driver->init(sd) < 0)
+ return -1;
+
+ return 0;
+}
+
+void sub_init_from_sh(struct dec_sub *sub, struct sh_sub *sh)
+{
+ assert(!sub->num_sd);
+
+ if (sh->extradata && !sub->init_sd.extradata)
+ sub_set_extradata(sub, sh->extradata, sh->extradata_len);
+ struct sd init_sd = sub->init_sd;
+ init_sd.codec = sh->gsh->codec;
+ init_sd.ass_track = sh->track;
+
+ while (sub->num_sd < MAX_NUM_SD) {
+ struct sd *sd = talloc(NULL, struct sd);
+ *sd = init_sd;
+ sd->opts = sub->opts;
+ if (sub_init_decoder(sub, sd) < 0) {
+ talloc_free(sd);
+ break;
+ }
+ sub->sd[sub->num_sd] = sd;
+ sub->num_sd++;
+ // 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;
- osd->sh_sub = sh;
- osd->switch_sub_id++;
- sh->initialized = true;
- sh->active = true;
+ }
+ init_sd = (struct sd) {
+ .codec = sd->output_codec,
+ .converted_from = sd->codec,
+ .extradata = sd->output_extradata,
+ .extradata_len = sd->output_extradata_len,
+ .ass_library = sub->init_sd.ass_library,
+ .ass_renderer = sub->init_sd.ass_renderer,
+ };
+ }
+
+ sub_uninit(sub);
+ mp_msg(MSGT_OSD, MSGL_ERR, "Could not find subtitle decoder for format '%s'.\n",
+ sh->gsh->codec ? sh->gsh->codec : "<unknown>");
+}
+
+bool sub_accept_packets_in_advance(struct dec_sub *sub)
+{
+ // Converters are assumed to always accept packets in advance
+ struct sd *sd = sub_get_last_sd(sub);
+ return sd && sd->driver->accept_packets_in_advance;
+}
+
+static void decode_next(struct dec_sub *sub, int n, struct demux_packet *packet)
+{
+ struct sd *sd = sub->sd[n];
+ sd->driver->decode(sd, packet);
+ if (n + 1 >= sub->num_sd || !sd->driver->get_converted)
+ return;
+ while (1) {
+ struct demux_packet *next =
+ sd->driver->get_converted ? sd->driver->get_converted(sd) : NULL;
+ if (!next)
+ break;
+ decode_next(sub, n + 1, next);
}
}
-void sub_decode(struct sh_sub *sh, struct osd_state *osd, void *data,
- int data_len, double pts, double duration)
+void sub_decode(struct dec_sub *sub, struct demux_packet *packet)
{
- if (sh->active && sh->sd_driver->decode)
- sh->sd_driver->decode(sh, osd, data, data_len, pts, duration);
+ if (sub->num_sd > 0)
+ decode_next(sub, 0, packet);
}
-void sub_get_bitmaps(struct osd_state *osd, struct mp_osd_res dim, double pts,
+void sub_get_bitmaps(struct dec_sub *sub, struct mp_osd_res dim, double pts,
struct sub_bitmaps *res)
{
- struct MPOpts *opts = osd->opts;
+ struct MPOpts *opts = sub->opts;
+ struct sd *sd = sub_get_last_sd(sub);
*res = (struct sub_bitmaps) {0};
- if (!opts->sub_visibility || !osd->sh_sub || !osd->sh_sub->active) {
- /* Change ID in case we just switched from visible subtitles
- * to current state. Hopefully, unnecessarily claiming that
- * things may have changed is harmless for empty contents.
- * Increase osd-> values ahead so that _next_ returned id
- * is also guaranteed to differ from this one.
- */
- osd->switch_sub_id++;
- } else {
- if (osd->sh_sub->sd_driver->get_bitmaps)
- osd->sh_sub->sd_driver->get_bitmaps(osd->sh_sub, osd, dim, pts, res);
+ if (sd && opts->sub_visibility) {
+ if (sd->driver->get_bitmaps)
+ sd->driver->get_bitmaps(sd, dim, pts, res);
}
+}
- res->bitmap_id += osd->switch_sub_id;
- res->bitmap_pos_id += osd->switch_sub_id;
- osd->switch_sub_id = 0;
+bool sub_has_get_text(struct dec_sub *sub)
+{
+ struct sd *sd = sub_get_last_sd(sub);
+ return sd && sd->driver->get_text;
}
-void sub_reset(struct sh_sub *sh, struct osd_state *osd)
+char *sub_get_text(struct dec_sub *sub, double pts)
{
- if (sh->active && sh->sd_driver->reset)
- sh->sd_driver->reset(sh, osd);
+ struct MPOpts *opts = sub->opts;
+ struct sd *sd = sub_get_last_sd(sub);
+ char *text = NULL;
+ if (sd && opts->sub_visibility) {
+ if (sd->driver->get_text)
+ text = sd->driver->get_text(sd, pts);
+ }
+ return text;
}
-void sub_switchoff(struct sh_sub *sh, struct osd_state *osd)
+void sub_reset(struct dec_sub *sub)
{
- if (sh->active && sh->sd_driver->switch_off) {
- assert(osd->sh_sub == sh);
- sh->sd_driver->switch_off(sh, osd);
- osd->sh_sub = NULL;
+ for (int n = 0; n < sub->num_sd; n++) {
+ if (sub->sd[n]->driver->reset)
+ sub->sd[n]->driver->reset(sub->sd[n]);
}
- sh->active = false;
}
-void sub_uninit(struct sh_sub *sh)
+#define MAX_PACKETS 10
+#define MAX_BYTES 10000
+
+struct sd_conv_buffer {
+ struct demux_packet pkt[MAX_PACKETS];
+ int num_pkt;
+ int read_pkt;
+ char buffer[MAX_BYTES];
+ int cur_buffer;
+};
+
+void sd_conv_add_packet(struct sd *sd, void *data, int data_len, double pts,
+ double duration)
+{
+ if (!sd->sd_conv_buffer)
+ sd->sd_conv_buffer = talloc_zero(sd, struct sd_conv_buffer);
+ struct sd_conv_buffer *buf = sd->sd_conv_buffer;
+ if (buf->num_pkt >= MAX_PACKETS || buf->cur_buffer + data_len + 1 > MAX_BYTES)
+ goto out_of_space;
+ if (buf->read_pkt == buf->num_pkt)
+ sd_conv_def_reset(sd);
+ assert(buf->read_pkt == 0); // no mixing of reading/adding allowed
+ struct demux_packet *pkt = &buf->pkt[buf->num_pkt++];
+ *pkt = (struct demux_packet) {
+ .buffer = &buf->buffer[buf->cur_buffer],
+ .len = data_len,
+ .pts = pts,
+ .duration = duration,
+ };
+ memcpy(pkt->buffer, data, data_len);
+ pkt->buffer[data_len] = 0;
+ buf->cur_buffer += data_len + 1;
+ return;
+
+out_of_space:
+ mp_msg(MSGT_OSD, MSGL_ERR, "Subtitle too big.\n");
+}
+
+struct demux_packet *sd_conv_def_get_converted(struct sd *sd)
{
- assert (!sh->active);
- if (sh->initialized && sh->sd_driver->uninit)
- sh->sd_driver->uninit(sh);
- sh->initialized = false;
+ struct sd_conv_buffer *buf = sd->sd_conv_buffer;
+ if (buf && buf->read_pkt < buf->num_pkt)
+ return &buf->pkt[buf->read_pkt++];
+ return NULL;
+}
+
+void sd_conv_def_reset(struct sd *sd)
+{
+ struct sd_conv_buffer *buf = sd->sd_conv_buffer;
+ if (buf) {
+ buf->read_pkt = buf->num_pkt = 0;
+ buf->cur_buffer = 0;
+ }
}
diff --git a/sub/dec_sub.h b/sub/dec_sub.h
index 593eac1e03..805a87ef5c 100644
--- a/sub/dec_sub.h
+++ b/sub/dec_sub.h
@@ -9,26 +9,36 @@
struct sh_sub;
struct ass_track;
struct MPOpts;
+struct demux_packet;
+struct ass_library;
+struct ass_renderer;
-bool is_text_sub(const char *t);
-bool is_ass_sub(const char *t);
-bool is_dvd_sub(const char *t);
+struct dec_sub;
+struct sd;
-void sub_decode(struct sh_sub *sh, struct osd_state *osd, void *data,
- int data_len, double pts, double duration);
-void sub_get_bitmaps(struct osd_state *osd, struct mp_osd_res dim, double pts,
+struct dec_sub *sub_create(struct MPOpts *opts);
+void sub_destroy(struct dec_sub *sub);
+
+void sub_set_video_res(struct dec_sub *sub, int w, int h);
+void sub_set_extradata(struct dec_sub *sub, void *data, int data_len);
+void sub_set_ass_renderer(struct dec_sub *sub, struct ass_library *ass_library,
+ struct ass_renderer *ass_renderer);
+void sub_init_from_sh(struct dec_sub *sub, struct sh_sub *sh);
+
+bool sub_is_initialized(struct dec_sub *sub);
+
+bool sub_accept_packets_in_advance(struct dec_sub *sub);
+void sub_decode(struct dec_sub *sub, struct demux_packet *packet);
+void sub_get_bitmaps(struct dec_sub *sub, struct mp_osd_res dim, double pts,
struct sub_bitmaps *res);
-void sub_init(struct sh_sub *sh, struct osd_state *osd);
-void sub_reset(struct sh_sub *sh, struct osd_state *osd);
-void sub_switchoff(struct sh_sub *sh, struct osd_state *osd);
-void sub_uninit(struct sh_sub *sh);
+bool sub_has_get_text(struct dec_sub *sub);
+char *sub_get_text(struct dec_sub *sub, double pts);
+void sub_reset(struct dec_sub *sub);
-struct sh_sub *sd_ass_create_from_track(struct ass_track *track,
- bool vsfilter_aspect,
- struct MPOpts *opts);
+struct sd *sub_get_last_sd(struct dec_sub *sub);
#ifdef CONFIG_ASS
-struct ass_track *sub_get_ass_track(struct osd_state *osd);
+struct ass_track *sub_get_ass_track(struct dec_sub *sub);
#endif
#endif
diff --git a/sub/find_sub.c b/sub/find_sub.c
deleted file mode 100644
index 5feef2a3e9..0000000000
--- a/sub/find_sub.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * .SUB
- *
- * 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.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-
-#include "sub.h"
-#include "subreader.h"
-
-#include "core/mp_msg.h"
-#include "core/mp_common.h"
-#include "core/mplayer.h"
-
-static int current_sub=0;
-
-//static subtitle* subtitles=NULL;
-static int nosub_range_start=-1;
-static int nosub_range_end=-1;
-static const sub_data *last_sub_data = NULL;
-
-void step_sub(sub_data *subd, float pts, int movement) {
- subtitle *subs;
- int key;
-
- if (subd == NULL) return;
- subs = subd->subtitles;
- key = (pts+sub_delay) * (subd->sub_uses_time ? 100 : sub_fps);
-
- /* Tell the OSD subsystem that the OSD contents will change soon */
- vo_osd_changed(OSDTYPE_SUBTITLE);
-
- /* If we are moving forward, don't count the next (current) subtitle
- * if we haven't displayed it yet. Same when moving other direction.
- */
- if (movement > 0 && key < subs[current_sub].start)
- movement--;
- if (movement < 0 && key >= subs[current_sub].end)
- movement++;
-
- /* Never move beyond first or last subtitle. */
- if (current_sub+movement < 0)
- movement = 0-current_sub;
- if (current_sub+movement >= subd->sub_num)
- movement = subd->sub_num - current_sub - 1;
-
- current_sub += movement;
- sub_delay = subs[current_sub].start / (subd->sub_uses_time ? 100 : sub_fps) - pts;
-}
-
-void find_sub(struct MPContext *mpctx, sub_data* subd,int key){
- subtitle *subs;
- subtitle *new_sub = NULL;
- int i,j;
-
- if ( !subd || subd->sub_num == 0) return;
- subs = subd->subtitles;
-
- if (last_sub_data != subd) {
- // Sub data changed, reset nosub range.
- last_sub_data = subd;
- nosub_range_start = -1;
- nosub_range_end = -1;
- }
-
- if(vo_sub){
- if(key>=vo_sub->start && key<=vo_sub->end) return; // OK!
- } else {
- if(key>nosub_range_start && key<nosub_range_end) return; // OK!
- }
- // sub changed!
-
- /* Tell the OSD subsystem that the OSD contents will change soon */
- vo_osd_changed(OSDTYPE_SUBTITLE);
-
- if(key<=0){
- // no sub here
- goto update;
- }
-
-// printf("\r---- sub changed ----\n");
-
- // check next sub.
- if(current_sub>=0 && current_sub+1 < subd->sub_num){
- if(key>subs[current_sub].end && key<subs[current_sub+1].start){
- // no sub
- nosub_range_start=subs[current_sub].end;
- nosub_range_end=subs[current_sub+1].start;
- goto update;
- }
- // next sub?
- ++current_sub;
- new_sub=&subs[current_sub];
- if(key>=new_sub->start && key<=new_sub->end) goto update; // OK!
- }
-
-// printf("\r---- sub log search... ----\n");
-
- // use logarithmic search:
- i=0;
- j = subd->sub_num - 1;
-// printf("Searching %d in %d..%d\n",key,subs[i].start,subs[j].end);
- while(j>=i){
- current_sub=(i+j+1)/2;
- new_sub=&subs[current_sub];
- if(key<new_sub->start) j=current_sub-1;
- else if(key>new_sub->end) i=current_sub+1;
- else goto update; // found!
- }
-// if(key>=new_sub->start && key<=new_sub->end) return; // OK!
-
- // check where are we...
- if(key<new_sub->start){
- if(current_sub<=0){
- // before the first sub
- nosub_range_start=key-1; // tricky
- nosub_range_end=new_sub->start;
-// printf("FIRST... key=%d end=%d \n",key,new_sub->start);
- new_sub=NULL;
- goto update;
- }
- --current_sub;
- if(key>subs[current_sub].end && key<subs[current_sub+1].start){
- // no sub
- nosub_range_start=subs[current_sub].end;
- nosub_range_end=subs[current_sub+1].start;
-// printf("No sub... 1 \n");
- new_sub=NULL;
- goto update;
- }
- printf("HEH???? ");
- } else {
- if(key<=new_sub->end) printf("JAJJ! "); else
- if(current_sub+1 >= subd->sub_num){
- // at the end?
- nosub_range_start=new_sub->end;
- nosub_range_end=0x7FFFFFFF; // MAXINT
-// printf("END!?\n");
- new_sub=NULL;
- goto update;
- } else
- if(key>subs[current_sub].end && key<subs[current_sub+1].start){
- // no sub
- nosub_range_start=subs[current_sub].end;
- nosub_range_end=subs[current_sub+1].start;
-// printf("No sub... 2 \n");
- new_sub=NULL;
- goto update;
- }
- }
-
- mp_msg(MSGT_FIXME,MSGL_FIXME,"SUB ERROR: %d ? %d --- %d [%d] \n",key,(int)new_sub->start,(int)new_sub->end,current_sub);
-
- new_sub=NULL; // no sub here
-update:
- set_osd_subtitle(mpctx, new_sub);
-}
diff --git a/sub/find_subfiles.c b/sub/find_subfiles.c
index e77015114b..3519e5c386 100644
--- a/sub/find_subfiles.c
+++ b/sub/find_subfiles.c
@@ -12,7 +12,6 @@
#include "core/mp_common.h"
#include "sub/find_subfiles.h"
#include "sub/sub.h"
-#include "sub/subreader.h"
static struct bstr strip_ext(struct bstr str)
{
@@ -119,9 +118,9 @@ static void append_dir_subtitles(struct MPOpts *opts,
// does it end with a subtitle extension?
#ifdef CONFIG_ICONV
#ifdef CONFIG_ENCA
- int i = (sub_cp && strncasecmp(sub_cp, "enca", 4) != 0) ? 3 : 0;
+ int i = (opts->sub_cp && strncasecmp(opts->sub_cp, "enca", 4) != 0) ? 3 : 0;
#else
- int i = sub_cp ? 3 : 0;
+ int i = opts->sub_cp ? 3 : 0;
#endif
#else
int i = 0;
@@ -153,12 +152,12 @@ static void append_dir_subtitles(struct MPOpts *opts,
if (!prio && bstrcmp(tmp_fname_trim, f_fname_trim) == 0)
prio = 3; // matches the movie name
if (!prio && bstr_find(tmp_fname_trim, f_fname_trim) >= 0
- && sub_match_fuzziness >= 1)
+ && opts->sub_match_fuzziness >= 1)
prio = 2;