summaryrefslogtreecommitdiffstats
path: root/sub/spudec.c
diff options
context:
space:
mode:
Diffstat (limited to 'sub/spudec.c')
-rw-r--r--sub/spudec.c151
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);