summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/en/options.rst11
-rw-r--r--core/cfg-mplayer.h2
-rw-r--r--core/defaultopts.c3
-rw-r--r--core/mplayer.c26
-rw-r--r--core/options.h2
-rw-r--r--sub/osd_libass.c230
-rw-r--r--sub/sub.h9
7 files changed, 212 insertions, 71 deletions
diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst
index 91078b2424..98019c0333 100644
--- a/DOCS/man/en/options.rst
+++ b/DOCS/man/en/options.rst
@@ -1315,12 +1315,19 @@
prefixes, see ``Input command prefixes``. If you want to disable the OSD
completely, use ``--osd-level=0``.
---osd-bar-align-x=<-1..1>
+--osd-bar-align-x=<-1-1>
Position of the OSD bar. -1 is far left, 0 is centered, 1 is far right.
---osd-bar-align-y=<-1..1>
+--osd-bar-align-y=<-1-1>
Position of the OSD bar. -1 is top, 0 is centered, 1 is bottom.
+--osd-bar-w=<1-100>
+ Width of the OSD bar, in percentage of the screen width (default: 75).
+ A value of 0.5 means the bar is half the screen wide.
+
+--osd-bar-h=<0.1-50>
+ Height of the OSD bar, in percentage of the screen height (default: 3.125).
+
--osd-back-color=<#RRGGBB>, --sub-text-back-color=<#RRGGBB>
See ``--osd-color``. Color used for OSD/sub text background.
diff --git a/core/cfg-mplayer.h b/core/cfg-mplayer.h
index 3b164a7346..5bae70ab0e 100644
--- a/core/cfg-mplayer.h
+++ b/core/cfg-mplayer.h
@@ -501,6 +501,8 @@ const m_option_t common_opts[] = {
OPT_FLAG("osd-bar", osd_bar_visible, 0),
OPT_FLOATRANGE("osd-bar-align-x", osd_bar_align_x, 0, -1.0, +1.0),
OPT_FLOATRANGE("osd-bar-align-y", osd_bar_align_y, 0, -1.0, +1.0),
+ OPT_FLOATRANGE("osd-bar-w", osd_bar_w, 0, 1, 100),
+ OPT_FLOATRANGE("osd-bar-h", osd_bar_h, 0, 0.1, 50),
OPT_SUBSTRUCT("osd", osd_style, osd_style_conf, 0),
OPT_SUBSTRUCT("sub-text", sub_text_style, osd_style_conf, 0),
{NULL, NULL, 0, 0, 0, 0, NULL}
diff --git a/core/defaultopts.c b/core/defaultopts.c
index 9f544d6d55..36170df725 100644
--- a/core/defaultopts.c
+++ b/core/defaultopts.c
@@ -43,6 +43,9 @@ void set_default_mplayer_options(struct MPOpts *opts)
.gamma_hue = 1000,
.osd_level = 1,
.osd_duration = 1000,
+ .osd_bar_align_y = 0.5,
+ .osd_bar_w = 75.0,
+ .osd_bar_h = 3.125,
.loop_times = -1,
.ordered_chapters = 1,
.chapter_merge_threshold = 100,
diff --git a/core/mplayer.c b/core/mplayer.c
index eccb40b7ec..b0563a7c2c 100644
--- a/core/mplayer.c
+++ b/core/mplayer.c
@@ -1330,7 +1330,8 @@ void set_osd_bar(struct MPContext *mpctx, int type, const char *name,
if (mpctx->sh_video && opts->term_osd != 1) {
mpctx->osd_visible = (GetTimerMS() + opts->osd_duration) | 1;
mpctx->osd->progbar_type = type;
- mpctx->osd->progbar_value = 256 * (val - min) / (max - min);
+ mpctx->osd->progbar_value = (val - min) / (max - min);
+ mpctx->osd->progbar_num_stops = 0;
vo_osd_changed(OSDTYPE_PROGBAR);
return;
}
@@ -1345,7 +1346,7 @@ static void update_osd_bar(struct MPContext *mpctx, int type,
double min, double max, double val)
{
if (mpctx->osd->progbar_type == type) {
- int new_value = 256 * (val - min) / (max - min);
+ float new_value = (val - min) / (max - min);
if (new_value != mpctx->osd->progbar_value) {
mpctx->osd->progbar_value = new_value;
vo_osd_changed(OSDTYPE_PROGBAR);
@@ -1353,6 +1354,26 @@ static void update_osd_bar(struct MPContext *mpctx, int type,
}
}
+static void set_osd_bar_chapters(struct MPContext *mpctx, int type)
+{
+ struct osd_state *osd = mpctx->osd;
+ osd->progbar_num_stops = 0;
+ if (osd->progbar_type == type) {
+ double len = get_time_length(mpctx);
+ if (len > 0) {
+ int num = get_chapter_count(mpctx);
+ for (int n = 0; n < num; n++) {
+ double time = chapter_start_time(mpctx, n);
+ if (time >= 0) {
+ float pos = time / len;
+ MP_TARRAY_APPEND(osd, osd->progbar_stops,
+ osd->progbar_num_stops, pos);
+ }
+ }
+ }
+ }
+}
+
void set_osd_function(struct MPContext *mpctx, int osd_function)
{
struct MPOpts *opts = &mpctx->opts;
@@ -1432,6 +1453,7 @@ static void add_seek_osd_messages(struct MPContext *mpctx)
if (mpctx->add_osd_seek_info & OSD_SEEK_INFO_BAR) {
set_osd_bar(mpctx, OSD_BAR_SEEK, "Position", 0, 1,
av_clipf(get_current_pos_ratio(mpctx), 0, 1));
+ set_osd_bar_chapters(mpctx, OSD_BAR_SEEK);
}
if (mpctx->add_osd_seek_info & OSD_SEEK_INFO_TEXT) {
mp_osd_msg_t *msg = add_osd_msg(mpctx, OSD_MSG_TEXT, 1,
diff --git a/core/options.h b/core/options.h
index 4483d6bed2..4291f2d872 100644
--- a/core/options.h
+++ b/core/options.h
@@ -161,6 +161,8 @@ typedef struct MPOpts {
int osd_bar_visible;
float osd_bar_align_x;
float osd_bar_align_y;
+ float osd_bar_w;
+ float osd_bar_h;
struct osd_style_opts *osd_style;
struct osd_style_opts *sub_text_style;
float sub_scale;
diff --git a/sub/osd_libass.c b/sub/osd_libass.c
index bbd925f135..9f5f1fd692 100644
--- a/sub/osd_libass.c
+++ b/sub/osd_libass.c
@@ -61,14 +61,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 +88,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 +141,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;
+};
-#define OSDBAR_ELEMS 46
+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);
+}
-static void update_progbar(struct osd_state *osd, struct osd_object *obj)
+static void ass_draw_stop(struct ass_draw *d)
+{
+ d->text = talloc_strdup_append(d->text, "{\\p0}");
+}
+
+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 +281,57 @@ 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, "{\\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);
+
+ 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 +351,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/sub.h b/sub/sub.h
index 2055799d72..660fd9ccc9 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;