diff options
Diffstat (limited to 'sub/sd_lavc.c')
-rw-r--r-- | sub/sd_lavc.c | 131 |
1 files changed, 120 insertions, 11 deletions
diff --git a/sub/sd_lavc.c b/sub/sd_lavc.c index a4eafff429..1da33ffca1 100644 --- a/sub/sd_lavc.c +++ b/sub/sd_lavc.c @@ -19,6 +19,7 @@ #include <libavcodec/avcodec.h> +#include "talloc.h" #include "mp_msg.h" #include "libmpdemux/stheader.h" #include "sd.h" @@ -26,8 +27,17 @@ // Current code still pushes subs directly to global spudec #include "sub.h" -static void avsub_to_spudec(AVSubtitleRect **rects, int num_rects, - double pts, double endpts) +struct sd_lavc_priv { + AVCodecContext *avctx; + int count; + struct sub_bitmap *inbitmaps; + struct sub_bitmap *outbitmaps; + bool bitmaps_changed; + double endpts; +}; + +static void old_avsub_to_spudec(AVSubtitleRect **rects, int num_rects, + double pts, double endpts) { int i, xmin = INT_MAX, ymin = INT_MAX, xmax = INT_MIN, ymax = INT_MIN; struct spu_packet_t *packet; @@ -69,6 +79,9 @@ static void avsub_to_spudec(AVSubtitleRect **rects, int num_rects, static int init(struct sh_sub *sh, struct osd_state *osd) { + if (sh->initialized) + return 0; + struct sd_lavc_priv *priv = talloc_zero(NULL, struct sd_lavc_priv); enum CodecID cid = CODEC_ID_NONE; switch (sh->type) { case 'b': @@ -77,6 +90,8 @@ static int init(struct sh_sub *sh, struct osd_state *osd) cid = CODEC_ID_HDMV_PGS_SUBTITLE; break; case 'x': cid = CODEC_ID_XSUB; break; + case 'v': + cid = CODEC_ID_DVD_SUBTITLE; break; } AVCodecContext *ctx = NULL; AVCodec *sub_codec = avcodec_find_decoder(cid); @@ -85,25 +100,41 @@ static int init(struct sh_sub *sh, struct osd_state *osd) ctx = avcodec_alloc_context3(sub_codec); if (!ctx) goto error; + ctx->extradata_size = sh->extradata_len; + ctx->extradata = sh->extradata; if (avcodec_open2(ctx, sub_codec, NULL) < 0) goto error; - sh->context = ctx; + priv->avctx = ctx; + sh->context = priv; return 0; error: mp_msg(MSGT_SUBREADER, MSGL_ERR, "Could not open libavcodec subtitle decoder\n"); av_free(ctx); + talloc_free(priv); return -1; } +static void clear(struct sd_lavc_priv *priv) +{ + priv->count = 0; + talloc_free(priv->inbitmaps); + talloc_free(priv->outbitmaps); + priv->inbitmaps = priv->outbitmaps = NULL; + priv->bitmaps_changed = true; + priv->endpts = MP_NOPTS_VALUE; +} + static void decode(struct sh_sub *sh, struct osd_state *osd, void *data, int data_len, double pts, double duration) { - AVCodecContext *ctx = sh->context; + struct sd_lavc_priv *priv = sh->context; + AVCodecContext *ctx = priv->avctx; AVSubtitle sub; AVPacket pkt; + clear(priv); av_init_packet(&pkt); pkt.data = data; pkt.size = data_len; @@ -127,10 +158,37 @@ static void decode(struct sh_sub *sh, struct osd_state *osd, void *data, if (sub.num_rects > 0) { switch (sub.rects[0]->type) { case SUBTITLE_BITMAP: - if (!vo_spudec) - vo_spudec = spudec_new_scaled(NULL, ctx->width, ctx->height, NULL, 0); - avsub_to_spudec(sub.rects, sub.num_rects, pts, endpts); - vo_osd_changed(OSDTYPE_SPU); + // Assume resolution heuristics only work for PGS and DVB + if (!osd->support_rgba || sh->type != 'p' && sh->type != 'b') { + if (!vo_spudec) + vo_spudec = spudec_new_scaled(NULL, ctx->width, ctx->height, + NULL, 0); + old_avsub_to_spudec(sub.rects, sub.num_rects, pts, endpts); + vo_osd_changed(OSDTYPE_SPU); + break; + } + priv->inbitmaps = talloc_array(priv, struct sub_bitmap, + sub.num_rects); + for (int i = 0; i < sub.num_rects; i++) { + struct AVSubtitleRect *r = sub.rects[i]; + struct sub_bitmap *b = &priv->inbitmaps[i]; + uint32_t *outbmp = talloc_size(priv->inbitmaps, + r->w * r->h * 4); + b->bitmap = outbmp; + b->w = r->w; + b->h = r->h; + b->x = r->x; + b->y = r->y; + uint8_t *inbmp = r->pict.data[0]; + uint32_t *palette = (uint32_t *) r->pict.data[1]; + for (int y = 0; y < r->h; y++) { + for (int x = 0; x < r->w; x++) + *outbmp++ = palette[*inbmp++]; + inbmp += r->pict.linesize[0] - r->w; + }; + } + priv->count = sub.num_rects; + priv->endpts = endpts; break; default: mp_msg(MSGT_SUBREADER, MSGL_ERR, "sd_lavc: unsupported subtitle " @@ -141,21 +199,72 @@ static void decode(struct sh_sub *sh, struct osd_state *osd, void *data, avsubtitle_free(&sub); } +static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd, + struct sub_bitmaps *res) +{ + struct sd_lavc_priv *priv = sh->context; + + if (priv->endpts != MP_NOPTS_VALUE && (osd->sub_pts >= priv->endpts || + osd->sub_pts < priv->endpts - 300)) + clear(priv); + if (!osd->support_rgba) + return; + if (priv->bitmaps_changed && priv->count > 0) + priv->outbitmaps = talloc_memdup(priv, priv->inbitmaps, + talloc_get_size(priv->inbitmaps)); + bool pos_changed = false; + // Hope that PGS subs set these and 720/576 works for dvb subs + int inw = priv->avctx->width; + if (!inw) + inw = 720; + int inh = priv->avctx->height; + if (!inh) + inh = 576; + struct mp_eosd_res *d = &osd->dim; + double xscale = (double) (d->w - d->ml - d->mr) / inw; + double yscale = (double) (d->h - d->mt - d->mb) / inh; + for (int i = 0; i < priv->count; i++) { + struct sub_bitmap *bi = &priv->inbitmaps[i]; + struct sub_bitmap *bo = &priv->outbitmaps[i]; +#define SET(var, val) pos_changed |= var != (int)(val); var = (val) + SET(bo->x, bi->x * xscale + d->ml); + SET(bo->y, bi->y * yscale + d->mt); + SET(bo->dw, bi->w * xscale); + SET(bo->dh, bi->h * yscale); + } + res->parts = priv->outbitmaps; + res->part_count = priv->count; + if (priv->bitmaps_changed) + res->bitmap_id = ++res->bitmap_pos_id; + else if (pos_changed) + res->bitmap_pos_id++; + priv->bitmaps_changed = false; + res->type = SUBBITMAP_RGBA; + res->scaled = xscale != 1 || yscale != 1; +} + static void reset(struct sh_sub *sh, struct osd_state *osd) { + struct sd_lavc_priv *priv = sh->context; + + clear(priv); // lavc might not do this right for all codecs; may need close+reopen - avcodec_flush_buffers(sh->context); + avcodec_flush_buffers(priv->avctx); } static void uninit(struct sh_sub *sh) { - avcodec_close(sh->context); - av_free(sh->context); + struct sd_lavc_priv *priv = sh->context; + + avcodec_close(priv->avctx); + av_free(priv->avctx); + talloc_free(priv); } const struct sd_functions sd_lavc = { .init = init, .decode = decode, + .get_bitmaps = get_bitmaps, .reset = reset, .switch_off = reset, .uninit = uninit, |