command: add property to return text subtitles in ASS

See manpage additions. This was requested, sort of. Although what has
been requested might be something completely different. So this is
speculative.

This also changes sub_get_text() to return an allocated copy, because
the buffer shit was too damn messy.
This commit is contained in:
wm4 2020-05-14 22:14:49 +02:00
parent 0049ea38be
commit c6369933f1
7 changed files with 62 additions and 18 deletions

View File

@ -2461,6 +2461,19 @@ Property list
This property is experimental and might be removed in the future.
``sub-text-ass``
Like ``sub-text``, but return the text in ASS format. Text subtitles in
other formats are converted. For native ASS subtitles, events that do
not contain any text (but vector drawings etc.) are not filtered out. If
multiple events match with the current playback time, they are concatenated
with line breaks. Contains only the "Text" part of the events.
This property is not enough to render ASS subtitles correctly, because ASS
header and per-event metadata are not returned. You likely need to do
further filtering on the returned string to make it useful.
This property is experimental and might be removed in the future.
``sub-start``
Return the current subtitle start time (in seconds). If there's multiple
current subtitles, returns the first start time. If no current subtitle is

View File

@ -2695,6 +2695,7 @@ static int mp_property_sub_pos(void *ctx, struct m_property *prop,
static int mp_property_sub_text(void *ctx, struct m_property *prop,
int action, void *arg)
{
int type = *(int *)prop->priv;
MPContext *mpctx = ctx;
struct track *track = mpctx->current_track[0][STREAM_SUB];
struct dec_sub *sub = track ? track->d_sub : NULL;
@ -2702,11 +2703,19 @@ static int mp_property_sub_text(void *ctx, struct m_property *prop,
if (!sub || pts == MP_NOPTS_VALUE)
return M_PROPERTY_UNAVAILABLE;
char *text = sub_get_text(sub, pts);
if (!text)
text = "";
return m_property_strdup_ro(action, arg, text);
switch (action) {
case M_PROPERTY_GET: {
char *text = sub_get_text(sub, pts, type);
if (!text)
text = talloc_strdup(NULL, "");
*(char **)arg = text;
return M_PROPERTY_OK;
}
case M_PROPERTY_GET_TYPE:
*(struct m_option *)arg = (struct m_option){.type = CONF_TYPE_STRING};
return M_PROPERTY_OK;
}
return M_PROPERTY_NOT_IMPLEMENTED;
}
static struct sd_times get_times(void *ctx, struct m_property *prop,
@ -3489,7 +3498,10 @@ static const struct m_property mp_properties_base[] = {
{"sub-delay", mp_property_sub_delay},
{"sub-speed", mp_property_sub_speed},
{"sub-pos", mp_property_sub_pos},
{"sub-text", mp_property_sub_text},
{"sub-text", mp_property_sub_text,
.priv = (void *)&(const int){SD_TEXT_TYPE_PLAIN}},
{"sub-text-ass", mp_property_sub_text,
.priv = (void *)&(const int){SD_TEXT_TYPE_ASS}},
{"sub-start", mp_property_sub_start},
{"sub-end", mp_property_sub_end},

View File

@ -105,8 +105,11 @@ static bool update_subtitle(struct MPContext *mpctx, double video_pts,
return false;
// Handle displaying subtitles on terminal; never done for secondary subs
if (mpctx->current_track[0][STREAM_SUB] == track && !mpctx->video_out)
term_osd_set_subs(mpctx, sub_get_text(dec_sub, video_pts));
if (mpctx->current_track[0][STREAM_SUB] == track && !mpctx->video_out) {
char *text = sub_get_text(dec_sub, video_pts, SD_TEXT_TYPE_PLAIN);
term_osd_set_subs(mpctx, text);
talloc_free(text);
}
// Handle displaying subtitles on VO with no video being played. This is
// quite different, because normally subtitles are redrawn on new video

View File

@ -348,10 +348,10 @@ struct sub_bitmaps *sub_get_bitmaps(struct dec_sub *sub, struct mp_osd_res dim,
return res;
}
// See sub_get_bitmaps() for locking requirements.
// It can be called unlocked too, but then only 1 thread must call this function
// at a time (unless exclusive access is guaranteed).
char *sub_get_text(struct dec_sub *sub, double pts)
// This can only be called by the main thread, due to the returned text pointing
// to a buffer bound to the sub object. The main thread is the designated
// "outside" owner of the buffer.
char *sub_get_text(struct dec_sub *sub, double pts, enum sd_text_type type)
{
pthread_mutex_lock(&sub->lock);
char *text = NULL;
@ -362,7 +362,7 @@ char *sub_get_text(struct dec_sub *sub, double pts)
update_segment(sub);
if (sub->sd->driver->get_text)
text = sub->sd->driver->get_text(sub->sd, pts);
text = sub->sd->driver->get_text(sub->sd, pts, type);
pthread_mutex_unlock(&sub->lock);
return text;
}

View File

@ -22,6 +22,11 @@ enum sd_ctrl {
SD_CTRL_UPDATE_OPTS,
};
enum sd_text_type {
SD_TEXT_TYPE_PLAIN,
SD_TEXT_TYPE_ASS,
};
struct sd_times {
double start;
double end;
@ -41,7 +46,7 @@ void sub_preload(struct dec_sub *sub);
bool sub_read_packets(struct dec_sub *sub, double video_pts);
struct sub_bitmaps *sub_get_bitmaps(struct dec_sub *sub, struct mp_osd_res dim,
int format, double pts);
char *sub_get_text(struct dec_sub *sub, double pts);
char *sub_get_text(struct dec_sub *sub, double pts, enum sd_text_type type);
struct sd_times sub_get_times(struct dec_sub *sub, double pts);
void sub_reset(struct dec_sub *sub);
void sub_select(struct dec_sub *sub, bool selected);

View File

@ -40,7 +40,7 @@ struct sd_functions {
struct sub_bitmaps *(*get_bitmaps)(struct sd *sd, struct mp_osd_res dim,
int format, double pts);
char *(*get_text)(struct sd *sd, double pts);
char *(*get_text)(struct sd *sd, double pts, enum sd_text_type type);
struct sd_times (*get_times)(struct sd *sd, double pts);
};

View File

@ -627,7 +627,7 @@ static bool is_whitespace_only(char *s, int len)
return true;
}
static char *get_text(struct sd *sd, double pts)
static char *get_text_buf(struct sd *sd, double pts, enum sd_text_type type)
{
struct sd_ass_priv *ctx = sd->priv;
ASS_Track *track = ctx->ass_track;
@ -643,7 +643,13 @@ static char *get_text(struct sd *sd, double pts)
if (ipts >= event->Start && ipts < event->Start + event->Duration) {
if (event->Text) {
int start = b.len;
ass_to_plaintext(&b, event->Text);
if (type == SD_TEXT_TYPE_PLAIN) {
ass_to_plaintext(&b, event->Text);
} else {
char *t = event->Text;
while (*t)
append(&b, *t++);
}
if (is_whitespace_only(&b.start[start], b.len - start)) {
b.len = start;
} else {
@ -661,6 +667,11 @@ static char *get_text(struct sd *sd, double pts)
return ctx->last_text;
}
static char *get_text(struct sd *sd, double pts, enum sd_text_type type)
{
return talloc_strdup(NULL, get_text_buf(sd, pts, type));
}
static struct sd_times get_times(struct sd *sd, double pts)
{
struct sd_ass_priv *ctx = sd->priv;
@ -697,7 +708,7 @@ static void fill_plaintext(struct sd *sd, double pts)
ass_flush_events(track);
char *text = get_text(sd, pts);
char *text = get_text_buf(sd, pts, SD_TEXT_TYPE_PLAIN);
if (!text)
return;