diff --git a/meson.build b/meson.build
index d4c75a907f..a55e550cb3 100644
--- a/meson.build
+++ b/meson.build
@@ -203,6 +203,7 @@ sources = files(
'sub/lavc_conv.c',
'sub/osd.c',
'sub/osd_libass.c',
+ 'sub/packer.c',
'sub/sd_ass.c',
'sub/sd_lavc.c',
diff --git a/sub/ass_mp.c b/sub/ass_mp.c
index c8b1bd05d6..7e81bb266d 100644
--- a/sub/ass_mp.c
+++ b/sub/ass_mp.c
@@ -17,7 +17,6 @@
* License along with mpv. If not, see .
*/
-#include
#include
#include
#include
@@ -32,12 +31,8 @@
#include "common/msg.h"
#include "options/path.h"
#include "ass_mp.h"
-#include "img_convert.h"
#include "osd.h"
#include "stream/stream.h"
-#include "options/options.h"
-#include "video/out/bitmap_packer.h"
-#include "video/mp_image.h"
// res_y should be track->PlayResY
// It determines scaling of font sizes and more.
@@ -159,294 +154,6 @@ void mp_ass_flush_old_events(ASS_Track *track, long long ts)
}
}
-static void draw_ass_rgba(unsigned char *src, int src_w, int src_h,
- int src_stride, unsigned char *dst, size_t dst_stride,
- int dst_x, int dst_y, uint32_t color)
-{
- const unsigned int r = (color >> 24) & 0xff;
- const unsigned int g = (color >> 16) & 0xff;
- const unsigned int b = (color >> 8) & 0xff;
- const unsigned int a = 0xff - (color & 0xff);
-
- dst += dst_y * dst_stride + dst_x * 4;
-
- for (int y = 0; y < src_h; y++, dst += dst_stride, src += src_stride) {
- uint32_t *dstrow = (uint32_t *) dst;
- for (int x = 0; x < src_w; x++) {
- const unsigned int v = src[x];
- int rr = (r * a * v);
- int gg = (g * a * v);
- int bb = (b * a * v);
- int aa = a * v;
- uint32_t dstpix = dstrow[x];
- unsigned int dstb = dstpix & 0xFF;
- unsigned int dstg = (dstpix >> 8) & 0xFF;
- unsigned int dstr = (dstpix >> 16) & 0xFF;
- unsigned int dsta = (dstpix >> 24) & 0xFF;
- dstb = (bb + dstb * (255 * 255 - aa)) / (255 * 255);
- dstg = (gg + dstg * (255 * 255 - aa)) / (255 * 255);
- dstr = (rr + dstr * (255 * 255 - aa)) / (255 * 255);
- dsta = (aa * 255 + dsta * (255 * 255 - aa)) / (255 * 255);
- dstrow[x] = dstb | (dstg << 8) | (dstr << 16) | (dsta << 24);
- }
- }
-}
-
-struct mp_ass_packer {
- struct sub_bitmap *cached_parts; // only for the array memory
- struct mp_image *cached_img;
- struct sub_bitmaps cached_subs;
- bool cached_subs_valid;
- struct sub_bitmap rgba_imgs[MP_SUB_BB_LIST_MAX];
- struct bitmap_packer *packer;
-};
-
-// Free with talloc_free().
-struct mp_ass_packer *mp_ass_packer_alloc(void *ta_parent)
-{
- struct mp_ass_packer *p = talloc_zero(ta_parent, struct mp_ass_packer);
- p->packer = talloc_zero(p, struct bitmap_packer);
- p->packer->padding = 1; // assume bilinear sampling
- return p;
-}
-
-static bool pack(struct mp_ass_packer *p, struct sub_bitmaps *res, int imgfmt)
-{
- packer_set_size(p->packer, res->num_parts);
-
- for (int n = 0; n < res->num_parts; n++)
- p->packer->in[n] = (struct pos){res->parts[n].w, res->parts[n].h};
-
- if (p->packer->count == 0 || packer_pack(p->packer) < 0)
- return false;
-
- struct pos bb[2];
- packer_get_bb(p->packer, bb);
-
- res->packed_w = bb[1].x;
- res->packed_h = bb[1].y;
-
- if (!p->cached_img || p->cached_img->w < res->packed_w ||
- p->cached_img->h < res->packed_h ||
- p->cached_img->imgfmt != imgfmt)
- {
- talloc_free(p->cached_img);
- p->cached_img = mp_image_alloc(imgfmt, p->packer->w, p->packer->h);
- if (!p->cached_img) {
- packer_reset(p->packer);
- return false;
- }
- talloc_steal(p, p->cached_img);
- }
-
- if (!mp_image_make_writeable(p->cached_img)) {
- packer_reset(p->packer);
- return false;
- }
-
- res->packed = p->cached_img;
-
- for (int n = 0; n < res->num_parts; n++) {
- struct sub_bitmap *b = &res->parts[n];
- struct pos pos = p->packer->result[n];
-
- b->src_x = pos.x;
- b->src_y = pos.y;
- }
-
- return true;
-}
-
-static void fill_padding_1(uint8_t *base, int w, int h, int stride, int padding)
-{
- for (int row = 0; row < h; ++row) {
- uint8_t *row_ptr = base + row * stride;
- uint8_t left_pixel = row_ptr[0];
- uint8_t right_pixel = row_ptr[w - 1];
-
- for (int i = 1; i <= padding; ++i)
- row_ptr[-i] = left_pixel;
-
- for (int i = 0; i < padding; ++i)
- row_ptr[w + i] = right_pixel;
- }
-
- int row_bytes = (w + 2 * padding);
- uint8_t *top_row = base - padding;
- for (int i = 1; i <= padding; ++i)
- memcpy(base - i * stride - padding, top_row, row_bytes);
-
- uint8_t *last_row = base + (h - 1) * stride - padding;
- for (int i = 0; i < padding; ++i)
- memcpy(base + (h + i) * stride - padding, last_row, row_bytes);
-}
-
-static void fill_padding_4(uint8_t *base, int w, int h, int stride, int padding)
-{
- for (int row = 0; row < h; ++row) {
- uint32_t *row_ptr = (uint32_t *)(base + row * stride);
- uint32_t left_pixel = row_ptr[0];
- uint32_t right_pixel = row_ptr[w - 1];
-
- for (int i = 1; i <= padding; ++i)
- row_ptr[-i] = left_pixel;
-
- for (int i = 0; i < padding; ++i)
- row_ptr[w + i] = right_pixel;
- }
-
- int row_bytes = (w + 2 * padding) * 4;
- uint8_t *top_row = base - padding * 4;
- for (int i = 1; i <= padding; ++i)
- memcpy(base - i * stride - padding * 4, top_row, row_bytes);
-
- uint8_t *last_row = base + (h - 1) * stride - padding * 4;
- for (int i = 0; i < padding; ++i)
- memcpy(base + (h + i) * stride - padding * 4, last_row, row_bytes);
-}
-
-static bool pack_libass(struct mp_ass_packer *p, struct sub_bitmaps *res)
-{
- if (!pack(p, res, IMGFMT_Y8))
- return false;
-
- int padding = p->packer->padding;
- uint8_t *base = res->packed->planes[0];
- int stride = res->packed->stride[0];
-
- for (int n = 0; n < res->num_parts; n++) {
- struct sub_bitmap *b = &res->parts[n];
- void *pdata = base + b->src_y * stride + b->src_x;
- memcpy_pic(pdata, b->bitmap, b->w, b->h, stride, b->stride);
- fill_padding_1(pdata, b->w, b->h, stride, padding);
-
- b->bitmap = pdata;
- b->stride = stride;
- }
-
- return true;
-}
-
-static bool pack_rgba(struct mp_ass_packer *p, struct sub_bitmaps *res)
-{
- struct mp_rect bb_list[MP_SUB_BB_LIST_MAX];
- int num_bb = mp_get_sub_bb_list(res, bb_list, MP_SUB_BB_LIST_MAX);
-
- struct sub_bitmaps imgs = {
- .change_id = res->change_id,
- .format = SUBBITMAP_BGRA,
- .parts = p->rgba_imgs,
- .num_parts = num_bb,
- };
-
- for (int n = 0; n < imgs.num_parts; n++) {
- imgs.parts[n].w = bb_list[n].x1 - bb_list[n].x0;
- imgs.parts[n].h = bb_list[n].y1 - bb_list[n].y0;
- }
-
- if (!pack(p, &imgs, IMGFMT_BGRA))
- return false;
-
- int padding = p->packer->padding;
- uint8_t *base = imgs.packed->planes[0];
- int stride = imgs.packed->stride[0];
-
- for (int n = 0; n < num_bb; n++) {
- struct mp_rect bb = bb_list[n];
- struct sub_bitmap *b = &imgs.parts[n];
-
- b->x = bb.x0;
- b->y = bb.y0;
- b->w = b->dw = mp_rect_w(bb);
- b->h = b->dh = mp_rect_h(bb);
- b->stride = stride;
- b->bitmap = base + b->stride * b->src_y + b->src_x * 4;
- memset_pic(b->bitmap, 0, b->w * 4, b->h, b->stride);
-
- for (int i = 0; i < res->num_parts; i++) {
- struct sub_bitmap *s = &res->parts[i];
-
- // Assume mp_get_sub_bb_list() never splits sub bitmaps
- // So we don't clip/adjust the size of the sub bitmap
- if (s->x >= b->x + b->w || s->x + s->w <= b->x ||
- s->y >= b->y + b->h || s->y + s->h <= b->y)
- continue;
-
- draw_ass_rgba(s->bitmap, s->w, s->h, s->stride,
- b->bitmap, b->stride,
- s->x - b->x, s->y - b->y,
- s->libass.color);
- }
- fill_padding_4(b->bitmap, b->w, b->h, b->stride, padding);
- }
-
- *res = imgs;
- return true;
-}
-
-// Pack the contents of image_lists[0] to image_lists[num_image_lists-1] into
-// a single image, and make *out point to it. *out is completely overwritten.
-// If libass reported any change, image_lists_changed must be set (it then
-// repacks all images). preferred_osd_format can be set to a desired
-// sub_bitmap_format. Currently, only SUBBITMAP_LIBASS is supported.
-void mp_ass_packer_pack(struct mp_ass_packer *p, ASS_Image **image_lists,
- int num_image_lists, bool image_lists_changed, bool video_color_space,
- int preferred_osd_format, struct sub_bitmaps *out)
-{
- int format = preferred_osd_format == SUBBITMAP_BGRA ? SUBBITMAP_BGRA
- : SUBBITMAP_LIBASS;
-
- if (p->cached_subs_valid && !image_lists_changed &&
- p->cached_subs.format == format)
- {
- *out = p->cached_subs;
- return;
- }
-
- *out = (struct sub_bitmaps){.change_id = 1};
- p->cached_subs_valid = false;
-
- struct sub_bitmaps res = {
- .change_id = image_lists_changed,
- .format = SUBBITMAP_LIBASS,
- .parts = p->cached_parts,
- .video_color_space = video_color_space,
- };
-
- for (int n = 0; n < num_image_lists; n++) {
- for (struct ass_image *img = image_lists[n]; img; img = img->next) {
- if (img->w == 0 || img->h == 0)
- continue;
- MP_TARRAY_GROW(p, p->cached_parts, res.num_parts);
- res.parts = p->cached_parts;
- struct sub_bitmap *b = &res.parts[res.num_parts];
- b->bitmap = img->bitmap;
- b->stride = img->stride;
- b->libass.color = img->color;
- b->dw = b->w = img->w;
- b->dh = b->h = img->h;
- b->x = img->dst_x;
- b->y = img->dst_y;
- res.num_parts++;
- }
- }
-
- bool r = false;
- if (format == SUBBITMAP_BGRA) {
- r = pack_rgba(p, &res);
- } else {
- r = pack_libass(p, &res);
- }
-
- if (!r)
- return;
-
- *out = res;
- p->cached_subs = res;
- p->cached_subs.change_id = 0;
- p->cached_subs_valid = true;
-}
-
// Set *out_rc to [x0, y0, x1, y1] of the graphical bounding box in script
// coordinates.
// Set it to [inf, inf, -inf, -inf] if empty.
diff --git a/sub/ass_mp.h b/sub/ass_mp.h
index b4e16d6650..ecc44231ec 100644
--- a/sub/ass_mp.h
+++ b/sub/ass_mp.h
@@ -20,7 +20,6 @@
#ifndef MPLAYER_ASS_MP_H
#define MPLAYER_ASS_MP_H
-#include
#include
#include
@@ -53,12 +52,6 @@ void mp_ass_configure_fonts(ASS_Renderer *priv, struct osd_style_opts *opts,
ASS_Library *mp_ass_init(struct mpv_global *global,
struct osd_style_opts *opts, struct mp_log *log);
-struct sub_bitmaps;
-struct mp_ass_packer;
-struct mp_ass_packer *mp_ass_packer_alloc(void *ta_parent);
-void mp_ass_packer_pack(struct mp_ass_packer *p, ASS_Image **image_lists,
- int num_image_lists, bool changed, bool video_color_space,
- int preferred_osd_format, struct sub_bitmaps *out);
void mp_ass_get_bb(ASS_Image *image_list, ASS_Track *track,
struct mp_osd_res *res, double *out_rc);
diff --git a/sub/osd_libass.c b/sub/osd_libass.c
index 8e79bd8a2f..7b0850954c 100644
--- a/sub/osd_libass.c
+++ b/sub/osd_libass.c
@@ -33,6 +33,7 @@ static const char osd_font_pfb[] =
;
#include "sub/ass_mp.h"
+#include "sub/packer.h"
#include "options/options.h"
@@ -690,13 +691,13 @@ struct sub_bitmaps *osd_object_get_bitmaps(struct osd_state *osd,
if (obj->osd_changed) {
update_osd(osd, obj);
} else {
- mp_require(obj->ass_packer);
+ mp_require(obj->sub_packer);
goto done;
}
}
- if (!obj->ass_packer)
- obj->ass_packer = mp_ass_packer_alloc(obj);
+ if (!obj->sub_packer)
+ obj->sub_packer = mp_sub_packer_alloc(obj);
MP_TARRAY_GROW(obj, obj->ass_imgs, obj->num_externals + 1);
@@ -713,7 +714,7 @@ struct sub_bitmaps *osd_object_get_bitmaps(struct osd_state *osd,
done:;
struct sub_bitmaps out_imgs = {0};
- mp_ass_packer_pack(obj->ass_packer, obj->ass_imgs, obj->num_externals + 1,
+ mp_sub_packer_pack_ass(obj->sub_packer, obj->ass_imgs, obj->num_externals + 1,
obj->changed, false, format, &out_imgs);
obj->changed = false;
diff --git a/sub/osd_state.h b/sub/osd_state.h
index ef0ff20a57..cd4ca15a04 100644
--- a/sub/osd_state.h
+++ b/sub/osd_state.h
@@ -55,7 +55,7 @@ struct osd_object {
// Internally used by osd_libass.c
bool changed;
struct ass_state ass;
- struct mp_ass_packer *ass_packer;
+ struct mp_sub_packer *sub_packer;
struct sub_bitmap_copy_cache *copy_cache;
struct ass_image **ass_imgs;
};
diff --git a/sub/packer.c b/sub/packer.c
new file mode 100644
index 0000000000..cfa41cbe5d
--- /dev/null
+++ b/sub/packer.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2006 Evgeniy Stepanov
+ *
+ * This file is part of mpv.
+ *
+ * mpv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * mpv is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+
+#include "config.h"
+
+#include
+#include
+
+#include "common/common.h"
+#include "packer.h"
+#include "img_convert.h"
+#include "osd.h"
+#include "video/out/bitmap_packer.h"
+#include "video/mp_image.h"
+
+struct mp_sub_packer {
+ struct sub_bitmap *cached_parts; // only for the array memory
+ struct mp_image *cached_img;
+ struct sub_bitmaps cached_subs;
+ bool cached_subs_valid;
+ struct sub_bitmap rgba_imgs[MP_SUB_BB_LIST_MAX];
+ struct bitmap_packer *packer;
+};
+
+// Free with talloc_free().
+struct mp_sub_packer *mp_sub_packer_alloc(void *ta_parent)
+{
+ struct mp_sub_packer *p = talloc_zero(ta_parent, struct mp_sub_packer);
+ p->packer = talloc_zero(p, struct bitmap_packer);
+ p->packer->padding = 1; // assume bilinear sampling
+ return p;
+}
+
+static bool pack(struct mp_sub_packer *p, struct sub_bitmaps *res, int imgfmt)
+{
+ packer_set_size(p->packer, res->num_parts);
+
+ for (int n = 0; n < res->num_parts; n++)
+ p->packer->in[n] = (struct pos){res->parts[n].w, res->parts[n].h};
+
+ if (p->packer->count == 0 || packer_pack(p->packer) < 0)
+ return false;
+
+ struct pos bb[2];
+ packer_get_bb(p->packer, bb);
+
+ res->packed_w = bb[1].x;
+ res->packed_h = bb[1].y;
+
+ if (!p->cached_img || p->cached_img->w < res->packed_w ||
+ p->cached_img->h < res->packed_h ||
+ p->cached_img->imgfmt != imgfmt)
+ {
+ talloc_free(p->cached_img);
+ p->cached_img = mp_image_alloc(imgfmt, p->packer->w, p->packer->h);
+ if (!p->cached_img) {
+ packer_reset(p->packer);
+ return false;
+ }
+ talloc_steal(p, p->cached_img);
+ }
+
+ if (!mp_image_make_writeable(p->cached_img)) {
+ packer_reset(p->packer);
+ return false;
+ }
+
+ res->packed = p->cached_img;
+
+ for (int n = 0; n < res->num_parts; n++) {
+ struct sub_bitmap *b = &res->parts[n];
+ struct pos pos = p->packer->result[n];
+
+ b->src_x = pos.x;
+ b->src_y = pos.y;
+ }
+
+ return true;
+}
+
+static void fill_padding_1(uint8_t *base, int w, int h, int stride, int padding)
+{
+ for (int row = 0; row < h; ++row) {
+ uint8_t *row_ptr = base + row * stride;
+ uint8_t left_pixel = row_ptr[0];
+ uint8_t right_pixel = row_ptr[w - 1];
+
+ for (int i = 1; i <= padding; ++i)
+ row_ptr[-i] = left_pixel;
+
+ for (int i = 0; i < padding; ++i)
+ row_ptr[w + i] = right_pixel;
+ }
+
+ int row_bytes = (w + 2 * padding);
+ uint8_t *top_row = base - padding;
+ for (int i = 1; i <= padding; ++i)
+ memcpy(base - i * stride - padding, top_row, row_bytes);
+
+ uint8_t *last_row = base + (h - 1) * stride - padding;
+ for (int i = 0; i < padding; ++i)
+ memcpy(base + (h + i) * stride - padding, last_row, row_bytes);
+}
+
+static void fill_padding_4(uint8_t *base, int w, int h, int stride, int padding)
+{
+ for (int row = 0; row < h; ++row) {
+ uint32_t *row_ptr = (uint32_t *)(base + row * stride);
+ uint32_t left_pixel = row_ptr[0];
+ uint32_t right_pixel = row_ptr[w - 1];
+
+ for (int i = 1; i <= padding; ++i)
+ row_ptr[-i] = left_pixel;
+
+ for (int i = 0; i < padding; ++i)
+ row_ptr[w + i] = right_pixel;
+ }
+
+ int row_bytes = (w + 2 * padding) * 4;
+ uint8_t *top_row = base - padding * 4;
+ for (int i = 1; i <= padding; ++i)
+ memcpy(base - i * stride - padding * 4, top_row, row_bytes);
+
+ uint8_t *last_row = base + (h - 1) * stride - padding * 4;
+ for (int i = 0; i < padding; ++i)
+ memcpy(base + (h + i) * stride - padding * 4, last_row, row_bytes);
+}
+
+static void draw_ass_rgba(unsigned char *src, int src_w, int src_h,
+ int src_stride, unsigned char *dst, size_t dst_stride,
+ int dst_x, int dst_y, uint32_t color)
+{
+ const unsigned int r = (color >> 24) & 0xff;
+ const unsigned int g = (color >> 16) & 0xff;
+ const unsigned int b = (color >> 8) & 0xff;
+ const unsigned int a = 0xff - (color & 0xff);
+
+ dst += dst_y * dst_stride + dst_x * 4;
+
+ for (int y = 0; y < src_h; y++, dst += dst_stride, src += src_stride) {
+ uint32_t *dstrow = (uint32_t *) dst;
+ for (int x = 0; x < src_w; x++) {
+ const unsigned int v = src[x];
+ int rr = (r * a * v);
+ int gg = (g * a * v);
+ int bb = (b * a * v);
+ int aa = a * v;
+ uint32_t dstpix = dstrow[x];
+ unsigned int dstb = dstpix & 0xFF;
+ unsigned int dstg = (dstpix >> 8) & 0xFF;
+ unsigned int dstr = (dstpix >> 16) & 0xFF;
+ unsigned int dsta = (dstpix >> 24) & 0xFF;
+ dstb = (bb + dstb * (255 * 255 - aa)) / (255 * 255);
+ dstg = (gg + dstg * (255 * 255 - aa)) / (255 * 255);
+ dstr = (rr + dstr * (255 * 255 - aa)) / (255 * 255);
+ dsta = (aa * 255 + dsta * (255 * 255 - aa)) / (255 * 255);
+ dstrow[x] = dstb | (dstg << 8) | (dstr << 16) | (dsta << 24);
+ }
+ }
+}
+
+static bool pack_libass(struct mp_sub_packer *p, struct sub_bitmaps *res)
+{
+ if (!pack(p, res, IMGFMT_Y8))
+ return false;
+
+ int padding = p->packer->padding;
+ uint8_t *base = res->packed->planes[0];
+ int stride = res->packed->stride[0];
+
+ for (int n = 0; n < res->num_parts; n++) {
+ struct sub_bitmap *b = &res->parts[n];
+ void *pdata = base + b->src_y * stride + b->src_x;
+ memcpy_pic(pdata, b->bitmap, b->w, b->h, stride, b->stride);
+ fill_padding_1(pdata, b->w, b->h, stride, padding);
+
+ b->bitmap = pdata;
+ b->stride = stride;
+ }
+
+ return true;
+}
+
+static bool pack_rgba(struct mp_sub_packer *p, struct sub_bitmaps *res)
+{
+ struct mp_rect bb_list[MP_SUB_BB_LIST_MAX];
+ int num_bb = mp_get_sub_bb_list(res, bb_list, MP_SUB_BB_LIST_MAX);
+
+ struct sub_bitmaps imgs = {
+ .change_id = res->change_id,
+ .format = SUBBITMAP_BGRA,
+ .parts = p->rgba_imgs,
+ .num_parts = num_bb,
+ };
+
+ for (int n = 0; n < imgs.num_parts; n++) {
+ imgs.parts[n].w = bb_list[n].x1 - bb_list[n].x0;
+ imgs.parts[n].h = bb_list[n].y1 - bb_list[n].y0;
+ }
+
+ if (!pack(p, &imgs, IMGFMT_BGRA))
+ return false;
+
+ int padding = p->packer->padding;
+ uint8_t *base = imgs.packed->planes[0];
+ int stride = imgs.packed->stride[0];
+
+ for (int n = 0; n < num_bb; n++) {
+ struct mp_rect bb = bb_list[n];
+ struct sub_bitmap *b = &imgs.parts[n];
+
+ b->x = bb.x0;
+ b->y = bb.y0;
+ b->w = b->dw = mp_rect_w(bb);
+ b->h = b->dh = mp_rect_h(bb);
+ b->stride = stride;
+ b->bitmap = base + b->stride * b->src_y + b->src_x * 4;
+ memset_pic(b->bitmap, 0, b->w * 4, b->h, b->stride);
+
+ for (int i = 0; i < res->num_parts; i++) {
+ struct sub_bitmap *s = &res->parts[i];
+
+ // Assume mp_get_sub_bb_list() never splits sub bitmaps
+ // So we don't clip/adjust the size of the sub bitmap
+ if (s->x >= b->x + b->w || s->x + s->w <= b->x ||
+ s->y >= b->y + b->h || s->y + s->h <= b->y)
+ continue;
+
+ draw_ass_rgba(s->bitmap, s->w, s->h, s->stride,
+ b->bitmap, b->stride,
+ s->x - b->x, s->y - b->y,
+ s->libass.color);
+ }
+ fill_padding_4(b->bitmap, b->w, b->h, b->stride, padding);
+ }
+
+ *res = imgs;
+ return true;
+}
+
+// Pack the contents of image_lists[0] to image_lists[num_image_lists-1] into
+// a single image, and make *out point to it. *out is completely overwritten.
+// If libass reported any change, image_lists_changed must be set (it then
+// repacks all images). preferred_osd_format can be set to a desired
+// sub_bitmap_format. Currently, only SUBBITMAP_LIBASS is supported.
+void mp_sub_packer_pack_ass(struct mp_sub_packer *p, ASS_Image **image_lists,
+ int num_image_lists, bool image_lists_changed, bool video_color_space,
+ int preferred_osd_format, struct sub_bitmaps *out)
+{
+ int format = preferred_osd_format == SUBBITMAP_BGRA ? SUBBITMAP_BGRA
+ : SUBBITMAP_LIBASS;
+
+ if (p->cached_subs_valid && !image_lists_changed &&
+ p->cached_subs.format == format)
+ {
+ *out = p->cached_subs;
+ return;
+ }
+
+ *out = (struct sub_bitmaps){.change_id = 1};
+ p->cached_subs_valid = false;
+
+ struct sub_bitmaps res = {
+ .change_id = image_lists_changed,
+ .format = SUBBITMAP_LIBASS,
+ .parts = p->cached_parts,
+ .video_color_space = video_color_space,
+ };
+
+ for (int n = 0; n < num_image_lists; n++) {
+ for (struct ass_image *img = image_lists[n]; img; img = img->next) {
+ if (img->w == 0 || img->h == 0)
+ continue;
+ MP_TARRAY_GROW(p, p->cached_parts, res.num_parts);
+ res.parts = p->cached_parts;
+ struct sub_bitmap *b = &res.parts[res.num_parts];
+ b->bitmap = img->bitmap;
+ b->stride = img->stride;
+ b->libass.color = img->color;
+ b->dw = b->w = img->w;
+ b->dh = b->h = img->h;
+ b->x = img->dst_x;
+ b->y = img->dst_y;
+ res.num_parts++;
+ }
+ }
+
+ bool r = false;
+ if (format == SUBBITMAP_BGRA) {
+ r = pack_rgba(p, &res);
+ } else {
+ r = pack_libass(p, &res);
+ }
+
+ if (!r)
+ return;
+
+ *out = res;
+ p->cached_subs = res;
+ p->cached_subs.change_id = 0;
+ p->cached_subs_valid = true;
+}
diff --git a/sub/packer.h b/sub/packer.h
new file mode 100644
index 0000000000..9b0a5c67ba
--- /dev/null
+++ b/sub/packer.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2006 Evgeniy Stepanov
+ *
+ * This file is part of mpv.
+ *
+ * mpv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * mpv is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv. If not, see .
+ */
+
+#ifndef MP_SUB_PACKER_H
+#define MP_SUB_PACKER_H
+
+#include
+
+#include
+#include
+
+struct sub_bitmaps;
+struct mp_sub_packer;
+struct mp_sub_packer *mp_sub_packer_alloc(void *ta_parent);
+void mp_sub_packer_pack_ass(struct mp_sub_packer *p, ASS_Image **image_lists,
+ int num_image_lists, bool changed, bool video_color_space,
+ int preferred_osd_format, struct sub_bitmaps *out);
+
+#endif
diff --git a/sub/sd_ass.c b/sub/sd_ass.c
index ece372a231..6c449ad442 100644
--- a/sub/sd_ass.c
+++ b/sub/sd_ass.c
@@ -38,6 +38,7 @@
#include "video/mp_image.h"
#include "dec_sub.h"
#include "ass_mp.h"
+#include "packer.h"
#include "sd.h"
struct sd_ass_priv {
@@ -51,7 +52,7 @@ struct sd_ass_priv {
struct sd_filter **filters;
int num_filters;
bool clear_once;
- struct mp_ass_packer *packer;
+ struct mp_sub_packer *packer;
struct sub_bitmap_copy_cache *copy_cache;
bstr last_text;
struct mp_image_params video_params;
@@ -319,7 +320,7 @@ static int init(struct sd *sd)
assobjects_init(sd);
filters_init(sd);
- ctx->packer = mp_ass_packer_alloc(ctx);
+ ctx->packer = mp_sub_packer_alloc(ctx);
// Subtitles does not have any profile value, so put the converted type as a profile.
const char *_Atomic *desc = ctx->converter ? &sd->codec->codec_profile : &sd->codec->codec_desc;
@@ -778,7 +779,7 @@ static struct sub_bitmaps *get_bitmaps(struct sd *sd, struct mp_osd_res dim,
int changed;
ASS_Image *imgs = ass_render_frame(renderer, track, ts, &changed);
- mp_ass_packer_pack(ctx->packer, &imgs, 1, changed, !converted, format, res);
+ mp_sub_packer_pack_ass(ctx->packer, &imgs, 1, changed, !converted, format, res);
done:
// mangle_colors() modifies the color field, so copy the thing _before_.