summaryrefslogtreecommitdiffstats
path: root/sub/sd_spu.c
blob: 3a7bf09127d8ab61d571222012bae16c8f4685ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 * This file is part of mpv.
 *
 * mpv is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * mpv is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with mpv.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdlib.h>
#include <assert.h>

#include "talloc.h"
#include "options/options.h"
#include "video/mp_image.h"
#include "sd.h"
#include "spudec.h"

struct sd_spu_priv {
    void *spudec;
    struct mp_image_params video_params;
};

static bool is_dvd_sub(const char *t)
{
    return t && (strcmp(t, "dvd_subtitle") == 0 ||
                 strcmp(t, "dvd_subtitle_mpg") == 0);
}

static bool supports_format(const char *format)
{
    return is_dvd_sub(format);
}

static int init(struct sd *sd)
{
    void *spudec = spudec_new_scaled(sd->log, sd->sub_video_w, sd->sub_video_h,
                                     sd->extradata, sd->extradata_len);
    if (!spudec)
        return -1;
    struct sd_spu_priv *priv = talloc_zero(NULL, struct sd_spu_priv);
    priv->spudec = spudec;
    sd->priv = priv;
    return 0;
}

static void decode(struct sd *sd, struct demux_packet *packet)
{
    struct sd_spu_priv *priv = sd->priv;

    if (packet->pts < 0 || packet->len == 0)
        return;

    spudec_assemble(priv->spudec, packet->buffer, packet->len,
                    packet->pts * 90000);
}

static void get_bitmaps(struct sd *sd, struct mp_osd_res d, double pts,
                        struct sub_bitmaps *res)
{
    struct MPOpts *opts = sd->opts;
    struct sd_spu_priv *priv = sd->priv;

    spudec_set_forced_subs_only(priv->spudec, opts->forced_subs_only);
    spudec_heartbeat(priv->spudec, pts * 90000);

    if (spudec_visible(priv->spudec)) {
        double xscale = 1;
        double yscale = 1;
        if (opts->stretch_dvd_subs) {
            // For DVD subs, try to keep the subtitle PAR at display PAR.
            double video_par =
                  (priv->video_params.d_w / (double)priv->video_params.d_h)
                / (priv->video_params.w   / (double)priv->video_params.h);
            if (video_par > 1.0) {
                xscale /= video_par;
            } else {
                yscale *= video_par;
            }
        }
        spudec_get_indexed(priv->spudec, &d, xscale, yscale, res);
    }
}

static void reset(struct sd *sd)
{
    struct sd_spu_priv *priv = sd->priv;

    spudec_reset(priv->spudec);
}

static void uninit(struct sd *sd)
{
    struct sd_spu_priv *priv = sd->priv;

    spudec_free(priv->spudec);
    talloc_free(priv);
}

static int control(struct sd *sd, enum sd_ctrl cmd, void *arg)
{
    struct sd_spu_priv *priv = sd->priv;
    switch (cmd) {
    case SD_CTRL_SET_VIDEO_PARAMS:
        priv->video_params = *(struct mp_image_params *)arg;
        return CONTROL_OK;
    default:
        return CONTROL_UNKNOWN;
    }
}

const struct sd_functions sd_spu = {
    .name = "spu",
    .supports_format = supports_format,
    .init = init,
    .decode = decode,
    .get_bitmaps = get_bitmaps,
    .control = control,
    .reset = reset,
    .uninit = uninit,
};