diff options
Diffstat (limited to 'sub/spudec.c')
-rw-r--r-- | sub/spudec.c | 151 |
1 files changed, 150 insertions, 1 deletions
diff --git a/sub/spudec.c b/sub/spudec.c index 47e1676e2e..4eea10ed8f 100644 --- a/sub/spudec.c +++ b/sub/spudec.c @@ -34,6 +34,7 @@ #include <unistd.h> #include <string.h> #include <math.h> +#include <assert.h> #include <libavutil/common.h> #include <libavutil/intreadwrite.h> @@ -44,6 +45,7 @@ #include "spudec.h" #include "vobsub.h" +#include "sub.h" #include "mpcommon.h" /* Valid values for spu_aamode: @@ -57,7 +59,6 @@ int spu_aamode = 3; int spu_alignment = -1; float spu_gaussvar = 1.0; -extern int sub_pos; typedef struct spu_packet_t packet_t; struct spu_packet_t { @@ -123,6 +124,10 @@ typedef struct { unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */ struct palette_crop_cache palette_crop_cache; + + struct old_osd_planar borrowed_sub_image; + struct sub_bitmap sub_part, borrowed_sub_part; + struct osd_bmp_indexed borrowed_bmp; } spudec_handle_t; static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet) @@ -339,6 +344,70 @@ int spudec_apply_palette_crop(void *this, uint32_t palette, return c->result; } +static void setup_palette(spudec_handle_t *spu, uint32_t palette[256]) +{ + memset(palette, 0, sizeof(palette)); + for (int i = 0; i < 4; ++i) { + int alpha = spu->alpha[i]; + // extend 4 -> 8 bit + alpha |= alpha << 4; + if (spu->custom && (spu->cuspal[i] >> 31) != 0) + alpha = 0; + int color = spu->custom ? spu->cuspal[i] : + spu->global_palette[spu->palette[i]]; + int y = (color >> 16) & 0xff; + int u = (color >> 8) & 0xff; + int v = color & 0xff; + // stolen from some site, likely incorrect + int b = 1.164 * (y - 16) + 2.018 * (u - 128); + int g = 1.164 * (y - 16) - 0.813 * (v - 128) - 0.391 * (u - 128); + int r = 1.164 * (y - 16) + 1.596 * (v - 128); +#define CL(x) FFMAX(FFMIN((x), 255), 0) + palette[i] = (alpha << 24) | CL(r) | (CL(g) << 8) | (CL(b) << 16); +#undef CL + } +} + +static void crop_image(struct sub_bitmap *part) +{ + if (part->w < 1 || part->h < 1) + return; + struct osd_bmp_indexed *bmp = part->bitmap; + bool invisible[256]; + for (int n = 0; n < 256; n++) + invisible[n] = !(bmp->palette[n] >> 24); + int y0 = 0, y1 = part->h, x0 = part->w, x1 = 0; + bool y_all_invisible = true; + for (int y = 0; y < part->h; y++) { + uint8_t *pixels = bmp->bitmap + part->stride * y; + int cur = 0; + while (cur < part->w && invisible[pixels[cur]]) + cur++; + int start_visible = cur; + int last_visible = -1; + while (cur < part->w) { + if (!invisible[pixels[cur]]) + last_visible = cur; + cur++; + } + x0 = FFMIN(x0, start_visible); + x1 = FFMAX(x1, last_visible); + bool all_invisible = last_visible == -1; + if (all_invisible) { + if (y_all_invisible) + y0 = y; + } else { + y_all_invisible = false; + y1 = y + 1; + } + } + bmp->bitmap += x0 + y0 * part->stride; + part->w = FFMAX(x1 - x0, 0); + part->h = FFMAX(y1 - y0, 0); + part->x += x0; + part->y += y0; +} + static void spudec_process_data(spudec_handle_t *this, packet_t *packet) { unsigned int i, x, y; @@ -386,6 +455,18 @@ static void spudec_process_data(spudec_handle_t *this, packet_t *packet) dst += len; } apply_palette_crop(this, 0, 0, this->pal_width, this->pal_height); + + struct sub_bitmap *sub_part = &this->sub_part; + struct osd_bmp_indexed *bmp = &this->borrowed_bmp; + bmp->bitmap = this->pal_image; + setup_palette(this, bmp->palette); + sub_part->bitmap = bmp; + sub_part->stride = this->pal_width; + sub_part->w = this->pal_width; + sub_part->h = this->pal_height; + sub_part->x = this->pal_start_col; + sub_part->y = this->pal_start_row; + crop_image(sub_part); } @@ -722,6 +803,66 @@ void spudec_set_forced_subs_only(void * const this, const unsigned int flag) } } +static void get_data(void *ctx, int x0,int y0, int w,int h, unsigned char* src, + unsigned char *srca, int stride) +{ + struct sub_bitmaps *bmp = ctx; + assert(bmp->num_parts == 0); + bmp->num_parts = 1; + struct sub_bitmap *s = &bmp->parts[0]; + struct old_osd_planar *p = s->bitmap; + // We know that the data stays valid until the next SPU related call + p->bitmap = src; + p->alpha = srca; + *s = (struct sub_bitmap) { + .bitmap = p, .stride = stride, + .x = x0, .y = y0, + .w = w, .h = h, + .dw = w, .dh = h, + }; +} + +void spudec_get_bitmap(void *this, int w, int h, struct sub_bitmaps *res) +{ + spudec_handle_t *spu = this; + *res = (struct sub_bitmaps) { + .format = SUBBITMAP_OLD_PLANAR, + .parts = &spu->borrowed_sub_part, + }; + res->parts[0].bitmap = &spu->borrowed_sub_image; + if (w == -1 && h == -1) { + spudec_draw(this, get_data, res); + } else { + spudec_draw_scaled(this, w, h, get_data, res); + } +} + +void spudec_get_indexed(void *this, struct mp_eosd_res *dim, + struct sub_bitmaps *res) +{ + spudec_handle_t *spu = this; + *res = (struct sub_bitmaps) { .format = SUBBITMAP_INDEXED }; + struct sub_bitmap *part = &spu->borrowed_sub_part; + res->parts = part; + *part = spu->sub_part; + // Empty subs do happen when cropping + bool empty = part->w < 1 || part->h < 1; + if (spudec_visible(spu) && !empty) { + double xscale = (double) (dim->w - dim->ml - dim->mr) / spu->orig_frame_width; + double yscale = (double) (dim->h - dim->mt - dim->mb) / spu->orig_frame_height; + part->x = part->x * xscale + dim->ml; + part->y = part->y * yscale + dim->mt; + part->dw = part->w * xscale; + part->dh = part->h * yscale; + res->num_parts = 1; + res->scaled = true; + } + if (spu->spu_changed) { + res->bitmap_id = res->bitmap_pos_id = 1; + spu->spu_changed = 0; + } +} + void spudec_draw(void *this, void (*draw_alpha)(void *ctx, int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride), void *ctx) { spudec_handle_t *spu = this; @@ -1287,6 +1428,14 @@ void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigne return this; } +void spudec_set_res(void *this, unsigned int frame_width, unsigned int frame_height) +{ + spudec_handle_t *spu = this; + // intentionally do not apply resolution heuristics + spu->orig_frame_width = frame_width; + spu->orig_frame_height = frame_height; +} + void *spudec_new(unsigned int *palette) { return spudec_new_scaled(palette, 0, 0, NULL, 0); |