summaryrefslogtreecommitdiffstats
path: root/sub
diff options
context:
space:
mode:
Diffstat (limited to 'sub')
-rw-r--r--sub/ass_mp.c5
-rw-r--r--sub/dec_sub.c25
-rw-r--r--sub/dec_sub.h7
-rw-r--r--sub/draw_bmp.c6
-rw-r--r--sub/osd_font.otfbin0 -> 2276 bytes
-rw-r--r--sub/osd_font.pfbbin8322 -> 0 bytes
-rw-r--r--sub/osd_libass.c246
-rw-r--r--sub/sd.h1
-rw-r--r--sub/sd_ass.c17
-rw-r--r--sub/sd_lavc.c35
-rw-r--r--sub/sub.c1
-rw-r--r--sub/sub.h10
-rw-r--r--sub/subassconvert.c197
-rw-r--r--sub/subreader.c13
-rw-r--r--sub/subreader.h1
15 files changed, 439 insertions, 125 deletions
diff --git a/sub/ass_mp.c b/sub/ass_mp.c
index 2312eaeff5..497e307953 100644
--- a/sub/ass_mp.c
+++ b/sub/ass_mp.c
@@ -69,6 +69,9 @@ void mp_ass_set_style(ASS_Style *style, struct osd_style_opts *opts)
style->MarginV = opts->margin_y * scale;
style->ScaleX = 1.;
style->ScaleY = 1.;
+#if LIBASS_VERSION >= 0x01020000
+ style->Blur = opts->blur;
+#endif
}
ASS_Track *mp_ass_default_track(ASS_Library *library, struct MPOpts *opts)
@@ -267,7 +270,9 @@ void mp_ass_configure_fonts(ASS_Renderer *priv, struct osd_style_opts *opts)
default_font = NULL;
}
+ mp_msg(MSGT_ASS, MSGL_V, "[ass] Setting up fonts...\n");
ass_set_fonts(priv, default_font, opts->font, 1, config, 1);
+ mp_msg(MSGT_ASS, MSGL_V, "[ass] Done.\n");
talloc_free(default_font);
talloc_free(config);
diff --git a/sub/dec_sub.c b/sub/dec_sub.c
index 4e703e7dc0..d3cedea80d 100644
--- a/sub/dec_sub.c
+++ b/sub/dec_sub.c
@@ -30,17 +30,36 @@
extern const struct sd_functions sd_ass;
extern const struct sd_functions sd_lavc;
+bool is_text_sub(const char *t)
+{
+ return t && (is_ass_sub(t) ||
+ strcmp(t, "text") == 0 ||
+ strcmp(t, "subrip") == 0 ||
+ strcmp(t, "mov_text") == 0);
+}
+
+bool is_ass_sub(const char *t)
+{
+ return t && (strcmp(t, "ass") == 0 ||
+ strcmp(t, "ssa") == 0);
+}
+
+bool is_dvd_sub(const char *t)
+{
+ return t && strcmp(t, "dvd_subtitle") == 0;
+}
+
void sub_init(struct sh_sub *sh, struct osd_state *osd)
{
struct MPOpts *opts = sh->opts;
assert(!osd->sh_sub);
+ if (sd_lavc.probe(sh))
+ sh->sd_driver = &sd_lavc;
#ifdef CONFIG_ASS
- if (opts->ass_enabled && is_text_sub(sh->type))
+ if (opts->ass_enabled && sd_ass.probe(sh))
sh->sd_driver = &sd_ass;
#endif
- if (strchr("bpxv", sh->type))
- sh->sd_driver = &sd_lavc;
if (sh->sd_driver) {
if (sh->sd_driver->init(sh, osd) < 0)
return;
diff --git a/sub/dec_sub.h b/sub/dec_sub.h
index f66f05c021..593eac1e03 100644
--- a/sub/dec_sub.h
+++ b/sub/dec_sub.h
@@ -10,10 +10,9 @@ struct sh_sub;
struct ass_track;
struct MPOpts;
-static inline bool is_text_sub(int type)
-{
- return type == 't' || type == 'm' || type == 'a';
-}
+bool is_text_sub(const char *t);
+bool is_ass_sub(const char *t);
+bool is_dvd_sub(const char *t);
void sub_decode(struct sh_sub *sh, struct osd_state *osd, void *data,
int data_len, double pts, double duration);
diff --git a/sub/draw_bmp.c b/sub/draw_bmp.c
index 09068dba89..4057500f01 100644
--- a/sub/draw_bmp.c
+++ b/sub/draw_bmp.c
@@ -287,8 +287,10 @@ static void draw_ass(struct mp_draw_sub_cache *cache, struct mp_rect bb,
cspar.int_bits_out = 8;
float yuv2rgb[3][4], rgb2yuv[3][4];
- mp_get_yuv2rgb_coeffs(&cspar, yuv2rgb);
- mp_invert_yuv2rgb(rgb2yuv, yuv2rgb);
+ if (temp->flags & MP_IMGFLAG_YUV) {
+ mp_get_yuv2rgb_coeffs(&cspar, yuv2rgb);
+ mp_invert_yuv2rgb(rgb2yuv, yuv2rgb);
+ }
for (int i = 0; i < sbs->num_parts; ++i) {
struct sub_bitmap *sb = &sbs->parts[i];
diff --git a/sub/osd_font.otf b/sub/osd_font.otf
new file mode 100644
index 0000000000..d8ebec0ad8
--- /dev/null
+++ b/sub/osd_font.otf
Binary files differ
diff --git a/sub/osd_font.pfb b/sub/osd_font.pfb
deleted file mode 100644
index a4a65a143b..0000000000
--- a/sub/osd_font.pfb
+++ /dev/null
Binary files differ
diff --git a/sub/osd_libass.c b/sub/osd_libass.c
index bbd925f135..495bce2b73 100644
--- a/sub/osd_libass.c
+++ b/sub/osd_libass.c
@@ -54,6 +54,12 @@ void osd_init_backend(struct osd_state *osd)
void osd_destroy_backend(struct osd_state *osd)
{
+ for (int n = 0; n < MAX_OSD_PARTS; n++) {
+ struct osd_object *obj = osd->objs[n];
+ if (obj->osd_track)
+ ass_free_track(obj->osd_track);
+ obj->osd_track = NULL;
+ }
if (osd->osd_render)
ass_renderer_done(osd->osd_render);
osd->osd_render = NULL;
@@ -61,14 +67,19 @@ void osd_destroy_backend(struct osd_state *osd)
osd->osd_ass_library = NULL;
}
-static ASS_Track *create_osd_ass_track(struct osd_state *osd)
+static void create_osd_ass_track(struct osd_state *osd, struct osd_object *obj)
{
- ASS_Track *track = ass_new_track(osd->osd_ass_library);
+ ASS_Track *track = obj->osd_track;
+ if (!track)
+ track = ass_new_track(osd->osd_ass_library);
+
+ double aspect = 1.0 * obj->vo_res.w / FFMAX(obj->vo_res.h, 1) /
+ obj->vo_res.display_par;
track->track_type = TRACK_TYPE_ASS;
track->Timer = 100.;
track->PlayResY = MP_ASS_FONT_PLAYRESY;
- track->PlayResX = track->PlayResY * 1.33333;
+ track->PlayResX = track->PlayResY * aspect;
track->WrapStyle = 1; // end-of-line wrapping instead of smart wrapping
if (track->n_styles == 0) {
@@ -83,18 +94,19 @@ static ASS_Track *create_osd_ass_track(struct osd_state *osd)
style->Encoding = -1;
}
- return track;
+ obj->osd_track = track;
}
-static ASS_Event *get_osd_ass_event(ASS_Track *track)
+static ASS_Event *add_osd_ass_event(ASS_Track *track, const char *text)
{
- ass_flush_events(track);
- ass_alloc_event(track);
- ASS_Event *event = track->events + 0;
+ int n = ass_alloc_event(track);
+ ASS_Event *event = track->events + n;
event->Start = 0;
event->Duration = 100;
event->Style = track->default_style;
assert(event->Text == NULL);
+ if (text)
+ event->Text = strdup(text);
return event;
}
@@ -135,67 +147,135 @@ static char *mangle_ass(const char *in)
static void update_osd(struct osd_state *osd, struct osd_object *obj)
{
- if (!osd->osd_text[0]) {
- clear_obj(obj);
+ create_osd_ass_track(osd, obj);
+ clear_obj(obj);
+ if (!osd->osd_text[0])
return;
- }
- if (!obj->osd_track)
- obj->osd_track = create_osd_ass_track(osd);
- ASS_Event *event = get_osd_ass_event(obj->osd_track);
char *text = mangle_ass(osd->osd_text);
- event->Text = strdup(text);
+ add_osd_ass_event(obj->osd_track, text);
talloc_free(text);
}
-static int get_align(float val, int res, int *out_margin)
+// align: -1 .. +1
+// frame: size of the containing area
+// obj: size of the object that should be positioned inside the area
+// margin: min. distance from object to frame (as long as -1 <= align <= +1)
+static float get_align(float align, float frame, float obj, float margin)
{
- *out_margin = FFMAX(0, (1.0 - fabs(val)) * res / 2);
- if (fabs(val) < 0.1)
- return 1; // centered
- return val > 0 ? 2 : 0; // bottom / top (or right / left)
+ frame -= margin * 2;
+ return margin + frame / 2 - obj / 2 + (frame - obj) / 2 * align;
}
-static const int ass_align_x[3] = {1, 2, 3};
-static const int ass_align_y[3] = {4, 8, 0};
+struct ass_draw {
+ int scale;
+ char *text;
+};
+
+static void ass_draw_start(struct ass_draw *d)
+{
+ d->scale = FFMAX(d->scale, 1);
+ d->text = talloc_asprintf_append(d->text, "{\\p%d}", d->scale);
+}
-#define OSDBAR_ELEMS 46
+static void ass_draw_stop(struct ass_draw *d)
+{
+ d->text = talloc_strdup_append(d->text, "{\\p0}");
+}
-static void update_progbar(struct osd_state *osd, struct osd_object *obj)
+static void ass_draw_c(struct ass_draw *d, float x, float y)
+{
+ int ix = round(x * (1 << (d->scale - 1)));
+ int iy = round(y * (1 << (d->scale - 1)));
+ d->text = talloc_asprintf_append(d->text, " %d %d", ix, iy);
+}
+
+static void ass_draw_append(struct ass_draw *d, const char *t)
+{
+ d->text = talloc_strdup_append(d->text, t);
+}
+
+static void ass_draw_move_to(struct ass_draw *d, float x, float y)
+{
+ ass_draw_append(d, " m");
+ ass_draw_c(d, x, y);
+}
+
+static void ass_draw_line_to(struct ass_draw *d, float x, float y)
+{
+ ass_draw_append(d, " l");
+ ass_draw_c(d, x, y);
+}
+
+static void ass_draw_rect_ccw(struct ass_draw *d, float x0, float y0,
+ float x1, float y1)
+{
+ ass_draw_move_to(d, x0, y0);
+ ass_draw_line_to(d, x0, y1);
+ ass_draw_line_to(d, x1, y1);
+ ass_draw_line_to(d, x1, y0);
+}
+
+static void ass_draw_rect_cw(struct ass_draw *d, float x0, float y0,
+ float x1, float y1)
+{
+ ass_draw_move_to(d, x0, y0);
+ ass_draw_line_to(d, x1, y0);
+ ass_draw_line_to(d, x1, y1);
+ ass_draw_line_to(d, x0, y1);
+}
+
+static void ass_draw_reset(struct ass_draw *d)
+{
+ talloc_free(d->text);
+ d->text = NULL;
+}
+
+static void get_osd_bar_box(struct osd_state *osd, struct osd_object *obj,
+ float *o_x, float *o_y, float *o_w, float *o_h,
+ float *o_border)
{
struct MPOpts *opts = osd->opts;
- if (osd->progbar_type < 0) {
- clear_obj(obj);
- return;
+ bool new_track = !obj->osd_track;
+ create_osd_ass_track(osd, obj);
+ ASS_Track *track = obj->osd_track;
+ ASS_Style *style = track->styles + track->default_style;
+
+ *o_w = track->PlayResX * (opts->osd_bar_w / 100.0);
+ *o_h = track->PlayResY * (opts->osd_bar_h / 100.0);
+
+ if (new_track) {
+ float base_size = 0.03125;
+ style->Outline *= *o_h / track->PlayResY / base_size;
+ // So that the chapter marks have space between them
+ style->Outline = FFMIN(style->Outline, *o_h / 5.2);
+ // So that the border is not 0
+ style->Outline = FFMAX(style->Outline, *o_h / 32.0);
+ // Rendering with shadow is broken (because there's more than one shape)
+ style->Shadow = 0;
}
- if (!obj->osd_track)
- obj->osd_track = create_osd_ass_track(osd);
+ *o_border = style->Outline;
- ASS_Style *style = obj->osd_track->styles + obj->osd_track->default_style;
+ *o_x = get_align(opts->osd_bar_align_x, track->PlayResX, *o_w, *o_border);
+ *o_y = get_align(opts->osd_bar_align_y, track->PlayResY, *o_h, *o_border);
+}
+
+static void update_progbar(struct osd_state *osd, struct osd_object *obj)
+{
+ float px, py, width, height, border;
+ get_osd_bar_box(osd, obj, &px, &py, &width, &height, &border);
- int ax = get_align(opts->osd_bar_align_x, obj->osd_track->PlayResX,
- &style->MarginR);
- int ay = get_align(opts->osd_bar_align_y, obj->osd_track->PlayResY,
- &style->MarginV);
- style->Alignment = ass_align_x[ax] + ass_align_y[ay];
- style->MarginL = style->MarginR;
+ clear_obj(obj);
- // We need a fixed font size with respect to the OSD width.
- // Assume the OSD bar takes 2/3 of the OSD width at PlayResY=288 and
- // FontSize=22 with an OSD aspect ratio of 16:9. Rescale as needed.
- // xxx can fail when unknown fonts are involved
- double asp = (double)obj->vo_res.w / obj->vo_res.h;
- double scale = (asp / 1.77777) * (obj->osd_track->PlayResY / 288.0);
- style->ScaleX = style->ScaleY = scale;
- style->FontSize = 22.0;
- style->Outline = style->FontSize / 16 * scale;
+ if (osd->progbar_type < 0)
+ return;
- int active = (osd->progbar_value * OSDBAR_ELEMS + 255) / 256;
- active = FFMIN(OSDBAR_ELEMS, FFMAX(active, 0));
+ float sx = px - border * 2 - height / 4; // includes additional spacing
+ float sy = py + height / 2;
- char *text = talloc_strdup(NULL, "{\\q2}");
+ char *text = talloc_asprintf(NULL, "{\\an6\\pos(%f,%f)}", sx, sy);
if (osd->progbar_type == 0 || osd->progbar_type >= 256) {
// no sym
@@ -207,30 +287,67 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj)
text = talloc_strdup_append_buffer(text, "{\\r}");
}
- //xxx space in normal font, because OSD font doesn't have a space
- text = talloc_strdup_append_buffer(text, "\\h");
- text = talloc_strdup_append_buffer(text, ASS_USE_OSD_FONT);
+ add_osd_ass_event(obj->osd_track, text);
+ talloc_free(text);
- text = mp_append_utf8_buffer(text, OSD_CODEPOINTS + OSD_PB_START);
- for (int n = 0; n < active; n++)
- text = mp_append_utf8_buffer(text, OSD_CODEPOINTS + OSD_PB_0);
- for (int n = 0; n < OSDBAR_ELEMS - active; n++)
- text = mp_append_utf8_buffer(text, OSD_CODEPOINTS + OSD_PB_1);
- text = mp_append_utf8_buffer(text, OSD_CODEPOINTS + OSD_PB_END);
+ struct ass_draw *d = &(struct ass_draw) { .scale = 4 };
+ // filled area
+ d->text = talloc_asprintf_append(d->text, "{\\bord0\\pos(%f,%f)}", px, py);
+ ass_draw_start(d);
+ float pos = osd->progbar_value * width - border / 2;
+ ass_draw_rect_cw(d, 0, 0, pos, height);
+ ass_draw_stop(d);
+ add_osd_ass_event(obj->osd_track, d->text);
+ ass_draw_reset(d);
+
+ // position marker
+ d->text = talloc_asprintf_append(d->text, "{\\bord%f\\pos(%f,%f)}",
+ border / 2, px, py);
+ ass_draw_start(d);
+ ass_draw_move_to(d, pos + border / 2, 0);
+ ass_draw_line_to(d, pos + border / 2, height);
+ ass_draw_stop(d);
+ add_osd_ass_event(obj->osd_track, d->text);
+ ass_draw_reset(d);
+
+ d->text = talloc_asprintf_append(d->text, "{\\pos(%f,%f)}", px, py);
+ ass_draw_start(d);
+
+ // the box
+ ass_draw_rect_cw(d, -border, -border, width + border, height + border);
+
+ // the "hole"
+ ass_draw_rect_ccw(d, 0, 0, width, height);
+
+ // chapter marks
+ for (int n = 0; n < osd->progbar_num_stops; n++) {
+ float s = osd->progbar_stops[n] * width;
+ float dent = border * 1.3;
+
+ if (s > dent && s < width - dent) {
+ ass_draw_move_to(d, s + dent, 0);
+ ass_draw_line_to(d, s, dent);
+ ass_draw_line_to(d, s - dent, 0);
+
+ ass_draw_move_to(d, s - dent, height);
+ ass_draw_line_to(d, s, height - dent);
+ ass_draw_line_to(d, s + dent, height);
+ }
+ }
- ASS_Event *event = get_osd_ass_event(obj->osd_track);
- event->Text = strdup(text);
- talloc_free(text);
+ ass_draw_stop(d);
+ add_osd_ass_event(obj->osd_track, d->text);
+ ass_draw_reset(d);
}
static void update_sub(struct osd_state *osd, struct osd_object *obj)
{
struct MPOpts *opts = osd->opts;
- if (!(vo_sub && opts->sub_visibility)) {
- clear_obj(obj);
+ clear_obj(obj);
+
+ if (!(vo_sub && opts->sub_visibility))
return;
- }
if (!obj->osd_track)
obj->osd_track = mp_ass_default_track(osd->osd_ass_library, osd->opts);
@@ -250,9 +367,8 @@ static void update_sub(struct osd_state *osd, struct osd_object *obj)
for (int n = 0; n < vo_sub->lines; n++)
text = talloc_asprintf_append_buffer(text, "%s\n", vo_sub->text[n]);
- ASS_Event *event = get_osd_ass_event(obj->osd_track);
char *escaped_text = mangle_ass(text);
- event->Text = strdup(escaped_text);
+ add_osd_ass_event(obj->osd_track, escaped_text);
talloc_free(escaped_text);
talloc_free(text);
}
diff --git a/sub/sd.h b/sub/sd.h
index 29f021ab5e..881c429689 100644
--- a/sub/sd.h
+++ b/sub/sd.h
@@ -4,6 +4,7 @@
#include "dec_sub.h"
struct sd_functions {
+ bool (*probe)(struct sh_sub *sh);
int (*init)(struct sh_sub *sh, struct osd_state *osd);
void (*decode)(struct sh_sub *sh, struct osd_state *osd,
void *data, int data_len, double pts, double duration);
diff --git a/sub/sd_ass.c b/sub/sd_ass.c
index 00f2f8d796..8d17835809 100644
--- a/sub/sd_ass.c
+++ b/sub/sd_ass.c
@@ -41,6 +41,11 @@ struct sd_ass_priv {
bool flush_on_seek;
};
+static bool probe(struct sh_sub *sh)
+{
+ return is_text_sub(sh->gsh->codec);
+}
+
static void free_last_event(ASS_Track *track)
{
assert(track->n_events > 0);
@@ -51,13 +56,14 @@ static void free_last_event(ASS_Track *track)
static int init(struct sh_sub *sh, struct osd_state *osd)
{
struct sd_ass_priv *ctx;
+ bool ass = is_ass_sub(sh->gsh->codec);
if (sh->initialized) {
ctx = sh->context;
} else {
ctx = talloc_zero(NULL, struct sd_ass_priv);
sh->context = ctx;
- if (sh->type == 'a') {
+ if (ass) {
ctx->ass_track = ass_new_track(osd->ass_library);
if (sh->extradata)
ass_process_codec_private(ctx->ass_track, sh->extradata,
@@ -66,7 +72,7 @@ static int init(struct sh_sub *sh, struct osd_state *osd)
ctx->ass_track = mp_ass_default_track(osd->ass_library, sh->opts);
}
- ctx->vsfilter_aspect = sh->type == 'a';
+ ctx->vsfilter_aspect = ass;
return 0;
}
@@ -77,7 +83,7 @@ static void decode(struct sh_sub *sh, struct osd_state *osd, void *data,
struct sd_ass_priv *ctx = sh->context;
ASS_Track *track = ctx->ass_track;
- if (sh->type == 'a') { // ssa/ass subs
+ if (is_ass_sub(sh->gsh->codec)) {
if (bstr_startswith0((bstr){data, data_len}, "Dialogue: ")) {
// broken ffmpeg ASS packet format
ctx->flush_on_seek = true;
@@ -177,6 +183,7 @@ static void uninit(struct sh_sub *sh)
}
const struct sd_functions sd_ass = {
+ .probe = probe,
.init = init,
.decode = decode,
.get_bitmaps = get_bitmaps,
@@ -199,7 +206,9 @@ struct sh_sub *sd_ass_create_from_track(struct ass_track *track,
talloc_set_destructor(sh, sd_ass_track_destructor);
*sh = (struct sh_sub) {
.opts = opts,
- .type = 'a',
+ .gsh = talloc_struct(sh, struct sh_stream, {
+ .codec = "ass",
+ }),
.sd_driver = &sd_ass,
.context = talloc_struct(sh, struct sd_ass_priv, {
.ass_track = track,
diff --git a/sub/sd_lavc.c b/sub/sd_lavc.c
index f1f93b480e..1665e36749 100644
--- a/sub/sd_lavc.c
+++ b/sub/sd_lavc.c
@@ -22,6 +22,7 @@
#include "talloc.h"
#include "core/mp_msg.h"
+#include "core/av_common.h"
#include "demux/stheader.h"
#include "sd.h"
#include "dec_sub.h"
@@ -40,9 +41,24 @@ struct sd_lavc_priv {
double endpts;
};
-static void guess_resolution(char type, int *w, int *h)
+static bool probe(struct sh_sub *sh)
{
- if (type == 'v') {
+ enum AVCodecID cid = mp_codec_to_av_codec_id(sh->gsh->codec);
+ // Supported codecs must be known to decode to paletted bitmaps
+ switch (cid) {
+ case AV_CODEC_ID_DVB_SUBTITLE:
+ case AV_CODEC_ID_HDMV_PGS_SUBTITLE:
+ case AV_CODEC_ID_XSUB:
+ case AV_CODEC_ID_DVD_SUBTITLE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void guess_resolution(enum AVCodecID type, int *w, int *h)
+{
+ if (type == AV_CODEC_ID_DVD_SUBTITLE) {
/* XXX Although the video frame is some size, the SPU frame is
always maximum size i.e. 720 wide and 576 or 480 high */
// For HD files in MKV the VobSub resolution can be higher though,
@@ -65,17 +81,7 @@ static int init(struct sh_sub *sh, struct osd_state *osd)
if (sh->initialized)
return 0;
struct sd_lavc_priv *priv = talloc_zero(NULL, struct sd_lavc_priv);
- enum CodecID cid = CODEC_ID_NONE;
- switch (sh->type) {
- case 'b':
- cid = CODEC_ID_DVB_SUBTITLE; break;
- case 'p':
- cid = CODEC_ID_HDMV_PGS_SUBTITLE; break;
- case 'x':
- cid = CODEC_ID_XSUB; break;
- case 'v':
- cid = CODEC_ID_DVD_SUBTITLE; break;
- }
+ enum AVCodecID cid = mp_codec_to_av_codec_id(sh->gsh->codec);
AVCodecContext *ctx = NULL;
AVCodec *sub_codec = avcodec_find_decoder(cid);
if (!sub_codec)
@@ -194,7 +200,7 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd,
talloc_get_size(priv->inbitmaps));
int inw = priv->avctx->width;
int inh = priv->avctx->height;
- guess_resolution(sh->type, &inw, &inh);
+ guess_resolution(priv->avctx->codec_id, &inw, &inh);
double xscale = (double) (d.w - d.ml - d.mr) / inw;
double yscale = (double) (d.h - d.mt - d.mb) / inh;
for (int i = 0; i < priv->count; i++) {
@@ -235,6 +241,7 @@ static void uninit(struct sh_sub *sh)
}
const struct sd_functions sd_lavc = {
+ .probe = probe,
.init = init,
.decode = decode,
.get_bitmaps = get_bitmaps,
diff --git a/sub/sub.c b/sub/sub.c
index b0c9e22d7a..e9496f7853 100644
--- a/sub/sub.c
+++ b/sub/sub.c
@@ -79,6 +79,7 @@ const struct m_sub_options osd_style_conf = {
OPT_FLOATRANGE("spacing", spacing, 0, -10, 10),
OPT_INTRANGE("margin-x", margin_x, 0, 0, 300),
OPT_INTRANGE("margin-y", margin_y, 0, 0, 600),
+ OPT_FLOATRANGE("blur", blur, 0, 0, 20),
{0}
},
.size = sizeof(struct osd_style_opts),
diff --git a/sub/sub.h b/sub/sub.h
index 2055799d72..f062b3dddf 100644
--- a/sub/sub.h
+++ b/sub/sub.h
@@ -129,8 +129,13 @@ struct osd_state {
bool want_redraw;
- char *osd_text; // OSDTYPE_OSD
- int progbar_type, progbar_value; // OSDTYPE_PROGBAR
+ // OSDTYPE_OSD
+ char *osd_text;
+ // OSDTYPE_PROGBAR
+ int progbar_type; // <0: disabled, 1-255: symbol, else: no symbol
+ float progbar_value; // range 0.0-1.0
+ float *progbar_stops; // used for chapter indicators (0.0-1.0 each)
+ int progbar_num_stops;
int switch_sub_id;
@@ -187,6 +192,7 @@ struct osd_style_opts {
float spacing;
int margin_x;
int margin_y;
+ float blur;
};
extern const struct m_sub_options osd_style_conf;
diff --git a/sub/subassconvert.c b/sub/subassconvert.c
index 1d05096c15..c665750682 100644
--- a/sub/subassconvert.c
+++ b/sub/subassconvert.c
@@ -55,6 +55,11 @@ static void append_text(struct line *dst, char *fmt, ...)
va_end(va);
}
+static void append_text_n(struct line *dst, char *start, size_t length)
+{
+ append_text(dst, "%.*s", (int)length, start);
+}
+
static int indexof(const char *s, int c)
{
char *f = strchr(s, c);
@@ -88,7 +93,7 @@ static const struct tag_conv {
{"<b>", "{\\b1}"}, {"</b>", "{\\b0}"},
{"<u>", "{\\u1}"}, {"</u>", "{\\u0}"},
{"<s>", "{\\s1}"}, {"</s>", "{\\s0}"},
- {"{", "\\{"}, {"}", "\\}"},
+ {"}", "\\}"},
{"\r\n", "\\N"}, {"\n", "\\N"}, {"\r", "\\N"},
};
@@ -96,29 +101,155 @@ static const struct {
char *s;
uint32_t v;
} subrip_web_colors[] = {
- /* Named CSS3 colors in BGR format; a subset of those
+ /* Named CSS3 colors in RGB format; a subset of those
at http://www.w3.org/TR/css3-color/#svg-color */
- {"aqua", 0xffff00},
- {"black", 0x000000},
- {"blue", 0xff0000},
- {"cyan", 0xffff00},
- {"fuchsia", 0xff00ff},
- {"gray", 0x808080},
- {"green", 0x008000},
- {"grey", 0x808080},
- {"lime", 0x00ff00},
- {"magenta", 0xff00ff},
- {"maroon", 0x000080},
- {"navy", 0x800000},
- {"olive", 0x008080},
- {"orange", 0x00a5ff},
- {"pink", 0xcbc0ff},
- {"purple", 0x800080},
- {"red", 0x0000ff},
- {"silver", 0xc0c0c0},
- {"teal", 0x808000},
- {"white", 0xffffff},
- {"yellow", 0x00ffff},
+ {"aliceblue", 0xF0F8FF},
+ {"antiquewhite", 0xFAEBD7},
+ {"aqua", 0x00FFFF},
+ {"aquamarine", 0x7FFFD4},
+ {"azure", 0xF0FFFF},
+ {"beige", 0xF5F5DC},
+ {"bisque", 0xFFE4C4},
+ {"black", 0x000000},
+ {"blanchedalmond", 0xFFEBCD},
+ {"blue", 0x0000FF},
+ {"blueviolet", 0x8A2BE2},
+ {"brown", 0xA52A2A},
+ {"burlywood", 0xDEB887},
+ {"cadetblue", 0x5F9EA0},
+ {"chartreuse", 0x7FFF00},
+ {"chocolate", 0xD2691E},
+ {"coral", 0xFF7F50},
+ {"cornflowerblue", 0x6495ED},
+ {"cornsilk", 0xFFF8DC},
+ {"crimson", 0xDC143C},
+ {"cyan", 0x00FFFF},
+ {"darkblue", 0x00008B},
+ {"darkcyan", 0x008B8B},
+ {"darkgoldenrod", 0xB8860B},
+ {"darkgray", 0xA9A9A9},
+ {"darkgreen", 0x006400},
+ {"darkgrey", 0xA9A9A9},
+ {"darkkhaki", 0xBDB76B},
+ {"darkmagenta", 0x8B008B},
+ {"darkolivegreen", 0x556B2F},
+ {"darkorange", 0xFF8C00},
+ {"darkorchid", 0x9932CC},
+ {"darkred", 0x8B0000},
+ {"darksalmon", 0xE9967A},
+ {"darkseagreen", 0x8FBC8F},
+ {"darkslateblue", 0x483D8B},
+ {"darkslategray", 0x2F4F4F},
+ {"darkslategrey", 0x2F4F4F},
+ {"darkturquoise", 0x00CED1},
+ {"darkviolet", 0x9400D3},
+ {"deeppink", 0xFF1493},
+ {"deepskyblue", 0x00BFFF},
+ {"dimgray", 0x696969},
+ {"dimgrey", 0x696969},
+ {"dodgerblue", 0x1E90FF},
+ {"firebrick", 0xB22222},
+ {"floralwhite", 0xFFFAF0},
+ {"forestgreen", 0x228B22},
+ {"fuchsia", 0xFF00FF},
+ {"gainsboro", 0xDCDCDC},
+ {"ghostwhite", 0xF8F8FF},
+ {"gold", 0xFFD700},
+ {"goldenrod", 0xDAA520},
+ {"gray", 0x808080},
+ {"green", 0x008000},
+ {"greenyellow", 0xADFF2F},
+ {"grey", 0x808080},
+ {"honeydew", 0xF0FFF0},
+ {"hotpink", 0xFF69B4},
+ {"indianred", 0xCD5C5C},
+ {"indigo", 0x4B0082},
+ {"ivory", 0xFFFFF0},
+ {"khaki", 0xF0E68C},
+ {"lavender", 0xE6E6FA},
+ {"lavenderblush", 0xFFF0F5},
+ {"lawngreen", 0x7CFC00},
+ {"lemonchiffon", 0xFFFACD},
+ {"lightblue", 0xADD8E6},
+ {"lightcoral", 0xF08080},
+ {"lightcyan", 0xE0FFFF},
+ {"lightgoldenrodyellow", 0xFAFAD2},
+ {"lightgray", 0xD3D3D3},
+ {"lightgreen", 0x90EE90},
+ {"lightgrey", 0xD3D3D3},
+ {"lightpink", 0xFFB6C1},
+ {"lightsalmon", 0xFFA07A},
+ {"lightseagreen", 0x20B2AA},
+ {"lightskyblue", 0x87CEFA},
+ {"lightslategray", 0x778899},
+ {"lightslategrey", 0x778899},
+ {"lightsteelblue", 0xB0C4DE},
+ {"lightyellow", 0xFFFFE0},
+ {"lime", 0x00FF00},
+ {"limegreen", 0x32CD32},
+ {"linen", 0xFAF0E6},
+ {"magenta", 0xFF00FF},
+ {"maroon", 0x800000},
+ {"mediumaquamarine", 0x66CDAA},
+ {"mediumblue", 0x0000CD},
+ {"mediumorchid", 0xBA55D3},
+ {"mediumpurple", 0x9370DB},
+ {"mediumseagreen", 0x3CB371},
+ {"mediumslateblue", 0x7B68EE},
+ {"mediumspringgreen", 0x00FA9A},
+ {"mediumturquoise", 0x48D1CC},
+ {"mediumvioletred", 0xC71585},
+ {"midnightblue", 0x191970},
+ {"mintcream", 0xF5FFFA},
+ {"mistyrose", 0xFFE4E1},
+ {"moccasin", 0xFFE4B5},
+ {"navajowhite", 0xFFDEAD},
+ {"navy", 0x000080},
+ {"oldlace", 0xFDF5E6},
+ {"olive", 0x808000},
+ {"olivedrab", 0x6B8E23},
+ {"orange", 0xFFA500},
+ {"orangered", 0xFF4500},
+ {"orchid", 0xDA70D6},
+ {"palegoldenrod", 0xEEE8AA},
+ {"palegreen", 0x98FB98},
+ {"paleturquoise", 0xAFEEEE},
+ {"palevioletred", 0xDB7093},
+ {"papayawhip", 0xFFEFD5},
+ {"peachpuff", 0xFFDAB9},
+ {"peru", 0xCD853F},
+ {"pink", 0xFFC0CB},
+ {"plum", 0xDDA0DD},
+ {"powderblue", 0xB0E0E6},
+ {"purple", 0x800080},
+ {"red", 0xFF0000},
+ {"rosybrown", 0xBC8F8F},
+ {"royalblue", 0x4169E1},
+ {"saddlebrown", 0x8B4513},
+ {"salmon", 0xFA8072},
+ {"sandybrown", 0xF4A460},
+ {"seagreen", 0x2E8B57},
+ {"seashell", 0xFFF5EE},
+ {"sienna", 0xA0522D},
+ {"silver", 0xC0C0C0},
+ {"skyblue", 0x87CEEB},
+ {"slateblue", 0x6A5ACD},
+ {"slategray", 0x708090},
+ {"slategrey", 0x708090},
+ {"snow", 0xFFFAFA},
+ {"springgreen", 0x00FF7F},
+ {"steelblue", 0x4682B4},
+ {"tan", 0xD2B48C},
+ {"teal", 0x008080},
+ {"thistle", 0xD8BFD8},
+ {"tomato", 0xFF6347},
+ {"turquoise", 0x40E0D0},
+ {"violet", 0xEE82EE},
+ {"wheat", 0xF5DEB3},
+ {"white", 0xFFFFFF},
+ {"whitesmoke", 0xF5F5F5},
+ {"yellow", 0xFFFF00},
+ {"yellowgreen", 0x9ACD32},
};
#define SUBRIP_MAX_STACKED_FONT_TAGS 16
@@ -238,7 +369,10 @@ void subassconvert_subrip(const char *orig, char *dest, int dest_buffer_size)
for (int i = 0; i < FF_ARRAY_ELEMS(subrip_web_colors); i++) {
char *color = subrip_web_colors[i].s;
if (bstrcasecmp(val, bstr0(color)) == 0) {
- tag->color = subrip_web_colors[i].v;
+ uint32_t color = subrip_web_colors[i].v;
+ tag->color = ((color & 0xff) << 16)
+ | (color & 0xff00)
+ | ((color & 0xff0000) >> 16);
found = 1;
}
}
@@ -264,7 +398,7 @@ void subassconvert_subrip(const char *orig, char *dest, int dest_buffer_size)
} else {
// We didn't find any matching color
mp_tmsg(MSGT_SUBREADER, MSGL_WARN,
- "SubRip: unknown font color in subtitle: %s\n",
+ "SubRip: unknown font color in subtitle: >%s<\n",
orig);
append_text(&new_line, "{\\c}");
}
@@ -288,6 +422,19 @@ void subassconvert_subrip(const char *orig, char *dest, int dest_buffer_size)
sp++;
line++;
}
+ } else if (*line == '{') {
+ char *end = strchr(line, '}');
+ if (line[1] == '\\' && end) {
+ // Likely ASS tag, pass them through
+ // Note that ASS tags like {something\an8} are legal too (i.e.
+ // the first character after '{' doesn't have to be '\'), but
+ // consider these fringe cases not worth supporting.
+ append_text_n(&new_line, line, end - line + 1);
+ line = end + 1;
+ } else {
+ append_text(&new_line, "\\{");
+ line++;
+ }
}
/* Tag conversion code didn't match */
diff --git a/sub/subreader.c b/sub/subreader.c
index bdcc79a64a..0f1b6c9bbd 100644
--- a/sub/