summaryrefslogtreecommitdiffstats
path: root/sub/img_convert.c
diff options
context:
space:
mode:
Diffstat (limited to 'sub/img_convert.c')
-rw-r--r--sub/img_convert.c148
1 files changed, 78 insertions, 70 deletions
diff --git a/sub/img_convert.c b/sub/img_convert.c
index 6eef4a01a3..b8a769f052 100644
--- a/sub/img_convert.c
+++ b/sub/img_convert.c
@@ -25,14 +25,16 @@
#include "img_convert.h"
#include "sub.h"
+#include "spudec.h"
struct osd_conv_cache {
struct sub_bitmap part;
+ struct sub_bitmap *parts;
// for osd_conv_cache_alloc_old_p() (SUBBITMAP_PLANAR)
int allocated, stride;
struct old_osd_planar bmp;
- // for osd_conv_cache_alloc_bmp() (various other formats)
- unsigned char *packed;
+ // for osd_conv_idx_to_old_p(), a spudec.c handle
+ void *spudec;
};
static int osd_conv_cache_destroy(void *p)
@@ -40,6 +42,8 @@ static int osd_conv_cache_destroy(void *p)
struct osd_conv_cache *c = p;
av_free(c->bmp.bitmap);
av_free(c->bmp.alpha);
+ if (c->spudec)
+ spudec_free(c->spudec);
return 0;
}
@@ -73,21 +77,6 @@ static void osd_conv_cache_alloc_old_p(struct osd_conv_cache *c, int w, int h)
};
}
-static void osd_conv_cache_alloc_bmp(struct osd_conv_cache *c, int w, int h,
- int bpp)
-{
- size_t size = talloc_get_size(c->packed);
- size_t new_size = w * bpp * h;
- if (new_size > size)
- c->packed = talloc_realloc(c, c->packed, unsigned char, new_size);
- c->part = (struct sub_bitmap) {
- .bitmap = c->packed,
- .stride = w * bpp,
- .w = w, .h = h,
- .dw = w, .dh = h,
- };
-}
-
static void draw_alpha_ass_to_old(unsigned char *src, int src_w, int src_h,
int src_stride, unsigned char *dst_a,
unsigned char *dst_i, size_t dst_stride,
@@ -177,80 +166,99 @@ bool osd_conv_ass_to_old_p(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
return true;
}
-// SUBBITMAP_OLD_PLANAR -> SUBBITMAP_RGBA
-bool osd_conv_old_p_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
+bool osd_conv_idx_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
{
struct sub_bitmaps src = *imgs;
- if (src.format != SUBBITMAP_OLD_PLANAR || src.num_parts > 1)
+ if (src.format != SUBBITMAP_INDEXED)
return false;
imgs->format = SUBBITMAP_RGBA;
- imgs->num_parts = 0;
- imgs->parts = NULL;
-
- if (src.num_parts == 0)
- return true;
-
- struct sub_bitmap *s = &src.parts[0];
- struct old_osd_planar *p = s->bitmap;
-
- osd_conv_cache_alloc_bmp(c, s->w, s->h, 4);
-
- for (int y = 0; y < s->h; y++) {
- unsigned char *y_src = p->bitmap + s->stride * y;
- unsigned char *y_srca = p->alpha + s->stride * y;
- unsigned char *cur = c->packed + y * s->w * 4;
- for (int x = 0; x < s->w; x++) {
- // This is incorrect, as input is premultiplied alpha, but output
- // has to be non-premultiplied. However, this code is for
- // compatibility with spudec.c only, and DVD subtitles have
- // binary transparency only - the rendered result will be the same.
- cur[x*4+0] = cur[x*4+1] = cur[x*4+2] = y_src[x];
- cur[x*4+3] = -y_srca[x];
+ talloc_free(c->parts);
+ imgs->parts = c->parts = talloc_array(c, struct sub_bitmap, src.num_parts);
+
+ for (int n = 0; n < src.num_parts; n++) {
+ struct sub_bitmap *d = &imgs->parts[n];
+ struct sub_bitmap *s = &src.parts[n];
+ struct osd_bmp_indexed *sb = s->bitmap;
+
+ *d = *s;
+ d->stride = s->w * 4;
+ d->bitmap = talloc_size(c->parts, s->h * d->stride);
+
+ uint32_t *palette = sb->palette;
+ uint32_t *outbmp = d->bitmap;
+ for (int y = 0; y < s->h; y++) {
+ uint8_t *inbmp = sb->bitmap + y * s->stride;
+ for (int x = 0; x < s->w; x++)
+ *outbmp++ = palette[*inbmp++];
}
}
-
- c->part.x = s->x;
- c->part.y = s->y;
-
- imgs->parts = &c->part;
- imgs->num_parts = 1;
return true;
}
-// SUBBITMAP_OLD_PLANAR -> SUBBITMAP_OLD
-bool osd_conv_old_p_to_old(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
+bool osd_conv_idx_to_old_p(struct osd_conv_cache *c, struct sub_bitmaps *imgs,
+ int screen_w, int screen_h)
{
struct sub_bitmaps src = *imgs;
- if (src.format != SUBBITMAP_OLD_PLANAR || src.num_parts > 1)
+ if (src.format != SUBBITMAP_INDEXED)
return false;
- imgs->format = SUBBITMAP_OLD;
+ imgs->format = SUBBITMAP_OLD_PLANAR;
imgs->num_parts = 0;
imgs->parts = NULL;
-
if (src.num_parts == 0)
return true;
- struct sub_bitmap *s = &src.parts[0];
- struct old_osd_planar *p = s->bitmap;
-
- osd_conv_cache_alloc_bmp(c, s->w, s->h, 2);
-
- for (int y = 0; y < s->h; y++) {
- unsigned char *y_src = p->bitmap + s->stride * y;
- unsigned char *y_srca = p->alpha + s->stride * y;
- unsigned char *cur = c->packed + y * s->w * 2;
- for (int x = 0; x < s->w; x++) {
- cur[x*2+0] = y_src[x];
- cur[x*2+1] = -y_srca[x];
- }
+ // assume they are all evenly scaled (and size 0 is not possible)
+ // could put more effort into it to reduce rounding errors, but it doesn't
+ // make much sense anyway
+ struct sub_bitmap *s0 = &src.parts[0];
+ double scale_x = (double)s0->w / s0->dw;
+ double scale_y = (double)s0->h / s0->dh;
+ double scale = FFMIN(scale_x, scale_y);
+
+ int xmin, ymin, xmax, ymax;
+
+ xmin = ymin = INT_MAX;
+ xmax = ymax = INT_MIN;
+ for (int n = 0; n < src.num_parts; n++) {
+ struct sub_bitmap *s = &src.parts[n];
+ int sx = s->x * scale;
+ int sy = s->y * scale;
+ xmin = FFMIN(xmin, sx);
+ ymin = FFMIN(ymin, sy);
+ xmax = FFMAX(xmax, sx + s->w);
+ ymax = FFMAX(ymax, sy + s->h);
}
- c->part.x = s->x;
- c->part.y = s->y;
+ int w = xmax - xmin;
+ int h = ymax - ymin;
- imgs->parts = &c->part;
- imgs->num_parts = 1;
+ struct spu_packet_t *packet = spudec_packet_create(xmin, ymin, w, h);
+ if (!packet)
+ return false;
+ spudec_packet_clear(packet);
+ for (int n = 0; n < src.num_parts; n++) {
+ struct sub_bitmap *s = &src.parts[n];
+ struct osd_bmp_indexed *sb = s->bitmap;
+ int sx = s->x * scale;
+ int sy = s->y * scale;
+ assert(sx >= xmin);
+ assert(sy >= ymin);
+ assert(sx - xmin + s->w <= w);
+ assert(sy - ymin + s->h <= h);
+ // assumes sub-images are not overlapping
+ spudec_packet_fill(packet, sb->bitmap, s->stride, sb->palette,
+ sx - xmin, sy - ymin, s->w, s->h);
+ }
+ if (!c->spudec)
+ c->spudec = spudec_new_scaled(NULL, 0, 0, NULL, 0);
+ spudec_packet_send(c->spudec, packet, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
+ spudec_set_res(c->spudec, screen_w * scale, screen_h * scale);
+ spudec_heartbeat(c->spudec, 0);
+ spudec_get_bitmap(c->spudec, screen_w, screen_h, imgs);
+ imgs->render_index = src.render_index;
+ imgs->bitmap_id = src.bitmap_id;
+ imgs->bitmap_pos_id = src.bitmap_pos_id;
return true;
}