summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUoti Urpala <uau@mplayer2.org>2012-08-31 15:42:30 +0300
committerwm4 <wm4@nowhere>2012-09-18 21:07:30 +0200
commit1959ba006ce1a4591f3dcd5093901993e3fdda5f (patch)
tree93fcd19aa07e47cddb875b1ca714ae69a453c8e8
parentae9c3d530c55e86eb54d8cf23a23c5ce6301ec6e (diff)
downloadmpv-1959ba006ce1a4591f3dcd5093901993e3fdda5f.tar.bz2
mpv-1959ba006ce1a4591f3dcd5093901993e3fdda5f.tar.xz
subs, vo_vdpau: support RGBA color for PGS subtitles
Support passing bitmap subtitles to VOs in full RGBA color, and implement this for libavcodec-decoded subtitle formats on decoding side and vo_vdpau on display side. Currently this is enabled for PGS (blu-ray) and DVB subtitles. VDPAU seems to have sampling issues similar to known GL ones when drawing a sub-rectangle from a larger texture with scaling, where adjacent pixels outside the specified source rectangle affect the result. As the bitmap subtitles may be scaled, add padding support to the bitmap packer code. In principle, this could be used for colored DVD subtitles too. However, the libavcodec DVD decoder lacks parts of the resolution and palette handling that are present in spudec.c. Conflicts: libvo/vo_gl.c sub/dec_sub.h sub/sd_lavc.c
-rw-r--r--libmpcodecs/vf_ass.c1
-rw-r--r--libmpcodecs/vf_vo.c1
-rw-r--r--libmpcodecs/vfcap.h1
-rw-r--r--libvo/bitmap_packer.c48
-rw-r--r--libvo/bitmap_packer.h8
-rw-r--r--libvo/vo_vdpau.c111
-rw-r--r--sub/dec_sub.c3
-rw-r--r--sub/dec_sub.h19
-rw-r--r--sub/sd_ass.c1
-rw-r--r--sub/sd_lavc.c131
-rw-r--r--sub/sub.h1
11 files changed, 273 insertions, 52 deletions
diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c
index ad4671fe57..f0b2e6ab77 100644
--- a/libmpcodecs/vf_ass.c
+++ b/libmpcodecs/vf_ass.c
@@ -364,6 +364,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
osd->normal_scale = vf->priv->aspect_correction;
osd->vsfilter_scale = 1;
osd->sub_pts = pts - osd->sub_offset;
+ osd->support_rgba = false;
struct sub_bitmaps b;
sub_get_bitmaps(osd, &b);
images = b.imgs;
diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c
index 3aec40cd15..862cd63492 100644
--- a/libmpcodecs/vf_vo.c
+++ b/libmpcodecs/vf_vo.c
@@ -119,6 +119,7 @@ static int control(struct vf_instance *vf, int request, void *data)
}
case VFCTRL_DRAW_EOSD: {
struct osd_state *osd = data;
+ osd->support_rgba = vf->default_caps & VFCAP_EOSD_RGBA;
osd->dim = (struct mp_eosd_res){0};
if (!video_out->config_ok ||
vo_control(video_out, VOCTRL_GET_EOSD_RES, &osd->dim) != true)
diff --git a/libmpcodecs/vfcap.h b/libmpcodecs/vfcap.h
index 86c6f6e477..aef75840ae 100644
--- a/libmpcodecs/vfcap.h
+++ b/libmpcodecs/vfcap.h
@@ -48,5 +48,6 @@
#define VOCAP_NOSLICES 0x8000
#define VFCAP_OSD_FILTER 0x10000 // OSD is drawn in filter chain
#define VFCAP_EOSD_FILTER 0x20000 // EOSD is drawn in filter chain
+#define VFCAP_EOSD_RGBA 0x40000
#endif /* MPLAYER_VFCAP_H */
diff --git a/libvo/bitmap_packer.c b/libvo/bitmap_packer.c
index 2ae8a1eee0..eedc2e2242 100644
--- a/libvo/bitmap_packer.c
+++ b/libvo/bitmap_packer.c
@@ -28,6 +28,7 @@
#include "mp_msg.h"
#include "mpcommon.h"
#include "sub/ass_mp.h"
+#include "sub/dec_sub.h"
#define HEIGHT_SORT_BITS 4
@@ -55,7 +56,7 @@ static int size_index(int s)
* free rectangle with corners (13, 20)-(w, 50) is filled recursively.
*/
static int pack_rectangles(struct pos *in, struct pos *out, int num_rects,
- int w, int h, int *scratch)
+ int w, int h, int *scratch, int *used_width)
{
int bins[16 << HEIGHT_SORT_BITS];
int sizes[16 << HEIGHT_SORT_BITS] = { 0 };
@@ -100,11 +101,12 @@ static int pack_rectangles(struct pos *in, struct pos *out, int num_rects,
s.x = right;
maxy = FFMAX(maxy, bottom);
}
+ *used_width = FFMAX(*used_width, s.x);
if (maxy > 0)
s.bottom = maxy;
}
}
- return num_rects ? -1 : 0;
+ return num_rects ? -1 : y;
}
int packer_pack(struct bitmap_packer *packer)
@@ -115,7 +117,7 @@ int packer_pack(struct bitmap_packer *packer)
struct pos *in = packer->in;
int xmax = 0, ymax = 0;
for (int i = 0; i < packer->count; i++) {
- if (in[i].x == 0 || in[i].y == 0)
+ if (in[i].x <= packer->padding || in[i].y <= packer->padding)
in[i] = (struct pos){0, 0};
if (in[i].x < 0 || in [i].x > 65535 || in[i].y < 0 || in[i].y > 65535) {
mp_msg(MSGT_VO, MSGL_FATAL, "Invalid OSD / subtitle bitmap size\n");
@@ -124,20 +126,33 @@ int packer_pack(struct bitmap_packer *packer)
xmax = FFMAX(xmax, in[i].x);
ymax = FFMAX(ymax, in[i].y);
}
+ xmax = FFMAX(0, xmax - packer->padding);
+ ymax = FFMAX(0, ymax - packer->padding);
if (xmax > packer->w)
packer->w = 1 << av_log2(xmax - 1) + 1;
if (ymax > packer->h)
packer->h = 1 << av_log2(ymax - 1) + 1;
while (1) {
- if (pack_rectangles(in, packer->result, packer->count, packer->w,
- packer->h, packer->scratch) >= 0)
+ int used_width = 0;
+ int y = pack_rectangles(in, packer->result, packer->count,
+ packer->w + packer->padding,
+ packer->h + packer->padding,
+ packer->scratch, &used_width);
+ if (y >= 0) {
+ // No padding at edges
+ packer->used_width = FFMIN(used_width, packer->w);
+ packer->used_height = FFMIN(y, packer->h);
return packer->w != w_orig || packer->h != h_orig;
+ }
if (packer->w <= packer->h && packer->w != packer->w_max)
packer->w = FFMIN(packer->w * 2, packer->w_max);
else if (packer->h != packer->h_max)
packer->h = FFMIN(packer->h * 2, packer->h_max);
- else
+ else {
+ packer->w = w_orig;
+ packer->h = h_orig;
return -1;
+ }
}
}
@@ -156,8 +171,8 @@ void packer_set_size(struct bitmap_packer *packer, int size)
packer->asize + 16);
}
-int packer_pack_from_assimg(struct bitmap_packer *packer,
- struct ass_image *imglist)
+static int packer_pack_from_assimg(struct bitmap_packer *packer,
+ struct ass_image *imglist)
{
int count = 0;
struct ass_image *img = imglist;
@@ -172,3 +187,20 @@ int packer_pack_from_assimg(struct bitmap_packer *packer,
packer->count = count;
return packer_pack(packer);
}
+
+int packer_pack_from_subbitmaps(struct bitmap_packer *packer,
+ struct sub_bitmaps *b, int padding_pixels)
+{
+ packer->padding = 0;
+ packer->count = 0;
+ if (b->type == SUBBITMAP_EMPTY)
+ return 0;
+ if (b->type == SUBBITMAP_LIBASS)
+ return packer_pack_from_assimg(packer, b->imgs);
+ packer->padding = padding_pixels;
+ packer_set_size(packer, b->part_count);
+ int a = packer->padding;
+ for (int i = 0; i < b->part_count; i++)
+ packer->in[i] = (struct pos){b->parts[i].w + a, b->parts[i].h + a};
+ return packer_pack(packer);
+}
diff --git a/libvo/bitmap_packer.h b/libvo/bitmap_packer.h
index 45b6fbc4ae..c7c377cbd0 100644
--- a/libvo/bitmap_packer.h
+++ b/libvo/bitmap_packer.h
@@ -11,9 +11,12 @@ struct bitmap_packer {
int h;
int w_max;
int h_max;
+ int padding;
int count;
struct pos *in;
struct pos *result;
+ int used_width;
+ int used_height;
// internal
int *scratch;
@@ -21,6 +24,7 @@ struct bitmap_packer {
};
struct ass_image;
+struct sub_bitmaps;
/* Reallocate packer->in for at least to desired number of items.
* Also sets packer->count to the same value.
@@ -41,7 +45,7 @@ int packer_pack(struct bitmap_packer *packer);
* packer->in will be reallocated if needed and filled from the
* given image list.
*/
-int packer_pack_from_assimg(struct bitmap_packer *packer,
- struct ass_image *imglist);
+int packer_pack_from_subbitmaps(struct bitmap_packer *packer,
+ struct sub_bitmaps *b, int padding_pixels);
#endif
diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c
index 922ec24201..594829b394 100644
--- a/libvo/vo_vdpau.c
+++ b/libvo/vo_vdpau.c
@@ -172,6 +172,7 @@ struct vdpctx {
// EOSD
struct eosd_bitmap_surface {
+ VdpRGBAFormat format;
VdpBitmapSurface surface;
uint32_t max_width;
uint32_t max_height;
@@ -1007,16 +1008,35 @@ static void generate_eosd(struct vo *vo, mp_eosd_images_t *imgs)
vc->eosd_render_count = 0;
- if (!imgs->imgs)
- return; // There's nothing to render!
+ if (imgs->type == SUBBITMAP_EMPTY)
+ return;
if (imgs->bitmap_id == vc->bitmap_id)
goto eosd_skip_upload;
need_upload = true;
+ VdpRGBAFormat format;
+ int format_size;
+ switch (imgs->type) {
+ case SUBBITMAP_LIBASS:
+ format = VDP_RGBA_FORMAT_A8;
+ format_size = 1;
+ break;
+ case SUBBITMAP_RGBA:
+ format = VDP_RGBA_FORMAT_B8G8R8A8;
+ format_size = 4;
+ break;
+ default:
+ abort();
+ };
+ if (sfc->format != format) {
+ talloc_free(sfc->packer);
+ sfc->packer = NULL;
+ };
+ sfc->format = format;
if (!sfc->packer)
- sfc->packer = make_packer(vo, VDP_RGBA_FORMAT_A8);
- int r = packer_pack_from_assimg(sfc->packer, imgs->imgs);
+ sfc->packer = make_packer(vo, format);
+ int r = packer_pack_from_subbitmaps(sfc->packer, imgs, imgs->scaled);
if (r < 0) {
mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] EOSD bitmaps do not fit on "
"a surface with the maximum supported size\n");
@@ -1028,13 +1048,21 @@ static void generate_eosd(struct vo *vo, mp_eosd_images_t *imgs)
}
mp_msg(MSGT_VO, MSGL_V, "[vdpau] Allocating a %dx%d surface for "
"EOSD bitmaps.\n", sfc->packer->w, sfc->packer->h);
- vdp_st = vdp->bitmap_surface_create(vc->vdp_device, VDP_RGBA_FORMAT_A8,
+ vdp_st = vdp->bitmap_surface_create(vc->vdp_device, format,
sfc->packer->w, sfc->packer->h,
true, &sfc->surface);
if (vdp_st != VDP_STATUS_OK)
sfc->surface = VDP_INVALID_HANDLE;
CHECK_ST_WARNING("EOSD: error when creating surface");
}
+ if (imgs->scaled) {
+ char zeros[sfc->packer->used_width * format_size];
+ memset(zeros, 0, sizeof(zeros));
+ vdp_st = vdp->bitmap_surface_put_bits_native(sfc->surface,
+ &(const void *){zeros}, &(uint32_t){0},
+ &(VdpRect){0, 0, sfc->packer->used_width,
+ sfc->packer->used_height});
+ }
eosd_skip_upload:
if (sfc->surface == VDP_INVALID_HANDLE)
@@ -1046,31 +1074,54 @@ eosd_skip_upload:
* sizeof(*vc->eosd_targets));
}
- int i = 0;
- for (ASS_Image *p = imgs->imgs; p; p = p->next, i++) {
- if (p->w == 0 || p->h == 0)
- continue;
- struct eosd_target *target = &vc->eosd_targets[vc->eosd_render_count];
- int x = sfc->packer->result[i].x;
- int y = sfc->packer->result[i].y;
- target->source = (VdpRect){x, y, x + p->w, y + p->h};
- if (need_upload) {
- vdp_st = vdp->
- bitmap_surface_put_bits_native(sfc->surface,
- (const void *) &p->bitmap,
- &p->stride, &target->source);
- CHECK_ST_WARNING("EOSD: putbits failed");
+ if (imgs->type == SUBBITMAP_LIBASS) {
+ int i = 0;
+ for (ASS_Image *p = imgs->imgs; p; p = p->next, i++) {
+ if (p->w == 0 || p->h == 0)
+ continue;
+ struct eosd_target *target = vc->eosd_targets +
+ vc->eosd_render_count;
+ int x = sfc->packer->result[i].x;
+ int y = sfc->packer->result[i].y;
+ target->source = (VdpRect){x, y, x + p->w, y + p->h};
+ if (need_upload) {
+ vdp_st = vdp->
+ bitmap_surface_put_bits_native(sfc->surface,
+ (const void *) &p->bitmap,
+ &p->stride, &target->source);
+ CHECK_ST_WARNING("EOSD: putbits failed");
+ }
+ // Render dest, color, etc.
+ target->color.alpha = 1.0 - ((p->color >> 0) & 0xff) / 255.0;
+ target->color.blue = ((p->color >> 8) & 0xff) / 255.0;
+ target->color.green = ((p->color >> 16) & 0xff) / 255.0;
+ target->color.red = ((p->color >> 24) & 0xff) / 255.0;
+ target->dest.x0 = p->dst_x;
+ target->dest.y0 = p->dst_y;
+ target->dest.x1 = p->w + p->dst_x;
+ target->dest.y1 = p->h + p->dst_y;
+ vc->eosd_render_count++;
+ }
+ } else {
+ for (int i = 0 ;i < sfc->packer->count; i++) {
+ struct sub_bitmap *b = &imgs->parts[i];
+ struct eosd_target *target = vc->eosd_targets +
+ vc->eosd_render_count;
+ int x = sfc->packer->result[i].x;
+ int y = sfc->packer->result[i].y;
+ target->source = (VdpRect){x, y, x + b->w, y + b->h};
+ if (need_upload) {
+ vdp_st = vdp->
+ bitmap_surface_put_bits_native(sfc->surface,
+ &(const void *){b->bitmap},
+ &(uint32_t){b->w * 4},
+ &target->source);
+ CHECK_ST_WARNING("EOSD: putbits failed");
+ }
+ target->color = (VdpColor){1, 1, 1, 1};
+ target->dest = (VdpRect){b->x, b->y, b->x + b->dw, b->y + b->dh};
+ vc->eosd_render_count++;
}
- // Render dest, color, etc.
- target->color.alpha = 1.0 - ((p->color >> 0) & 0xff) / 255.0;
- target->color.blue = ((p->color >> 8) & 0xff) / 255.0;
- target->color.green = ((p->color >> 16) & 0xff) / 255.0;
- target->color.red = ((p->color >> 24) & 0xff) / 255.0;
- target->dest.x0 = p->dst_x;
- target->dest.y0 = p->dst_y;
- target->dest.x1 = p->w + p->dst_x;
- target->dest.y1 = p->h + p->dst_y;
- vc->eosd_render_count++;
}
vc->bitmap_id = imgs->bitmap_id;
vc->bitmap_pos_id = imgs->bitmap_pos_id;
@@ -1529,7 +1580,7 @@ static int query_format(uint32_t format)
{
int default_flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW
| VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD | VFCAP_EOSD
- | VFCAP_EOSD_UNSCALED | VFCAP_FLIP;
+ | VFCAP_EOSD_UNSCALED | VFCAP_EOSD_RGBA | VFCAP_FLIP;
switch (format) {
case IMGFMT_YV12:
case IMGFMT_I420:
diff --git a/sub/dec_sub.c b/sub/dec_sub.c
index 3278c10d85..4a048b27a6 100644
--- a/sub/dec_sub.c
+++ b/sub/dec_sub.c
@@ -62,7 +62,8 @@ void sub_get_bitmaps(struct osd_state *osd, struct sub_bitmaps *res)
{
struct MPOpts *opts = osd->opts;
- *res = (struct sub_bitmaps){ .bitmap_id = osd->bitmap_id,
+ *res = (struct sub_bitmaps){ .type = SUBBITMAP_EMPTY,
+ .bitmap_id = osd->bitmap_id,
.bitmap_pos_id = osd->bitmap_pos_id };
if (!opts->sub_visibility || !osd->sh_sub || !osd->sh_sub->active) {
/* Change ID in case we just switched from visible subtitles
diff --git a/sub/dec_sub.h b/sub/dec_sub.h
index efbfdc9ce7..c71a2348aa 100644
--- a/sub/dec_sub.h
+++ b/sub/dec_sub.h
@@ -5,13 +5,32 @@ struct sh_sub;
struct osd_state;
struct ass_track;
+enum sub_bitmap_type {
+ SUBBITMAP_EMPTY,
+ SUBBITMAP_LIBASS,
+ SUBBITMAP_RGBA,
+};
+
typedef struct mp_eosd_res {
int w, h; // screen dimensions, including black borders
int mt, mb, ml, mr; // borders (top, bottom, left, right)
} mp_eosd_res_t;
typedef struct sub_bitmaps {
+ enum sub_bitmap_type type;
+
struct ass_image *imgs;
+
+ struct sub_bitmap {
+ int w, h;
+ int x, y;
+ // Note: not clipped, going outside the screen area is allowed
+ int dw, dh;
+ void *bitmap;
+ } *parts;
+ int part_count;
+
+ bool scaled;
int bitmap_id, bitmap_pos_id;
} mp_eosd_images_t;
diff --git a/sub/sd_ass.c b/sub/sd_ass.c
index 37c220a4b5..9295cab07d 100644
--- a/sub/sd_ass.c
+++ b/sub/sd_ass.c
@@ -147,6 +147,7 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd,
res->bitmap_id = ++res->bitmap_pos_id;
else if (changed)
res->bitmap_pos_id++;
+ res->type = SUBBITMAP_LIBASS;
}
static void reset(struct sh_sub *sh, struct osd_state *osd)
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,
diff --git a/sub/sub.h b/sub/sub.h
index 9fd6c5329e..fc0047bba6 100644
--- a/sub/sub.h
+++ b/sub/sub.h
@@ -71,6 +71,7 @@ struct osd_state {
double normal_scale;
double vsfilter_scale;
bool unscaled;
+ bool support_rgba;
struct ass_renderer *osd_render;
struct ass_library *osd_ass_library;