mirror of https://github.com/mpv-player/mpv
sd_lavc: implement sub_step/sub_seek
Works roughly the same as the one in sd_ass for text subtitles. While sub_step is very uninteresting, it comes for free with the support for sub_seek. The implementation is taken from ass_step_sub() from libass, with some modifications
This commit is contained in:
parent
a2e7642d3c
commit
a7cf091519
|
@ -54,6 +54,8 @@ struct sd_lavc_priv {
|
||||||
int64_t new_id;
|
int64_t new_id;
|
||||||
struct mp_image_params video_params;
|
struct mp_image_params video_params;
|
||||||
double current_pts;
|
double current_pts;
|
||||||
|
double *timestamps;
|
||||||
|
int num_timestamps;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool supports_format(const char *format)
|
static bool supports_format(const char *format)
|
||||||
|
@ -235,6 +237,18 @@ static void decode(struct sd *sd, struct demux_packet *packet)
|
||||||
b->y = r->y;
|
b->y = r->y;
|
||||||
current->count++;
|
current->count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pts != MP_NOPTS_VALUE && current->count) {
|
||||||
|
for (int n = 0; n < priv->num_timestamps; n++) {
|
||||||
|
if (priv->timestamps[n] == pts)
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
|
// Set arbitrary limit as safe-guard against insane files.
|
||||||
|
if (priv->num_timestamps >= 10000)
|
||||||
|
MP_TARRAY_REMOVE_AT(priv->timestamps, priv->num_timestamps, 0);
|
||||||
|
MP_TARRAY_APPEND(priv, priv->timestamps, priv->num_timestamps, pts);
|
||||||
|
skip: ;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_bitmaps(struct sd *sd, struct mp_osd_res d, double pts,
|
static void get_bitmaps(struct sd *sd, struct mp_osd_res d, double pts,
|
||||||
|
@ -349,10 +363,72 @@ static void uninit(struct sd *sd)
|
||||||
talloc_free(priv);
|
talloc_free(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int compare_double(const void *pa, const void *pb)
|
||||||
|
{
|
||||||
|
double diff = *(double *)pa - *(double *)pb;
|
||||||
|
return diff == 0 ? 0 : (diff < 0 ? -1 : +1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// taken from ass_step_sub(), libass (ISC)
|
||||||
|
static double step_sub(struct sd *sd, double now, int movement)
|
||||||
|
{
|
||||||
|
struct sd_lavc_priv *priv = sd->priv;
|
||||||
|
int best = -1;
|
||||||
|
double target = now;
|
||||||
|
int direction = movement > 0 ? 1 : -1;
|
||||||
|
|
||||||
|
if (movement == 0 || priv->num_timestamps == 0)
|
||||||
|
return MP_NOPTS_VALUE;
|
||||||
|
|
||||||
|
qsort(priv->timestamps, priv->num_timestamps, sizeof(priv->timestamps[0]),
|
||||||
|
compare_double);
|
||||||
|
|
||||||
|
while (movement) {
|
||||||
|
int closest = -1;
|
||||||
|
double closest_time = 0;
|
||||||
|
for (int i = 0; i < priv->num_timestamps; i++) {
|
||||||
|
double start = priv->timestamps[i];
|
||||||
|
if (direction < 0) {
|
||||||
|
double end = start;
|
||||||
|
if (i + 1 < priv->num_timestamps)
|
||||||
|
end = priv->timestamps[i + 1];
|
||||||
|
if (end < target) {
|
||||||
|
if (closest < 0 || end > closest_time) {
|
||||||
|
closest = i;
|
||||||
|
closest_time = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (start > target) {
|
||||||
|
if (closest < 0 || start < closest_time) {
|
||||||
|
closest = i;
|
||||||
|
closest_time = start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (closest < 0)
|
||||||
|
break;
|
||||||
|
target = closest_time + direction;
|
||||||
|
best = closest;
|
||||||
|
movement -= direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
return best < 0 ? 0 : priv->timestamps[best] - now;
|
||||||
|
}
|
||||||
|
|
||||||
static int control(struct sd *sd, enum sd_ctrl cmd, void *arg)
|
static int control(struct sd *sd, enum sd_ctrl cmd, void *arg)
|
||||||
{
|
{
|
||||||
struct sd_lavc_priv *priv = sd->priv;
|
struct sd_lavc_priv *priv = sd->priv;
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
|
case SD_CTRL_SUB_STEP: {
|
||||||
|
double *a = arg;
|
||||||
|
double res = step_sub(sd, a[0], a[1]);
|
||||||
|
if (res == MP_NOPTS_VALUE)
|
||||||
|
return false;
|
||||||
|
a[0] = res;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
case SD_CTRL_SET_VIDEO_PARAMS:
|
case SD_CTRL_SET_VIDEO_PARAMS:
|
||||||
priv->video_params = *(struct mp_image_params *)arg;
|
priv->video_params = *(struct mp_image_params *)arg;
|
||||||
return CONTROL_OK;
|
return CONTROL_OK;
|
||||||
|
|
Loading…
Reference in New Issue