2010-07-10 13:45:09 +00:00
|
|
|
/*
|
2015-04-13 07:36:54 +00:00
|
|
|
* This file is part of mpv.
|
2010-07-10 13:45:09 +00:00
|
|
|
*
|
2017-04-20 09:15:05 +00:00
|
|
|
* mpv is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2010-07-10 13:45:09 +00:00
|
|
|
*
|
2015-04-13 07:36:54 +00:00
|
|
|
* mpv is distributed in the hope that it will be useful,
|
2010-07-10 13:45:09 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2017-04-20 09:15:05 +00:00
|
|
|
* GNU Lesser General Public License for more details.
|
2010-07-10 13:45:09 +00:00
|
|
|
*
|
2017-04-20 09:15:05 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
2010-07-10 13:45:09 +00:00
|
|
|
*/
|
|
|
|
|
2012-08-16 15:21:21 +00:00
|
|
|
#include <stdlib.h>
|
2012-10-04 15:16:47 +00:00
|
|
|
#include <assert.h>
|
sub: fix crash with certain uses of --vf=sub
If, for some reason, the subtitle renderer attempts to render a
subtitle before SD_CTRL_SET_VIDEO_PARAMS was called, it passed a
value calculated from invalid values. This can happen with --vf=sub
and --start. The crash happens if 1. there was a subtitle packet that
falls into the timestamp of the rendered video frame, 2. the playloop
hasn't informed the subtitle decoder about the video resolution yet
(normally unneeded, because that is used for weird corner cases only,
so this code is a bit fuzzy), and 3. something actually requests a
frame to be drawn from the subtitle renderer, like with vf_sub.
The actual crash was due to passing NaN as pixel aspect to libass,
which then created glyphs with ridiculous sizes, involving a few
integer overflows and unchecked mallocs.
The sd_lavc.c and sd_spu.c cases probably don't crash, but I'm not
sure, and it's better fix them anyway.
Not bothering with sd_spu.c, this crap is for compatibility and will
be removed soon.
Note that this would have been no problem, had the code checked whether
SD_CTRL_SET_VIDEO_PARAMS was actually called. This commit adds such a
check (although it basically checks after using the parameters).
Regression since 49caa0a7 and 633fde4a.
2014-01-26 17:58:40 +00:00
|
|
|
#include <math.h>
|
2012-08-16 15:21:21 +00:00
|
|
|
|
2010-07-10 13:45:09 +00:00
|
|
|
#include <libavcodec/avcodec.h>
|
2013-07-15 01:00:58 +00:00
|
|
|
#include <libavutil/common.h>
|
2014-02-13 21:54:15 +00:00
|
|
|
#include <libavutil/intreadwrite.h>
|
2016-09-03 15:05:11 +00:00
|
|
|
#include <libavutil/opt.h>
|
2010-07-10 13:45:09 +00:00
|
|
|
|
2015-10-23 18:14:08 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2016-01-11 18:03:40 +00:00
|
|
|
#include "mpv_talloc.h"
|
2013-12-17 01:39:45 +00:00
|
|
|
#include "common/msg.h"
|
|
|
|
#include "common/av_common.h"
|
2015-12-18 00:54:14 +00:00
|
|
|
#include "demux/stheader.h"
|
2013-12-17 01:02:25 +00:00
|
|
|
#include "options/options.h"
|
2013-11-01 12:15:59 +00:00
|
|
|
#include "video/mp_image.h"
|
2016-06-17 18:10:39 +00:00
|
|
|
#include "video/out/bitmap_packer.h"
|
2016-06-17 19:54:12 +00:00
|
|
|
#include "img_convert.h"
|
2012-08-16 15:21:21 +00:00
|
|
|
#include "sd.h"
|
2012-10-04 15:16:40 +00:00
|
|
|
#include "dec_sub.h"
|
2010-07-10 13:45:09 +00:00
|
|
|
|
2014-06-17 22:18:37 +00:00
|
|
|
#define MAX_QUEUE 4
|
|
|
|
|
|
|
|
struct sub {
|
|
|
|
bool valid;
|
|
|
|
AVSubtitle avsub;
|
2012-08-31 12:42:30 +00:00
|
|
|
struct sub_bitmap *inbitmaps;
|
2016-06-17 18:10:39 +00:00
|
|
|
int count;
|
|
|
|
struct mp_image *data;
|
sub, vo_opengl: use packed sub-bitmaps directly if available
The previous few commits changed sd_lavc.c's output to packed RGB sub-
images. In particular, this means all sub-bitmaps are part of a larger,
single bitmap. Change the vo_opengl OSD code such that it can make use
of this, and upload the pre-packed image, instead of packing and copying
them again.
This complicates the upload code a bit (4 code paths due to messy PBO
handling). The plan is to make sub-bitmaps always packed, but some more
work is required to reach this point. The plan is to pack libass images
as well. Since this implies a copy, this will make it easy to refcount
the result.
(This is all targeted towards vo_opengl. Other VOs, vo_xv, vo_x11, and
vo_wayland in particular, will become less efficient. Although at least
vo_vdpau and vo_direct3d could be switched to the new method as well.)
2016-06-17 21:11:05 +00:00
|
|
|
int bound_w, bound_h;
|
2016-06-17 20:04:26 +00:00
|
|
|
int src_w, src_h;
|
2012-12-12 21:56:41 +00:00
|
|
|
double pts;
|
2012-08-31 12:42:30 +00:00
|
|
|
double endpts;
|
2014-06-17 22:18:37 +00:00
|
|
|
int64_t id;
|
|
|
|
};
|
|
|
|
|
2015-12-05 22:55:35 +00:00
|
|
|
struct seekpoint {
|
|
|
|
double pts;
|
|
|
|
double endpts;
|
|
|
|
};
|
|
|
|
|
2014-06-17 22:18:37 +00:00
|
|
|
struct sd_lavc_priv {
|
|
|
|
AVCodecContext *avctx;
|
2016-04-02 15:39:49 +00:00
|
|
|
AVRational pkt_timebase;
|
2014-08-24 10:26:34 +00:00
|
|
|
struct sub subs[MAX_QUEUE]; // most recent event first
|
2014-06-17 22:18:37 +00:00
|
|
|
struct sub_bitmap *outbitmaps;
|
|
|
|
int64_t displayed_id;
|
|
|
|
int64_t new_id;
|
2013-11-01 12:15:59 +00:00
|
|
|
struct mp_image_params video_params;
|
2015-12-05 22:54:00 +00:00
|
|
|
double current_pts;
|
2015-12-05 22:55:35 +00:00
|
|
|
struct seekpoint *seekpoints;
|
|
|
|
int num_seekpoints;
|
2016-06-17 18:10:39 +00:00
|
|
|
struct bitmap_packer *packer;
|
2012-08-31 12:42:30 +00:00
|
|
|
};
|
|
|
|
|
2013-06-01 17:44:12 +00:00
|
|
|
static int init(struct sd *sd)
|
2010-07-10 13:45:09 +00:00
|
|
|
{
|
2016-01-12 22:48:19 +00:00
|
|
|
enum AVCodecID cid = mp_codec_to_av_codec_id(sd->codec->codec);
|
2015-12-27 01:07:01 +00:00
|
|
|
|
|
|
|
// Supported codecs must be known to decode to paletted bitmaps
|
|
|
|
switch (cid) {
|
|
|
|
case AV_CODEC_ID_DVB_SUBTITLE:
|
2016-09-03 15:05:11 +00:00
|
|
|
#if LIBAVCODEC_VERSION_MICRO >= 100
|
|
|
|
case AV_CODEC_ID_DVB_TELETEXT:
|
|
|
|
#endif
|
2015-12-27 01:07:01 +00:00
|
|
|
case AV_CODEC_ID_HDMV_PGS_SUBTITLE:
|
|
|
|
case AV_CODEC_ID_XSUB:
|
|
|
|
case AV_CODEC_ID_DVD_SUBTITLE:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct sd_lavc_priv *priv = talloc_zero(NULL, struct sd_lavc_priv);
|
2012-08-16 15:21:21 +00:00
|
|
|
AVCodecContext *ctx = NULL;
|
|
|
|
AVCodec *sub_codec = avcodec_find_decoder(cid);
|
|
|
|
if (!sub_codec)
|
|
|
|
goto error;
|
|
|
|
ctx = avcodec_alloc_context3(sub_codec);
|
|
|
|
if (!ctx)
|
|
|
|
goto error;
|
2016-01-12 22:48:19 +00:00
|
|
|
mp_lavc_set_extradata(ctx, sd->codec->extradata, sd->codec->extradata_size);
|
2016-08-29 11:13:37 +00:00
|
|
|
priv->pkt_timebase = mp_get_codec_timebase(sd->codec);
|
2016-05-10 09:48:43 +00:00
|
|
|
#if LIBAVCODEC_VERSION_MICRO >= 100
|
2016-08-29 11:13:37 +00:00
|
|
|
ctx->pkt_timebase = priv->pkt_timebase;
|
2016-05-10 09:48:43 +00:00
|
|
|
#endif
|
2012-08-16 15:21:21 +00:00
|
|
|
if (avcodec_open2(ctx, sub_codec, NULL) < 0)
|
|
|
|
goto error;
|
2012-08-31 12:42:30 +00:00
|
|
|
priv->avctx = ctx;
|
2013-06-01 17:44:12 +00:00
|
|
|
sd->priv = priv;
|
2014-06-17 22:18:37 +00:00
|
|
|
priv->displayed_id = -1;
|
2015-12-05 22:54:00 +00:00
|
|
|
priv->current_pts = MP_NOPTS_VALUE;
|
2016-06-17 18:10:39 +00:00
|
|
|
priv->packer = talloc_zero(priv, struct bitmap_packer);
|
2012-08-16 15:21:21 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
2013-12-21 18:06:37 +00:00
|
|
|
MP_FATAL(sd, "Could not open libavcodec subtitle decoder\n");
|
2017-07-06 14:12:50 +00:00
|
|
|
avcodec_free_context(&ctx);
|
2012-08-31 12:42:30 +00:00
|
|
|
talloc_free(priv);
|
2012-08-16 15:21:21 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-06-17 22:18:37 +00:00
|
|
|
static void clear_sub(struct sub *sub)
|
2012-08-31 12:42:30 +00:00
|
|
|
{
|
2014-06-17 22:18:37 +00:00
|
|
|
sub->count = 0;
|
|
|
|
sub->pts = MP_NOPTS_VALUE;
|
|
|
|
sub->endpts = MP_NOPTS_VALUE;
|
|
|
|
if (sub->valid)
|
|
|
|
avsubtitle_free(&sub->avsub);
|
|
|
|
sub->valid = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void alloc_sub(struct sd_lavc_priv *priv)
|
|
|
|
{
|
|
|
|
clear_sub(&priv->subs[MAX_QUEUE - 1]);
|
2015-12-05 22:54:00 +00:00
|
|
|
struct sub tmp = priv->subs[MAX_QUEUE - 1];
|
2014-06-17 22:18:37 +00:00
|
|
|
for (int n = MAX_QUEUE - 1; n > 0; n--)
|
|
|
|
priv->subs[n] = priv->subs[n - 1];
|
2015-12-05 22:54:00 +00:00
|
|
|
priv->subs[0] = tmp;
|
2014-06-17 22:18:37 +00:00
|
|
|
// clear only some fields; the memory allocs can be reused
|
|
|
|
priv->subs[0].valid = false;
|
|
|
|
priv->subs[0].count = 0;
|
2016-06-17 20:04:26 +00:00
|
|
|
priv->subs[0].src_w = 0;
|
|
|
|
priv->subs[0].src_h = 0;
|
2014-06-17 22:18:37 +00:00
|
|
|
priv->subs[0].id = priv->new_id++;
|
2012-08-31 12:42:30 +00:00
|
|
|
}
|
|
|
|
|
2016-06-17 18:10:39 +00:00
|
|
|
static void convert_pal(uint32_t *colors, size_t count, bool gray)
|
|
|
|
{
|
|
|
|
for (int n = 0; n < count; n++) {
|
|
|
|
uint32_t c = colors[n];
|
2019-01-20 16:29:33 +00:00
|
|
|
uint32_t b = c & 0xFF;
|
|
|
|
uint32_t g = (c >> 8) & 0xFF;
|
|
|
|
uint32_t r = (c >> 16) & 0xFF;
|
|
|
|
uint32_t a = (c >> 24) & 0xFF;
|
2016-06-17 18:10:39 +00:00
|
|
|
if (gray)
|
|
|
|
r = g = b = (r + g + b) / 3;
|
|
|
|
// from straight to pre-multiplied alpha
|
|
|
|
b = b * a / 255;
|
|
|
|
g = g * a / 255;
|
|
|
|
r = r * a / 255;
|
|
|
|
colors[n] = b | (g << 8) | (r << 16) | (a << 24);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-17 15:48:05 +00:00
|
|
|
// Initialize sub from sub->avsub.
|
|
|
|
static void read_sub_bitmaps(struct sd *sd, struct sub *sub)
|
|
|
|
{
|
2017-12-29 16:19:25 +00:00
|
|
|
struct mp_subtitle_opts *opts = sd->opts;
|
2016-06-17 15:48:05 +00:00
|
|
|
struct sd_lavc_priv *priv = sd->priv;
|
|
|
|
AVSubtitle *avsub = &sub->avsub;
|
|
|
|
|
|
|
|
MP_TARRAY_GROW(priv, sub->inbitmaps, avsub->num_rects);
|
2016-06-17 18:10:39 +00:00
|
|
|
|
|
|
|
packer_set_size(priv->packer, avsub->num_rects);
|
|
|
|
|
2016-06-17 19:54:12 +00:00
|
|
|
// If we blur, we want a transparent region around the bitmap data to
|
|
|
|
// avoid "cut off" artifacts on the borders.
|
|
|
|
bool apply_blur = opts->sub_gauss != 0.0f;
|
|
|
|
int extend = apply_blur ? 5 : 0;
|
2016-06-17 18:10:39 +00:00
|
|
|
// Assume consumers may use bilinear scaling on it (2x2 filter)
|
2016-06-17 19:54:12 +00:00
|
|
|
int padding = 1 + extend;
|
|
|
|
|
|
|
|
priv->packer->padding = padding;
|
2016-06-17 15:48:05 +00:00
|
|
|
|
2016-06-18 10:08:17 +00:00
|
|
|
// For the sake of libswscale, which in some cases takes sub-rects as
|
|
|
|
// source images, and wants 16 byte start pointer and stride alignment.
|
|
|
|
int align = 4;
|
|
|
|
|
2016-06-17 15:48:05 +00:00
|
|
|
for (int i = 0; i < avsub->num_rects; i++) {
|
|
|
|
struct AVSubtitleRect *r = avsub->rects[i];
|
|
|
|
struct sub_bitmap *b = &sub->inbitmaps[sub->count];
|
2016-06-17 18:10:39 +00:00
|
|
|
|
2016-06-17 15:48:05 +00:00
|
|
|
if (r->type != SUBTITLE_BITMAP) {
|
|
|
|
MP_ERR(sd, "unsupported subtitle type from libavcodec\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!(r->flags & AV_SUBTITLE_FLAG_FORCED) && opts->forced_subs_only)
|
|
|
|
continue;
|
|
|
|
if (r->w <= 0 || r->h <= 0)
|
|
|
|
continue;
|
2016-06-17 18:10:39 +00:00
|
|
|
|
|
|
|
b->bitmap = r; // save for later (dumb hack to avoid more complexity)
|
|
|
|
|
2016-06-18 10:08:17 +00:00
|
|
|
priv->packer->in[sub->count] = (struct pos){r->w + (align - 1), r->h};
|
2016-06-17 18:10:39 +00:00
|
|
|
sub->count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
priv->packer->count = sub->count;
|
|
|
|
|
|
|
|
if (packer_pack(priv->packer) < 0) {
|
|
|
|
MP_ERR(sd, "Unable to pack subtitle bitmaps.\n");
|
|
|
|
sub->count = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sub->count)
|
|
|
|
return;
|
|
|
|
|
|
|
|
struct pos bb[2];
|
|
|
|
packer_get_bb(priv->packer, bb);
|
|
|
|
|
sub, vo_opengl: use packed sub-bitmaps directly if available
The previous few commits changed sd_lavc.c's output to packed RGB sub-
images. In particular, this means all sub-bitmaps are part of a larger,
single bitmap. Change the vo_opengl OSD code such that it can make use
of this, and upload the pre-packed image, instead of packing and copying
them again.
This complicates the upload code a bit (4 code paths due to messy PBO
handling). The plan is to make sub-bitmaps always packed, but some more
work is required to reach this point. The plan is to pack libass images
as well. Since this implies a copy, this will make it easy to refcount
the result.
(This is all targeted towards vo_opengl. Other VOs, vo_xv, vo_x11, and
vo_wayland in particular, will become less efficient. Although at least
vo_vdpau and vo_direct3d could be switched to the new method as well.)
2016-06-17 21:11:05 +00:00
|
|
|
sub->bound_w = bb[1].x;
|
|
|
|
sub->bound_h = bb[1].y;
|
|
|
|
|
|
|
|
if (!sub->data || sub->data->w < sub->bound_w || sub->data->h < sub->bound_h) {
|
2016-06-17 18:10:39 +00:00
|
|
|
talloc_free(sub->data);
|
|
|
|
sub->data = mp_image_alloc(IMGFMT_BGRA, priv->packer->w, priv->packer->h);
|
|
|
|
if (!sub->data) {
|
|
|
|
sub->count = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
talloc_steal(priv, sub->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < sub->count; i++) {
|
|
|
|
struct sub_bitmap *b = &sub->inbitmaps[i];
|
|
|
|
struct pos pos = priv->packer->result[i];
|
|
|
|
struct AVSubtitleRect *r = b->bitmap;
|
2016-06-17 15:48:05 +00:00
|
|
|
uint8_t **data = r->data;
|
|
|
|
int *linesize = r->linesize;
|
|
|
|
b->w = r->w;
|
|
|
|
b->h = r->h;
|
|
|
|
b->x = r->x;
|
|
|
|
b->y = r->y;
|
2016-06-18 10:08:17 +00:00
|
|
|
|
|
|
|
// Choose such that the extended start position is aligned.
|
2016-06-18 17:30:38 +00:00
|
|
|
pos.x = MP_ALIGN_UP(pos.x - extend, align) + extend;
|
2016-06-18 10:08:17 +00:00
|
|
|
|
sub, vo_opengl: use packed sub-bitmaps directly if available
The previous few commits changed sd_lavc.c's output to packed RGB sub-
images. In particular, this means all sub-bitmaps are part of a larger,
single bitmap. Change the vo_opengl OSD code such that it can make use
of this, and upload the pre-packed image, instead of packing and copying
them again.
This complicates the upload code a bit (4 code paths due to messy PBO
handling). The plan is to make sub-bitmaps always packed, but some more
work is required to reach this point. The plan is to pack libass images
as well. Since this implies a copy, this will make it easy to refcount
the result.
(This is all targeted towards vo_opengl. Other VOs, vo_xv, vo_x11, and
vo_wayland in particular, will become less efficient. Although at least
vo_vdpau and vo_direct3d could be switched to the new method as well.)
2016-06-17 21:11:05 +00:00
|
|
|
b->src_x = pos.x;
|
|
|
|
b->src_y = pos.y;
|
2016-06-17 18:10:39 +00:00
|
|
|
b->stride = sub->data->stride[0];
|
|
|
|
b->bitmap = sub->data->planes[0] + pos.y * b->stride + pos.x * 4;
|
|
|
|
|
2019-10-31 10:24:20 +00:00
|
|
|
sub->src_w = MPMAX(sub->src_w, b->x + b->w);
|
|
|
|
sub->src_h = MPMAX(sub->src_h, b->y + b->h);
|
2016-06-17 20:04:26 +00:00
|
|
|
|
2016-06-17 18:10:39 +00:00
|
|
|
assert(r->nb_colors > 0);
|
|
|
|
assert(r->nb_colors <= 256);
|
|
|
|
uint32_t pal[256] = {0};
|
|
|
|
memcpy(pal, data[1], r->nb_colors * 4);
|
|
|
|
convert_pal(pal, 256, opts->sub_gray);
|
|
|
|
|
2016-06-17 19:54:12 +00:00
|
|
|
for (int y = -padding; y < b->h + padding; y++) {
|
2016-06-17 18:10:39 +00:00
|
|
|
uint32_t *out = (uint32_t*)((char*)b->bitmap + y * b->stride);
|
|
|
|
int start = 0;
|
2016-06-17 19:54:12 +00:00
|
|
|
for (int x = -padding; x < 0; x++)
|
|
|
|
out[x] = 0;
|
|
|
|
if (y >= 0 && y < b->h) {
|
2016-06-17 18:10:39 +00:00
|
|
|
uint8_t *in = data[0] + y * linesize[0];
|
|
|
|
for (int x = 0; x < b->w; x++)
|
|
|
|
*out++ = pal[*in++];
|
|
|
|
start = b->w;
|
|
|
|
}
|
|
|
|
for (int x = start; x < b->w + padding; x++)
|
|
|
|
*out++ = 0;
|
|
|
|
}
|
2016-06-17 19:54:12 +00:00
|
|
|
|
|
|
|
b->bitmap = (char*)b->bitmap - extend * b->stride - extend * 4;
|
sub, vo_opengl: use packed sub-bitmaps directly if available
The previous few commits changed sd_lavc.c's output to packed RGB sub-
images. In particular, this means all sub-bitmaps are part of a larger,
single bitmap. Change the vo_opengl OSD code such that it can make use
of this, and upload the pre-packed image, instead of packing and copying
them again.
This complicates the upload code a bit (4 code paths due to messy PBO
handling). The plan is to make sub-bitmaps always packed, but some more
work is required to reach this point. The plan is to pack libass images
as well. Since this implies a copy, this will make it easy to refcount
the result.
(This is all targeted towards vo_opengl. Other VOs, vo_xv, vo_x11, and
vo_wayland in particular, will become less efficient. Although at least
vo_vdpau and vo_direct3d could be switched to the new method as well.)
2016-06-17 21:11:05 +00:00
|
|
|
b->src_x -= extend;
|
|
|
|
b->src_y -= extend;
|
2016-06-17 19:54:12 +00:00
|
|
|
b->x -= extend;
|
|
|
|
b->y -= extend;
|
|
|
|
b->w += extend * 2;
|
|
|
|
b->h += extend * 2;
|
|
|
|
|
|
|
|
if (apply_blur)
|
|
|
|
mp_blur_rgba_sub_bitmap(b, opts->sub_gauss);
|
2016-06-17 15:48:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-01 17:44:12 +00:00
|
|
|
static void decode(struct sd *sd, struct demux_packet *packet)
|
2012-08-16 15:21:21 +00:00
|
|
|
{
|
2017-12-29 16:19:25 +00:00
|
|
|
struct mp_subtitle_opts *opts = sd->opts;
|
2013-06-01 17:44:12 +00:00
|
|
|
struct sd_lavc_priv *priv = sd->priv;
|
2012-08-31 12:42:30 +00:00
|
|
|
AVCodecContext *ctx = priv->avctx;
|
2013-06-01 17:44:12 +00:00
|
|
|
double pts = packet->pts;
|
2015-12-05 22:55:35 +00:00
|
|
|
double endpts = MP_NOPTS_VALUE;
|
2013-06-01 17:44:12 +00:00
|
|
|
double duration = packet->duration;
|
2012-08-16 15:21:21 +00:00
|
|
|
AVSubtitle sub;
|
|
|
|
AVPacket pkt;
|
2010-07-11 09:40:46 +00:00
|
|
|
|
2016-04-02 15:35:42 +00:00
|
|
|
// libavformat sets duration==0, even if the duration is unknown. Some files
|
|
|
|
// also have actually subtitle packets with duration explicitly set to 0
|
|
|
|
// (yes, at least some of such mkv files were muxed by libavformat).
|
2013-10-31 17:16:30 +00:00
|
|
|
// Assume there are no bitmap subs that actually use duration==0 for
|
|
|
|
// hidden subtitle events.
|
|
|
|
if (duration == 0)
|
|
|
|
duration = -1;
|
|
|
|
|
2014-08-14 21:45:58 +00:00
|
|
|
if (pts == MP_NOPTS_VALUE)
|
2014-06-17 22:18:37 +00:00
|
|
|
MP_WARN(sd, "Subtitle with unknown start time.\n");
|
|
|
|
|
2016-04-02 15:39:49 +00:00
|
|
|
mp_set_av_packet(&pkt, packet, &priv->pkt_timebase);
|
2016-09-03 15:05:11 +00:00
|
|
|
|
|
|
|
if (ctx->codec_id == AV_CODEC_ID_DVB_TELETEXT) {
|
|
|
|
char page[4];
|
|
|
|
snprintf(page, sizeof(page), "%d", opts->teletext_page);
|
|
|
|
av_opt_set(ctx, "txt_page", page, AV_OPT_SEARCH_CHILDREN);
|
|
|
|
}
|
|
|
|
|
2012-08-16 15:21:21 +00:00
|
|
|
int got_sub;
|
|
|
|
int res = avcodec_decode_subtitle2(ctx, &sub, &got_sub, &pkt);
|
|
|
|
if (res < 0 || !got_sub)
|
|
|
|
return;
|
2014-06-17 22:18:37 +00:00
|
|
|
|
2016-04-02 15:39:49 +00:00
|
|
|
if (sub.pts != AV_NOPTS_VALUE)
|
|
|
|
pts = sub.pts / (double)AV_TIME_BASE;
|
|
|
|
|
2011-01-14 12:05:22 +00:00
|
|
|
if (pts != MP_NOPTS_VALUE) {
|
2014-12-21 22:55:00 +00:00
|
|
|
if (sub.end_display_time > sub.start_display_time &&
|
|
|
|
sub.end_display_time != UINT32_MAX)
|
|
|
|
{
|
2011-01-16 18:51:48 +00:00
|
|
|
duration = (sub.end_display_time - sub.start_display_time) / 1000.0;
|
2014-12-21 22:55:00 +00:00
|
|
|
}
|
2011-01-14 12:05:22 +00:00
|
|
|
pts += sub.start_display_time / 1000.0;
|
2014-06-17 22:18:37 +00:00
|
|
|
|
2015-12-05 22:55:35 +00:00
|
|
|
if (duration >= 0)
|
|
|
|
endpts = pts + duration;
|
|
|
|
|
|
|
|
// set end time of previous sub
|
|
|
|
struct sub *prev = &priv->subs[0];
|
|
|
|
if (prev->valid) {
|
|
|
|
if (prev->endpts == MP_NOPTS_VALUE || prev->endpts > pts)
|
|
|
|
prev->endpts = pts;
|
|
|
|
|
2015-12-05 22:55:56 +00:00
|
|
|
if (opts->sub_fix_timing && pts - prev->endpts <= SUB_GAP_THRESHOLD)
|
|
|
|
prev->endpts = pts;
|
|
|
|
|
2015-12-05 22:55:35 +00:00
|
|
|
for (int n = 0; n < priv->num_seekpoints; n++) {
|
|
|
|
if (priv->seekpoints[n].pts == prev->pts) {
|
|
|
|
priv->seekpoints[n].endpts = prev->endpts;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This subtitle packet only signals the end of subtitle display.
|
|
|
|
if (!sub.num_rects) {
|
|
|
|
avsubtitle_free(&sub);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2014-06-17 22:18:37 +00:00
|
|
|
|
|
|
|
alloc_sub(priv);
|
|
|
|
struct sub *current = &priv->subs[0];
|
|
|
|
|
|
|
|
current->valid = true;
|
|
|
|
current->pts = pts;
|
|
|
|
current->endpts = endpts;
|
|
|
|
current->avsub = sub;
|
|
|
|
|
2016-06-17 15:48:05 +00:00
|
|
|
read_sub_bitmaps(sd, current);
|
2015-12-05 22:55:22 +00:00
|
|
|
|
2015-12-05 22:55:35 +00:00
|
|
|
if (pts != MP_NOPTS_VALUE) {
|
|
|
|
for (int n = 0; n < priv->num_seekpoints; n++) {
|
|
|
|
if (priv->seekpoints[n].pts == pts)
|
2015-12-05 22:55:22 +00:00
|
|
|
goto skip;
|
|
|
|
}
|
|
|
|
// Set arbitrary limit as safe-guard against insane files.
|
2015-12-05 22:55:35 +00:00
|
|
|
if (priv->num_seekpoints >= 10000)
|
|
|
|
MP_TARRAY_REMOVE_AT(priv->seekpoints, priv->num_seekpoints, 0);
|
|
|
|
MP_TARRAY_APPEND(priv, priv->seekpoints, priv->num_seekpoints,
|
|
|
|
(struct seekpoint){.pts = pts, .endpts = endpts});
|
2015-12-05 22:55:22 +00:00
|
|
|
skip: ;
|
|
|
|
}
|
2012-08-16 15:21:21 +00:00
|
|
|
}
|
|
|
|
|
2019-09-21 18:11:18 +00:00
|
|
|
static struct sub *get_current(struct sd_lavc_priv *priv, double pts)
|
2012-08-31 12:42:30 +00:00
|
|
|
{
|
2014-06-17 22:18:37 +00:00
|
|
|
struct sub *current = NULL;
|
2016-04-02 15:32:05 +00:00
|
|
|
for (int n = 0; n < MAX_QUEUE; n++) {
|
2014-06-17 22:18:37 +00:00
|
|
|
struct sub *sub = &priv->subs[n];
|
2014-06-19 16:46:06 +00:00
|
|
|
if (!sub->valid)
|
|
|
|
continue;
|
2014-06-17 22:18:37 +00:00
|
|
|
if (pts == MP_NOPTS_VALUE ||
|
|
|
|
((sub->pts == MP_NOPTS_VALUE || pts >= sub->pts) &&
|
|
|
|
(sub->endpts == MP_NOPTS_VALUE || pts < sub->endpts)))
|
|
|
|
{
|
2014-12-21 23:00:18 +00:00
|
|
|
// Ignore "trailing" subtitles with unknown length after 1 minute.
|
|
|
|
if (sub->endpts == MP_NOPTS_VALUE && pts >= sub->pts + 60)
|
|
|
|
break;
|
2014-06-17 22:18:37 +00:00
|
|
|
current = sub;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-09-21 18:11:18 +00:00
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void get_bitmaps(struct sd *sd, struct mp_osd_res d, int format,
|
|
|
|
double pts, struct sub_bitmaps *res)
|
|
|
|
{
|
|
|
|
struct sd_lavc_priv *priv = sd->priv;
|
|
|
|
struct mp_subtitle_opts *opts = sd->opts;
|
|
|
|
|
|
|
|
priv->current_pts = pts;
|
|
|
|
|
|
|
|
struct sub *current = get_current(priv, pts);
|
|
|
|
|
2014-06-17 22:18:37 +00:00
|
|
|
if (!current)
|
2012-12-12 21:56:41 +00:00
|
|
|
return;
|
2014-06-17 22:18:37 +00:00
|
|
|
|
|
|
|
MP_TARRAY_GROW(priv, priv->outbitmaps, current->count);
|
|
|
|
for (int n = 0; n < current->count; n++)
|
|
|
|
priv->outbitmaps[n] = current->inbitmaps[n];
|
Add prelimimary (basic, possibly broken) dvdnav support
This readds a more or less completely new dvdnav implementation, though
it's based on the code from before commit 41fbcee. Note that this is
rather basic, and might be broken or not quite usable in many cases.
Most importantly, navigation highlights are not correctly implemented.
This would require changes in the FFmpeg dvdsub decoder (to apply a
different internal CLUT), so supporting it is not really possible right
now. And in fact, I don't think I ever want to support it, because it's
a very small gain for a lot of work. Instead, mpv will display fake
highlights, which are an approximate bounding box around the real
highlights.
Some things like mouse input or switching audio/subtitles stream using
the dvdnav VM are not supported.
Might be quite fragile on transitions: if dvdnav initiates a transition,
and doesn't give us enough mpeg data to initialize video playback, the
player will just quit.
This is added only because some users seem to want it. I don't intend to
make mpv a good DVD player, so the very basic minimum will have to do.
How about you just convert your DVD to proper video files?
2013-12-12 00:44:28 +00:00
|
|
|
|
2012-08-31 12:42:30 +00:00
|
|
|
res->parts = priv->outbitmaps;
|
2014-06-17 22:18:37 +00:00
|
|
|
res->num_parts = current->count;
|
|
|
|
if (priv->displayed_id != current->id)
|
2015-03-18 11:33:14 +00:00
|
|
|
res->change_id++;
|
2014-06-17 22:18:37 +00:00
|
|
|
priv->displayed_id = current->id;
|
sub, vo_opengl: use packed sub-bitmaps directly if available
The previous few commits changed sd_lavc.c's output to packed RGB sub-
images. In particular, this means all sub-bitmaps are part of a larger,
single bitmap. Change the vo_opengl OSD code such that it can make use
of this, and upload the pre-packed image, instead of packing and copying
them again.
This complicates the upload code a bit (4 code paths due to messy PBO
handling). The plan is to make sub-bitmaps always packed, but some more
work is required to reach this point. The plan is to pack libass images
as well. Since this implies a copy, this will make it easy to refcount
the result.
(This is all targeted towards vo_opengl. Other VOs, vo_xv, vo_x11, and
vo_wayland in particular, will become less efficient. Although at least
vo_vdpau and vo_direct3d could be switched to the new method as well.)
2016-06-17 21:11:05 +00:00
|
|
|
res->packed = current->data;
|
|
|
|
res->packed_w = current->bound_w;
|
|
|
|
res->packed_h = current->bound_h;
|
2016-06-17 18:10:39 +00:00
|
|
|
res->format = SUBBITMAP_RGBA;
|
2013-12-11 22:15:29 +00:00
|
|
|
|
2014-10-21 09:37:32 +00:00
|
|
|
double video_par = 0;
|
2013-12-11 22:15:29 +00:00
|
|
|
if (priv->avctx->codec_id == AV_CODEC_ID_DVD_SUBTITLE &&
|
2015-12-19 19:04:31 +00:00
|
|
|
opts->stretch_dvd_subs)
|
|
|
|
{
|
2013-12-11 22:15:29 +00:00
|
|
|
// For DVD subs, try to keep the subtitle PAR at display PAR.
|
2015-12-19 19:04:31 +00:00
|
|
|
double par = priv->video_params.p_w / (double)priv->video_params.p_h;
|
sub: fix crash with certain uses of --vf=sub
If, for some reason, the subtitle renderer attempts to render a
subtitle before SD_CTRL_SET_VIDEO_PARAMS was called, it passed a
value calculated from invalid values. This can happen with --vf=sub
and --start. The crash happens if 1. there was a subtitle packet that
falls into the timestamp of the rendered video frame, 2. the playloop
hasn't informed the subtitle decoder about the video resolution yet
(normally unneeded, because that is used for weird corner cases only,
so this code is a bit fuzzy), and 3. something actually requests a
frame to be drawn from the subtitle renderer, like with vf_sub.
The actual crash was due to passing NaN as pixel aspect to libass,
which then created glyphs with ridiculous sizes, involving a few
integer overflows and unchecked mallocs.
The sd_lavc.c and sd_spu.c cases probably don't crash, but I'm not
sure, and it's better fix them anyway.
Not bothering with sd_spu.c, this crap is for compatibility and will
be removed soon.
Note that this would have been no problem, had the code checked whether
SD_CTRL_SET_VIDEO_PARAMS was actually called. This commit adds such a
check (although it basically checks after using the parameters).
Regression since 49caa0a7 and 633fde4a.
2014-01-26 17:58:40 +00:00
|
|
|
if (isnormal(par))
|
|
|
|
video_par = par;
|
2013-12-11 22:15:29 +00:00
|
|
|
}
|
2014-10-21 09:37:32 +00:00
|
|
|
if (priv->avctx->codec_id == AV_CODEC_ID_HDMV_PGS_SUBTITLE)
|
|
|
|
video_par = -1;
|
2015-07-18 12:36:17 +00:00
|
|
|
if (opts->stretch_image_subs)
|
|
|
|
d.ml = d.mr = d.mt = d.mb = 0;
|
2017-01-23 14:28:12 +00:00
|
|
|
int w = priv->avctx->width;
|
|
|
|
int h = priv->avctx->height;
|
2017-01-23 14:55:09 +00:00
|
|
|
if (w <= 0 || h <= 0 || opts->image_subs_video_res) {
|
2017-01-23 14:28:12 +00:00
|
|
|
w = priv->video_params.w;
|
|
|
|
h = priv->video_params.h;
|
2015-10-21 18:49:12 +00:00
|
|
|
}
|
2017-01-23 14:28:12 +00:00
|
|
|
if (current->src_w > w || current->src_h > h) {
|
sd_lavc: add a hack ontop of another hack to fix completely fucked file
Do what we do best in multimedia: add conflicting hacks on top of other
hacks, that fix a single sample, and may break other ones.
In this case, it only happens if the file is most likely already broken
(subtitle bounding boxes go outside of the subtitle "canvas"), so it's
OK. The file still looks broken (and, in fact, the file is completely
fucking broken), but you can see the subtitles.
But in summary, this is not actually something I should have bothered
about.
I noticed that MPlayer shows the subtitles "correctly", but this is only
because they have a hack that extends subtitles with small resolution to
a larger hardcoded resolution. This hack was removed from mpv, because
it broke some completely legitimate files. As another really funny fact,
MPlayer's default video output (vdpau) appears to display this file
correctly, but only because it handles narrow aspect ratios (that extend
the height instead of the width) incorrectly. It extends the height, but
leaves the video with 1:1 aspect ratio at the top. It seems to repeat
the last video line. (-vo xv and -vo gl show it correctly, i.e.
stretched like mpv, by the way.) For some reason, the sample file at
hand is extended with black, so the subtitles are rendered into a black
area below the video, which is almost reasonable. So, MPlayer may
display this file "correctly", but in fact it only happens to do so
because of 1 hack that breaks legitimate files, and 1 bug. What the
fuck.
Fixes: #7218 (sort of)
2019-12-03 21:33:45 +00:00
|
|
|
w = MPMAX(priv->video_params.w, current->src_w);
|
|
|
|
h = MPMAX(priv->video_params.h, current->src_h);
|
2017-01-23 14:28:12 +00:00
|
|
|
}
|
2019-05-22 21:15:34 +00:00
|
|
|
|
|
|
|
if (opts->sub_pos != 100 && opts->ass_style_override) {
|
|
|
|
int offset = (100 - opts->sub_pos) / 100.0 * h;
|
|
|
|
|
|
|
|
for (int n = 0; n < res->num_parts; n++) {
|
|
|
|
struct sub_bitmap *sub = &res->parts[n];
|
|
|
|
|
|
|
|
// Decide by heuristic whether this is a sub-title or something
|
|
|
|
// else (top-title, covering whole screen).
|
|
|
|
if (sub->y < h / 2)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Allow moving up the subtitle, but only until it clips.
|
|
|
|
sub->y = MPMAX(sub->y - offset, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-23 14:28:12 +00:00
|
|
|
osd_rescale_bitmaps(res, w, h, d, video_par);
|
2019-07-28 01:18:59 +00:00
|
|
|
|
|
|
|
if (opts->sub_scale != 1.0 && opts->ass_style_override) {
|
|
|
|
for (int n = 0; n < res->num_parts; n++) {
|
|
|
|
struct sub_bitmap *sub = &res->parts[n];
|
|
|
|
|
|
|
|
float shit = (opts->sub_scale - 1.0f) / 2;
|
|
|
|
|
|
|
|
// Fortunately VO isn't supposed to give a FUCKING FUCK about
|
|
|
|
// whether the sub might e.g. go outside of the screen.
|
|
|
|
sub->x -= sub->dw * shit;
|
|
|
|
sub->y -= sub->dh * shit;
|
|
|
|
sub->dw += sub->dw * shit * 2;
|
|
|
|
sub->dh += sub->dh * shit * 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-31 12:42:30 +00:00
|
|
|
}
|
|
|
|
|
2019-09-21 18:11:18 +00:00
|
|
|
static struct sd_times get_times(struct sd *sd, double pts)
|
|
|
|
{
|
|
|
|
struct sd_lavc_priv *priv = sd->priv;
|
|
|
|
struct sd_times res = { .start = MP_NOPTS_VALUE, .end = MP_NOPTS_VALUE };
|
|
|
|
|
|
|
|
if (pts == MP_NOPTS_VALUE)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
struct sub *current = get_current(priv, pts);
|
|
|
|
|
|
|
|
if (!current)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
res.start = current->pts;
|
|
|
|
res.end = current->endpts;
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
sub: don't potentially discard too many subtitles on seek
The accepts_packet packet callback is supposed to deal with subtitle
decoders which have only a small queue of current subtitle events (i.e.
sd_lavc.c), in case feeding it too many packets would discard events
that are still needed.
Normally, the number of subtitles that need to be preserved is estimated
by the rendering pts (get_bitmaps() argument). Rendering lags behind
decoding, so normally the rendering pts is smaller than the next video
frame pts, and we simply discard all subtitle events until the rendering
pts.
This breaks down in some annoying corner cases. One of them is seeking
backwards: the VO will still try to render the old PTS during seeks,
which passes a high PTS to the subtitle renderer, which in turn would
discard more subtitles than it should. There is a similar issue with
forward seeks. Add hacks to deal with those issues.
There should be a better way to deal with the essentially unknown
"rendering position", which is made worse by screenshots or rendering
with vf_sub. At the very least, we could handle seeks better, and e.g.
either force the VO not to re-render subs after seeks (ugly), or
introduce seek sequence numbers to distinguish attempts to render
earlier subtitles when a seek is done.
2016-08-14 18:27:37 +00:00
|
|
|
static bool accepts_packet(struct sd *sd, double min_pts)
|
2015-12-05 22:54:00 +00:00
|
|
|
{
|
|
|
|
struct sd_lavc_priv *priv = sd->priv;
|
|
|
|
|
|
|
|
double pts = priv->current_pts;
|
sub: don't potentially discard too many subtitles on seek
The accepts_packet packet callback is supposed to deal with subtitle
decoders which have only a small queue of current subtitle events (i.e.
sd_lavc.c), in case feeding it too many packets would discard events
that are still needed.
Normally, the number of subtitles that need to be preserved is estimated
by the rendering pts (get_bitmaps() argument). Rendering lags behind
decoding, so normally the rendering pts is smaller than the next video
frame pts, and we simply discard all subtitle events until the rendering
pts.
This breaks down in some annoying corner cases. One of them is seeking
backwards: the VO will still try to render the old PTS during seeks,
which passes a high PTS to the subtitle renderer, which in turn would
discard more subtitles than it should. There is a similar issue with
forward seeks. Add hacks to deal with those issues.
There should be a better way to deal with the essentially unknown
"rendering position", which is made worse by screenshots or rendering
with vf_sub. At the very least, we could handle seeks better, and e.g.
either force the VO not to re-render subs after seeks (ugly), or
introduce seek sequence numbers to distinguish attempts to render
earlier subtitles when a seek is done.
2016-08-14 18:27:37 +00:00
|
|
|
if (min_pts != MP_NOPTS_VALUE) {
|
|
|
|
// guard against bogus rendering PTS in the future.
|
|
|
|
if (pts == MP_NOPTS_VALUE || min_pts < pts)
|
|
|
|
pts = min_pts;
|
|
|
|
// Heuristic: we assume rendering cannot lag behind more than 1 second
|
|
|
|
// behind decoding.
|
|
|
|
if (pts + 1 < min_pts)
|
|
|
|
pts = min_pts;
|
|
|
|
}
|
|
|
|
|
2015-12-05 22:54:00 +00:00
|
|
|
int last_needed = -1;
|
|
|
|
for (int n = 0; n < MAX_QUEUE; n++) {
|
|
|
|
struct sub *sub = &priv->subs[n];
|
|
|
|
if (!sub->valid)
|
|
|
|
continue;
|
|
|
|
if (pts == MP_NOPTS_VALUE ||
|
|
|
|
((sub->pts == MP_NOPTS_VALUE || sub->pts >= pts) ||
|
|
|
|
(sub->endpts == MP_NOPTS_VALUE || pts < sub->endpts)))
|
|
|
|
{
|
|
|
|
last_needed = n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// We can accept a packet if it wouldn't overflow the fixed subtitle queue.
|
|
|
|
// We assume that get_bitmaps() never decreases the PTS.
|
|
|
|
return last_needed + 1 < MAX_QUEUE;
|
|
|
|
}
|
|
|
|
|
2013-06-01 17:44:12 +00:00
|
|
|
static void reset(struct sd *sd)
|
2012-08-16 15:21:21 +00:00
|
|
|
{
|
2013-06-01 17:44:12 +00:00
|
|
|
struct sd_lavc_priv *priv = sd->priv;
|
2012-08-31 12:42:30 +00:00
|
|
|
|
2014-08-14 21:45:58 +00:00
|
|
|
for (int n = 0; n < MAX_QUEUE; n++)
|
|
|
|
clear_sub(&priv->subs[n]);
|
2012-08-16 15:21:21 +00:00
|
|
|
// lavc might not do this right for all codecs; may need close+reopen
|
2012-08-31 12:42:30 +00:00
|
|
|
avcodec_flush_buffers(priv->avctx);
|
2015-12-05 22:54:00 +00:00
|
|
|
|
|
|
|
priv->current_pts = MP_NOPTS_VALUE;
|
2010-07-10 13:45:09 +00:00
|
|
|
}
|
2012-08-16 15:21:21 +00:00
|
|
|
|
2013-06-01 17:44:12 +00:00
|
|
|
static void uninit(struct sd *sd)
|
2012-08-16 15:21:21 +00:00
|
|
|
{
|
2013-06-01 17:44:12 +00:00
|
|
|
struct sd_lavc_priv *priv = sd->priv;
|
2012-08-31 12:42:30 +00:00
|
|
|
|
2014-06-17 22:18:37 +00:00
|
|
|
for (int n = 0; n < MAX_QUEUE; n++)
|
|
|
|
clear_sub(&priv->subs[n]);
|
2017-07-16 10:51:48 +00:00
|
|
|
avcodec_free_context(&priv->avctx);
|
2012-08-31 12:42:30 +00:00
|
|
|
talloc_free(priv);
|
2012-08-16 15:21:21 +00:00
|
|
|
}
|
|
|
|
|
2015-12-05 22:55:35 +00:00
|
|
|
static int compare_seekpoint(const void *pa, const void *pb)
|
2015-12-05 22:55:22 +00:00
|
|
|
{
|
2015-12-05 22:55:35 +00:00
|
|
|
const struct seekpoint *a = pa, *b = pb;
|
|
|
|
return a->pts == b->pts ? 0 : (a->pts < b->pts ? -1 : +1);
|
2015-12-05 22:55:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
2016-02-04 21:44:18 +00:00
|
|
|
int direction = (movement > 0 ? 1 : -1) * !!movement;
|
2015-12-05 22:55:22 +00:00
|
|
|
|
2016-02-04 21:44:18 +00:00
|
|
|
if (priv->num_seekpoints == 0)
|
2015-12-05 22:55:22 +00:00
|
|
|
return MP_NOPTS_VALUE;
|
|
|
|
|
2015-12-05 22:55:35 +00:00
|
|
|
qsort(priv->seekpoints, priv->num_seekpoints, sizeof(priv->seekpoints[0]),
|
|
|
|
compare_seekpoint);
|
2015-12-05 22:55:22 +00:00
|
|
|
|
2016-02-04 21:44:18 +00:00
|
|
|
do {
|
2015-12-05 22:55:22 +00:00
|
|
|
int closest = -1;
|
|
|
|
double closest_time = 0;
|
2015-12-05 22:55:35 +00:00
|
|
|
for (int i = 0; i < priv->num_seekpoints; i++) {
|
|
|
|
struct seekpoint *p = &priv->seekpoints[i];
|
|
|
|
double start = p->pts;
|
2015-12-05 22:55:22 +00:00
|
|
|
if (direction < 0) {
|
2015-12-05 22:55:35 +00:00
|
|
|
double end = p->endpts == MP_NOPTS_VALUE ? INFINITY : p->endpts;
|
2015-12-05 22:55:22 +00:00
|
|
|
if (end < target) {
|
|
|
|
if (closest < 0 || end > closest_time) {
|
|
|
|
closest = i;
|
|
|
|
closest_time = end;
|
|
|
|
}
|
|
|
|
}
|
2016-02-04 21:44:18 +00:00
|
|
|
} else if (direction > 0) {
|
2015-12-05 22:55:22 +00:00
|
|
|
if (start > target) {
|
|
|
|
if (closest < 0 || start < closest_time) {
|
|
|
|
closest = i;
|
|
|
|
closest_time = start;
|
|
|
|
}
|
|
|
|
}
|
2016-02-04 21:44:18 +00:00
|
|
|
} else {
|
|
|
|
if (start < target) {
|
|
|
|
if (closest < 0 || start >= closest_time) {
|
|
|
|
closest = i;
|
|
|
|
closest_time = start;
|
|
|
|
}
|
|
|
|
}
|
2015-12-05 22:55:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (closest < 0)
|
|
|
|
break;
|
|
|
|
target = closest_time + direction;
|
|
|
|
best = closest;
|
|
|
|
movement -= direction;
|
2016-02-04 21:44:18 +00:00
|
|
|
} while (movement);
|
2015-12-05 22:55:22 +00:00
|
|
|
|
2017-12-29 14:39:38 +00:00
|
|
|
return best < 0 ? now : priv->seekpoints[best].pts;
|
2015-12-05 22:55:22 +00:00
|
|
|
}
|
|
|
|
|
2013-11-01 12:15:59 +00:00
|
|
|
static int control(struct sd *sd, enum sd_ctrl cmd, void *arg)
|
|
|
|
{
|
|
|
|
struct sd_lavc_priv *priv = sd->priv;
|
|
|
|
switch (cmd) {
|
2015-12-05 22:55:22 +00:00
|
|
|
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;
|
|
|
|
}
|
2013-11-01 12:15:59 +00:00
|
|
|
case SD_CTRL_SET_VIDEO_PARAMS:
|
|
|
|
priv->video_params = *(struct mp_image_params *)arg;
|
|
|
|
return CONTROL_OK;
|
|
|
|
default:
|
|
|
|
return CONTROL_UNKNOWN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-16 15:21:21 +00:00
|
|
|
const struct sd_functions sd_lavc = {
|
2013-06-03 19:49:39 +00:00
|
|
|
.name = "lavc",
|
2012-08-16 15:21:21 +00:00
|
|
|
.init = init,
|
|
|
|
.decode = decode,
|
2012-08-31 12:42:30 +00:00
|
|
|
.get_bitmaps = get_bitmaps,
|
2019-09-21 18:11:18 +00:00
|
|
|
.get_times = get_times,
|
2015-12-05 22:54:00 +00:00
|
|
|
.accepts_packet = accepts_packet,
|
2013-11-01 12:15:59 +00:00
|
|
|
.control = control,
|
2012-08-16 15:21:21 +00:00
|
|
|
.reset = reset,
|
|
|
|
.uninit = uninit,
|
|
|
|
};
|