mirror of
https://github.com/mpv-player/mpv.git
synced 2026-10-29 15:11:09 +08:00
Merge branch 'eosd' into my_master
This commit is contained in:
@@ -403,6 +403,7 @@ SRCS_COMMON = asxparser.c \
|
||||
libmpdemux/yuv4mpeg.c \
|
||||
libmpdemux/yuv4mpeg_ratio.c \
|
||||
libvo/osd.c \
|
||||
libvo/eosd_packer.c \
|
||||
osdep/numcores.c \
|
||||
osdep/$(GETCH) \
|
||||
osdep/$(TIMER) \
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Common code for packing EOSD images into larger surfaces.
|
||||
*
|
||||
* This file is part of mplayer2.
|
||||
*
|
||||
* mplayer2 is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mplayer2 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mplayer2; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <libavutil/common.h>
|
||||
#include "talloc.h"
|
||||
#include "mp_msg.h"
|
||||
#include "eosd_packer.h"
|
||||
|
||||
// Initial size of EOSD surface in pixels (x*x)
|
||||
#define EOSD_SURFACE_INITIAL_SIZE 256
|
||||
|
||||
// Allocate an eosd_packer, which can be used to layout and cache the list of
|
||||
// EOSD images contained in a mp_eosd_images_t into a flat surface.
|
||||
// It can be free'd with talloc_free().
|
||||
// Don't forget to call eosd_init() before using it.
|
||||
struct eosd_packer *eosd_packer_create(void *talloc_ctx) {
|
||||
return talloc_zero(talloc_ctx, struct eosd_packer);
|
||||
}
|
||||
|
||||
// Call this when you need to completely reinitialize the EOSD state, e.g. when
|
||||
// when your EOSD surface was deleted.
|
||||
// max_width and max_height are the maximum surface sizes that should be
|
||||
// allowed.
|
||||
void eosd_packer_reinit(struct eosd_packer *state, uint32_t max_width,
|
||||
uint32_t max_height)
|
||||
{
|
||||
state->max_surface_width = max_width;
|
||||
state->max_surface_height = max_height;
|
||||
state->surface.w = 0;
|
||||
state->surface.h = 0;
|
||||
state->targets_count = 0;
|
||||
}
|
||||
|
||||
#define HEIGHT_SORT_BITS 4
|
||||
static int size_index(struct eosd_target *r)
|
||||
{
|
||||
unsigned int h = r->source.y1;
|
||||
int n = av_log2_16bit(h);
|
||||
return (n << HEIGHT_SORT_BITS)
|
||||
+ (- 1 - (h << HEIGHT_SORT_BITS >> n) & (1 << HEIGHT_SORT_BITS) - 1);
|
||||
}
|
||||
|
||||
/* Pack the given rectangles into an area of size w * h.
|
||||
* The size of each rectangle is read from .source.x1/.source.y1.
|
||||
* The height of each rectangle must be at least 1 and less than 65536.
|
||||
* The .source rectangle is then set corresponding to the packed position.
|
||||
* 'scratch' must point to work memory for num_rects+16 ints.
|
||||
* Return 0 on success, -1 if the rectangles did not fit in w*h.
|
||||
*
|
||||
* The rectangles are placed in rows in order approximately sorted by
|
||||
* height (the approximate sorting is simpler than a full one would be,
|
||||
* and allows the algorithm to work in linear time). Additionally, to
|
||||
* reduce wasted space when there are a few tall rectangles, empty
|
||||
* lower-right parts of rows are filled recursively when the size of
|
||||
* rectangles in the row drops past a power-of-two threshold. So if a
|
||||
* row starts with rectangles of size 3x50, 10x40 and 5x20 then the
|
||||
* free rectangle with corners (13, 20)-(w, 50) is filled recursively.
|
||||
*/
|
||||
static int pack_rectangles(struct eosd_target *rects, int num_rects,
|
||||
int w, int h, int *scratch)
|
||||
{
|
||||
int bins[16 << HEIGHT_SORT_BITS];
|
||||
int sizes[16 << HEIGHT_SORT_BITS] = {};
|
||||
for (int i = 0; i < num_rects; i++)
|
||||
sizes[size_index(rects + i)]++;
|
||||
int idx = 0;
|
||||
for (int i = 0; i < 16 << HEIGHT_SORT_BITS; i += 1 << HEIGHT_SORT_BITS) {
|
||||
for (int j = 0; j < 1 << HEIGHT_SORT_BITS; j++) {
|
||||
bins[i + j] = idx;
|
||||
idx += sizes[i + j];
|
||||
}
|
||||
scratch[idx++] = -1;
|
||||
}
|
||||
for (int i = 0; i < num_rects; i++)
|
||||
scratch[bins[size_index(rects + i)]++] = i;
|
||||
for (int i = 0; i < 16; i++)
|
||||
bins[i] = bins[i << HEIGHT_SORT_BITS] - sizes[i << HEIGHT_SORT_BITS];
|
||||
struct {
|
||||
int size, x, bottom;
|
||||
} stack[16] = {{15, 0, h}}, s = {};
|
||||
int stackpos = 1;
|
||||
int y;
|
||||
while (stackpos) {
|
||||
y = s.bottom;
|
||||
s = stack[--stackpos];
|
||||
s.size++;
|
||||
while (s.size--) {
|
||||
int maxy = -1;
|
||||
int obj;
|
||||
while ((obj = scratch[bins[s.size]]) >= 0) {
|
||||
int bottom = y + rects[obj].source.y1;
|
||||
if (bottom > s.bottom)
|
||||
break;
|
||||
int right = s.x + rects[obj].source.x1;
|
||||
if (right > w)
|
||||
break;
|
||||
bins[s.size]++;
|
||||
rects[obj].source.x0 = s.x;
|
||||
rects[obj].source.x1 += s.x;
|
||||
rects[obj].source.y0 = y;
|
||||
rects[obj].source.y1 += y;
|
||||
num_rects--;
|
||||
if (maxy <= 0)
|
||||
stack[stackpos++] = s;
|
||||
s.x = right;
|
||||
maxy = FFMAX(maxy, bottom);
|
||||
}
|
||||
if (maxy > 0)
|
||||
s.bottom = maxy;
|
||||
}
|
||||
}
|
||||
return num_rects ? -1 : 0;
|
||||
}
|
||||
|
||||
// padding to reduce interpolation artifacts when doing scaling & filtering
|
||||
#define EOSD_PADDING 0
|
||||
|
||||
// Release all previous images, and packs the images in imgs into state. The
|
||||
// caller must check the change variables:
|
||||
// *out_need_reposition == true: sub-image positions changed
|
||||
// *out_need_upload == true: upload all sub-images again
|
||||
// *out_need_reallocate == true: resize the EOSD texture to state->surface.w/h
|
||||
// Logical implications: need_reallocate => need_upload => need_reposition
|
||||
void eosd_packer_generate(struct eosd_packer *state, mp_eosd_images_t *imgs,
|
||||
bool *out_need_reposition, bool *out_need_upload,
|
||||
bool *out_need_reallocate)
|
||||
{
|
||||
int i;
|
||||
ASS_Image *img = imgs->imgs;
|
||||
ASS_Image *p;
|
||||
struct eosd_surface *sfc = &state->surface;
|
||||
|
||||
*out_need_reposition = false;
|
||||
*out_need_upload = false;
|
||||
*out_need_reallocate = false;
|
||||
|
||||
int change_state = imgs->changed;
|
||||
|
||||
// eosd_reinit() was probably called, force full reupload.
|
||||
if (state->targets_count == 0 && img)
|
||||
change_state = 2;
|
||||
|
||||
if (change_state == 0)
|
||||
return; // Nothing changed, no need to redraw
|
||||
|
||||
state->targets_count = 0;
|
||||
|
||||
*out_need_reposition = true;
|
||||
|
||||
if (!img)
|
||||
return; // There's nothing to render!
|
||||
|
||||
if (change_state == 1)
|
||||
goto eosd_skip_upload;
|
||||
|
||||
*out_need_upload = true;
|
||||
while (1) {
|
||||
for (p = img, i = 0; p; p = p->next) {
|
||||
if (p->w <= 0 || p->h <= 0)
|
||||
continue;
|
||||
// Allocate new space for surface/target arrays
|
||||
if (i >= state->targets_size) {
|
||||
state->targets_size = FFMAX(state->targets_size * 2, 512);
|
||||
state->targets =
|
||||
talloc_realloc_size(state, state->targets,
|
||||
state->targets_size
|
||||
* sizeof(*state->targets));
|
||||
state->scratch =
|
||||
talloc_realloc_size(state, state->scratch,
|
||||
(state->targets_size + 16)
|
||||
* sizeof(*state->scratch));
|
||||
}
|
||||
state->targets[i].source.x1 = p->w + EOSD_PADDING;
|
||||
state->targets[i].source.y1 = p->h + EOSD_PADDING;
|
||||
i++;
|
||||
}
|
||||
if (pack_rectangles(state->targets, i, sfc->w, sfc->h,
|
||||
state->scratch) >= 0)
|
||||
break;
|
||||
int w = FFMIN(FFMAX(sfc->w * 2, EOSD_SURFACE_INITIAL_SIZE),
|
||||
state->max_surface_width);
|
||||
int h = FFMIN(FFMAX(sfc->h * 2, EOSD_SURFACE_INITIAL_SIZE),
|
||||
state->max_surface_height);
|
||||
if (w == sfc->w && h == sfc->h) {
|
||||
mp_msg(MSGT_VO, MSGL_ERR, "[eosd] EOSD bitmaps do not fit on "
|
||||
"a surface with the maximum supported size\n");
|
||||
return;
|
||||
}
|
||||
sfc->w = w;
|
||||
sfc->h = h;
|
||||
*out_need_reallocate = true;
|
||||
}
|
||||
if (*out_need_reallocate) {
|
||||
mp_msg(MSGT_VO, MSGL_V, "[eosd] Allocate a %dx%d surface for "
|
||||
"EOSD bitmaps.\n", sfc->w, sfc->h);
|
||||
}
|
||||
|
||||
eosd_skip_upload:
|
||||
for (p = img; p; p = p->next) {
|
||||
if (p->w <= 0 || p->h <= 0)
|
||||
continue;
|
||||
struct eosd_target *target = &state->targets[state->targets_count];
|
||||
target->source.x1 -= EOSD_PADDING;
|
||||
target->source.y1 -= EOSD_PADDING;
|
||||
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;
|
||||
target->color = p->color;
|
||||
target->ass_img = p;
|
||||
state->targets_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the bounding box of all sub-rectangles in the EOSD surface that
|
||||
// will be used for EOSD rendering.
|
||||
// If the bounding box is empty, return false.
|
||||
bool eosd_packer_calculate_source_bb(struct eosd_packer *state,
|
||||
struct eosd_rect *out_bb)
|
||||
{
|
||||
struct eosd_rect bb = { state->surface.w, state->surface.h, 0, 0 };
|
||||
|
||||
for (int n = 0; n < state->targets_count; n++) {
|
||||
struct eosd_rect s = state->targets[n].source;
|
||||
bb.x0 = FFMIN(bb.x0, s.x0);
|
||||
bb.y0 = FFMIN(bb.y0, s.y0);
|
||||
bb.x1 = FFMAX(bb.x1, s.x1);
|
||||
bb.y1 = FFMAX(bb.y1, s.y1);
|
||||
}
|
||||
|
||||
// avoid degenerate bounding box if empty
|
||||
bb.x0 = FFMIN(bb.x0, bb.x1);
|
||||
bb.y0 = FFMIN(bb.y0, bb.y1);
|
||||
|
||||
*out_bb = bb;
|
||||
return state->targets_count > 0;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* This file is part of mplayer2.
|
||||
*
|
||||
* mplayer2 is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mplayer2 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mplayer2; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPLAYER_EOSD_PACKER_H
|
||||
#define MPLAYER_EOSD_PACKER_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "sub/ass_mp.h"
|
||||
|
||||
// Pool of surfaces
|
||||
struct eosd_surface {
|
||||
//void *native_surface;
|
||||
int w;
|
||||
int h;
|
||||
};
|
||||
|
||||
struct eosd_rect {
|
||||
int x0, y0, x1, y1;
|
||||
};
|
||||
|
||||
// List of surfaces to be rendered
|
||||
struct eosd_target {
|
||||
struct eosd_rect source; // position in EOSD surface
|
||||
struct eosd_rect dest; // position on screen
|
||||
uint32_t color; // libass-style color of the image
|
||||
// NOTE: This must not be accessed after you return from your VO's
|
||||
// VOCTRL_DRAW_EOSD call - libass will free or reuse the associated
|
||||
// memory. Feel free to set this to NULL to make erroneous accesses to
|
||||
// this member fail early.
|
||||
ASS_Image *ass_img;
|
||||
};
|
||||
|
||||
struct eosd_packer {
|
||||
struct eosd_surface surface;
|
||||
struct eosd_target *targets;
|
||||
int targets_count; // number of valid elements in targets
|
||||
int targets_size; // number of allocated elements in targets
|
||||
|
||||
uint32_t max_surface_width;
|
||||
uint32_t max_surface_height;
|
||||
|
||||
int *scratch;
|
||||
};
|
||||
|
||||
struct eosd_packer *eosd_packer_create(void *talloc_ctx);
|
||||
void eosd_packer_reinit(struct eosd_packer *state, uint32_t max_width,
|
||||
uint32_t max_height);
|
||||
void eosd_packer_generate(struct eosd_packer *state, mp_eosd_images_t *imgs,
|
||||
bool *out_need_reposition, bool *out_need_upload,
|
||||
bool *out_need_reallocate);
|
||||
bool eosd_packer_calculate_source_bb(struct eosd_packer *state,
|
||||
struct eosd_rect *out_bb);
|
||||
|
||||
#endif /* MPLAYER_EOSD_PACKER_H */
|
||||
@@ -360,6 +360,12 @@ static const extfunc_desc_t extfuncs[] = {
|
||||
DEF_FUNC_DESC(ColorMask),
|
||||
DEF_FUNC_DESC(ReadPixels),
|
||||
DEF_FUNC_DESC(ReadBuffer),
|
||||
DEF_FUNC_DESC(VertexPointer),
|
||||
DEF_FUNC_DESC(ColorPointer),
|
||||
DEF_FUNC_DESC(TexCoordPointer),
|
||||
DEF_FUNC_DESC(DrawArrays),
|
||||
DEF_FUNC_DESC(EnableClientState),
|
||||
DEF_FUNC_DESC(DisableClientState),
|
||||
|
||||
DEF_EXT_DESC(GenBuffers, NULL,
|
||||
("glGenBuffers", "glGenBuffersARB")),
|
||||
|
||||
@@ -463,6 +463,13 @@ struct GL {
|
||||
void (GLAPIENTRY *ReadPixels)(GLint, GLint, GLsizei, GLsizei, GLenum,
|
||||
GLenum, GLvoid *);
|
||||
void (GLAPIENTRY *ReadBuffer)(GLenum);
|
||||
void (GLAPIENTRY *VertexPointer)(GLint, GLenum, GLsizei, const GLvoid *);
|
||||
void (GLAPIENTRY *ColorPointer)(GLint, GLenum, GLsizei, const GLvoid *);
|
||||
void (GLAPIENTRY *TexCoordPointer)(GLint, GLenum, GLsizei, const GLvoid *);
|
||||
void (GLAPIENTRY *DrawArrays)(GLenum, GLint, GLsizei);
|
||||
void (GLAPIENTRY *EnableClientState)(GLenum);
|
||||
void (GLAPIENTRY *DisableClientState)(GLenum);
|
||||
|
||||
|
||||
// OpenGL extension functions
|
||||
void (GLAPIENTRY *GenBuffers)(GLsizei, GLuint *);
|
||||
|
||||
+116
-150
@@ -38,6 +38,7 @@
|
||||
#include "osd.h"
|
||||
#include "sub/font_load.h"
|
||||
#include "sub/sub.h"
|
||||
#include "eosd_packer.h"
|
||||
|
||||
#include "gl_common.h"
|
||||
#include "aspect.h"
|
||||
@@ -49,19 +50,17 @@ static int preinit_nosw(struct vo *vo, const char *arg);
|
||||
//! How many parts the OSD may consist of at most
|
||||
#define MAX_OSD_PARTS 20
|
||||
|
||||
#define LARGE_EOSD_TEX_SIZE 512
|
||||
#define TINYTEX_SIZE 16
|
||||
#define TINYTEX_COLS (LARGE_EOSD_TEX_SIZE / TINYTEX_SIZE)
|
||||
#define TINYTEX_MAX (TINYTEX_COLS * TINYTEX_COLS)
|
||||
#define SMALLTEX_SIZE 32
|
||||
#define SMALLTEX_COLS (LARGE_EOSD_TEX_SIZE / SMALLTEX_SIZE)
|
||||
#define SMALLTEX_MAX (SMALLTEX_COLS * SMALLTEX_COLS)
|
||||
|
||||
//for gl_priv.use_yuv
|
||||
#define MASK_ALL_YUV (~(1 << YUV_CONVERSION_NONE))
|
||||
#define MASK_NOT_COMBINERS (~((1 << YUV_CONVERSION_NONE) | (1 << YUV_CONVERSION_COMBINERS)))
|
||||
#define MASK_GAMMA_SUPPORT (MASK_NOT_COMBINERS & ~(1 << YUV_CONVERSION_FRAGMENT))
|
||||
|
||||
struct vertex_eosd {
|
||||
float x, y;
|
||||
uint8_t color[4];
|
||||
float u, v;
|
||||
};
|
||||
|
||||
struct gl_priv {
|
||||
MPGLContext *glctx;
|
||||
GL *gl;
|
||||
@@ -74,17 +73,17 @@ struct gl_priv {
|
||||
//! Alpha textures for OSD
|
||||
GLuint osdatex[MAX_OSD_PARTS];
|
||||
#endif
|
||||
GLuint *eosdtex;
|
||||
GLuint largeeosdtex[2];
|
||||
GLuint eosd_texture;
|
||||
int eosd_texture_width, eosd_texture_height;
|
||||
struct eosd_packer *eosd;
|
||||
struct vertex_eosd *eosd_va;
|
||||
//! Display lists that draw the OSD parts
|
||||
GLuint osdDispList[MAX_OSD_PARTS];
|
||||
#ifndef FAST_OSD
|
||||
GLuint osdaDispList[MAX_OSD_PARTS];
|
||||
#endif
|
||||
GLuint eosdDispList;
|
||||
//! How many parts the OSD currently consists of
|
||||
int osdtexCnt;
|
||||
int eosdtexCnt;
|
||||
int osd_color;
|
||||
|
||||
int use_ycbcr;
|
||||
@@ -284,151 +283,112 @@ static void clearOSD(struct vo *vo)
|
||||
p->osdtexCnt = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief remove textures, display list and free memory used by EOSD
|
||||
*/
|
||||
static void clearEOSD(struct vo *vo)
|
||||
{
|
||||
struct gl_priv *p = vo->priv;
|
||||
GL *gl = p->gl;
|
||||
|
||||
if (p->eosdDispList)
|
||||
gl->DeleteLists(p->eosdDispList, 1);
|
||||
p->eosdDispList = 0;
|
||||
if (p->eosdtexCnt)
|
||||
gl->DeleteTextures(p->eosdtexCnt, p->eosdtex);
|
||||
p->eosdtexCnt = 0;
|
||||
free(p->eosdtex);
|
||||
p->eosdtex = NULL;
|
||||
}
|
||||
|
||||
static inline int is_tinytex(ASS_Image *i, int tinytexcur)
|
||||
{
|
||||
return i->w < TINYTEX_SIZE && i->h < TINYTEX_SIZE
|
||||
&& tinytexcur < TINYTEX_MAX;
|
||||
}
|
||||
|
||||
static inline int is_smalltex(ASS_Image *i, int smalltexcur)
|
||||
{
|
||||
return i->w < SMALLTEX_SIZE && i->h < SMALLTEX_SIZE
|
||||
&& smalltexcur < SMALLTEX_MAX;
|
||||
}
|
||||
|
||||
static inline void tinytex_pos(int tinytexcur, int *x, int *y)
|
||||
{
|
||||
*x = (tinytexcur % TINYTEX_COLS) * TINYTEX_SIZE;
|
||||
*y = (tinytexcur / TINYTEX_COLS) * TINYTEX_SIZE;
|
||||
}
|
||||
|
||||
static inline void smalltex_pos(int smalltexcur, int *x, int *y)
|
||||
{
|
||||
*x = (smalltexcur % SMALLTEX_COLS) * SMALLTEX_SIZE;
|
||||
*y = (smalltexcur / SMALLTEX_COLS) * SMALLTEX_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief construct display list from ass image list
|
||||
* \param img image list to create OSD from.
|
||||
* A value of NULL has the same effect as clearEOSD()
|
||||
*/
|
||||
static void genEOSD(struct vo *vo, mp_eosd_images_t *imgs)
|
||||
{
|
||||
struct gl_priv *p = vo->priv;
|
||||
GL *gl = p->gl;
|
||||
|
||||
int sx, sy;
|
||||
int tinytexcur = 0;
|
||||
int smalltexcur = 0;
|
||||
GLuint *curtex;
|
||||
GLint scale_type = p->scaled_osd ? GL_LINEAR : GL_NEAREST;
|
||||
ASS_Image *img = imgs->imgs;
|
||||
ASS_Image *i;
|
||||
bool need_repos, need_upload, need_allocate;
|
||||
eosd_packer_generate(p->eosd, imgs, &need_repos, &need_upload,
|
||||
&need_allocate);
|
||||
|
||||
if (imgs->changed == 0) // there are elements, but they are unchanged
|
||||
if (!need_repos)
|
||||
return;
|
||||
if (img && imgs->changed == 1) // there are elements, but they just moved
|
||||
goto skip_upload;
|
||||
|
||||
clearEOSD(vo);
|
||||
if (!img)
|
||||
if (!p->eosd_texture)
|
||||
gl->GenTextures(1, &p->eosd_texture);
|
||||
|
||||
gl->BindTexture(p->target, p->eosd_texture);
|
||||
|
||||
if (need_allocate) {
|
||||
texSize(vo, p->eosd->surface.w, p->eosd->surface.h,
|
||||
&p->eosd_texture_width, &p->eosd_texture_height);
|
||||
// xxx it doesn't need to be cleared, that's a waste of time
|
||||
glCreateClearTex(gl, p->target, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE,
|
||||
GL_NEAREST, p->eosd_texture_width,
|
||||
p->eosd_texture_height, 0);
|
||||
}
|
||||
|
||||
// 2 triangles primitives per quad = 6 vertices per quad
|
||||
// not using GL_QUADS, as it is deprecated in OpenGL 3.x and later
|
||||
p->eosd_va = talloc_realloc_size(p->eosd, p->eosd_va,
|
||||
p->eosd->targets_count
|
||||
* sizeof(struct vertex_eosd) * 6);
|
||||
|
||||
float eosd_w = p->eosd_texture_width;
|
||||
float eosd_h = p->eosd_texture_height;
|
||||
|
||||
if (p->use_rectangle == 1)
|
||||
eosd_w = eosd_h = 1.0f;
|
||||
|
||||
for (int n = 0; n < p->eosd->targets_count; n++) {
|
||||
struct eosd_target *target = &p->eosd->targets[n];
|
||||
ASS_Image *i = target->ass_img;
|
||||
|
||||
if (need_upload) {
|
||||
glUploadTex(gl, p->target, GL_ALPHA, GL_UNSIGNED_BYTE, i->bitmap,
|
||||
i->stride, target->source.x0, target->source.y0,
|
||||
i->w, i->h, 0);
|
||||
}
|
||||
|
||||
uint8_t color[4] = { i->color >> 24, (i->color >> 16) & 0xff,
|
||||
(i->color >> 8) & 0xff, 255 - (i->color & 0xff) };
|
||||
|
||||
float x0 = target->dest.x0;
|
||||
float y0 = target->dest.y0;
|
||||
float x1 = target->dest.x1;
|
||||
float y1 = target->dest.y1;
|
||||
float tx0 = target->source.x0 / eosd_w;
|
||||
float ty0 = target->source.y0 / eosd_h;
|
||||
float tx1 = target->source.x1 / eosd_w;
|
||||
float ty1 = target->source.y1 / eosd_h;
|
||||
|
||||
#define COLOR_INIT {color[0], color[1], color[2], color[3]}
|
||||
struct vertex_eosd *va = &p->eosd_va[n * 6];
|
||||
va[0] = (struct vertex_eosd) { x0, y0, COLOR_INIT, tx0, ty0 };
|
||||
va[1] = (struct vertex_eosd) { x0, y1, COLOR_INIT, tx0, ty1 };
|
||||
va[2] = (struct vertex_eosd) { x1, y0, COLOR_INIT, tx1, ty0 };
|
||||
va[3] = (struct vertex_eosd) { x1, y1, COLOR_INIT, tx1, ty1 };
|
||||
va[4] = va[2];
|
||||
va[5] = va[1];
|
||||
#undef COLOR_INIT
|
||||
}
|
||||
|
||||
gl->BindTexture(p->target, 0);
|
||||
}
|
||||
|
||||
// Note: relies on state being setup, like projection matrix and blending
|
||||
static void drawEOSD(struct vo *vo)
|
||||
{
|
||||
struct gl_priv *p = vo->priv;
|
||||
GL *gl = p->gl;
|
||||
|
||||
if (p->eosd->targets_count == 0)
|
||||
return;
|
||||
if (!p->largeeosdtex[0]) {
|
||||
gl->GenTextures(2, p->largeeosdtex);
|
||||
for (int n = 0; n < 2; n++) {
|
||||
gl->BindTexture(p->target, p->largeeosdtex[n]);
|
||||
glCreateClearTex(gl, p->target, GL_ALPHA, GL_ALPHA,
|
||||
GL_UNSIGNED_BYTE, scale_type,
|
||||
LARGE_EOSD_TEX_SIZE, LARGE_EOSD_TEX_SIZE, 0);
|
||||
}
|
||||
}
|
||||
for (i = img; i; i = i->next) {
|
||||
if (i->w <= 0 || i->h <= 0 || i->stride < i->w)
|
||||
continue;
|
||||
if (is_tinytex(i, tinytexcur))
|
||||
tinytexcur++;
|
||||
else if (is_smalltex(i, smalltexcur))
|
||||
smalltexcur++;
|
||||
else
|
||||
p->eosdtexCnt++;
|
||||
}
|
||||
mp_msg(MSGT_VO, MSGL_DBG2, "EOSD counts (tiny, small, all): %i, %i, %i\n",
|
||||
tinytexcur, smalltexcur, p->eosdtexCnt);
|
||||
if (p->eosdtexCnt) {
|
||||
p->eosdtex = calloc(p->eosdtexCnt, sizeof(GLuint));
|
||||
gl->GenTextures(p->eosdtexCnt, p->eosdtex);
|
||||
}
|
||||
tinytexcur = smalltexcur = 0;
|
||||
for (i = img, curtex = p->eosdtex; i; i = i->next) {
|
||||
int x = 0, y = 0;
|
||||
if (i->w <= 0 || i->h <= 0 || i->stride < i->w) {
|
||||
mp_msg(MSGT_VO, MSGL_V, "Invalid dimensions OSD for part!\n");
|
||||
continue;
|
||||
}
|
||||
if (is_tinytex(i, tinytexcur)) {
|
||||
tinytex_pos(tinytexcur, &x, &y);
|
||||
gl->BindTexture(p->target, p->largeeosdtex[0]);
|
||||
tinytexcur++;
|
||||
} else if (is_smalltex(i, smalltexcur)) {
|
||||
smalltex_pos(smalltexcur, &x, &y);
|
||||
gl->BindTexture(p->target, p->largeeosdtex[1]);
|
||||
smalltexcur++;
|
||||
} else {
|
||||
texSize(vo, i->w, i->h, &sx, &sy);
|
||||
gl->BindTexture(p->target, *curtex++);
|
||||
glCreateClearTex(gl, p->target, GL_ALPHA, GL_ALPHA,
|
||||
GL_UNSIGNED_BYTE, scale_type, sx, sy, 0);
|
||||
}
|
||||
glUploadTex(gl, p->target, GL_ALPHA, GL_UNSIGNED_BYTE, i->bitmap,
|
||||
i->stride, x, y, i->w, i->h, 0);
|
||||
}
|
||||
p->eosdDispList = gl->GenLists(1);
|
||||
skip_upload:
|
||||
gl->NewList(p->eosdDispList, GL_COMPILE);
|
||||
tinytexcur = smalltexcur = 0;
|
||||
for (i = img, curtex = p->eosdtex; i; i = i->next) {
|
||||
int x = 0, y = 0;
|
||||
if (i->w <= 0 || i->h <= 0 || i->stride < i->w)
|
||||
continue;
|
||||
gl->Color4ub(i->color >> 24, (i->color >> 16) & 0xff,
|
||||
(i->color >> 8) & 0xff, 255 - (i->color & 0xff));
|
||||
if (is_tinytex(i, tinytexcur)) {
|
||||
tinytex_pos(tinytexcur, &x, &y);
|
||||
sx = sy = LARGE_EOSD_TEX_SIZE;
|
||||
gl->BindTexture(p->target, p->largeeosdtex[0]);
|
||||
tinytexcur++;
|
||||
} else if (is_smalltex(i, smalltexcur)) {
|
||||
smalltex_pos(smalltexcur, &x, &y);
|
||||
sx = sy = LARGE_EOSD_TEX_SIZE;
|
||||
gl->BindTexture(p->target, p->largeeosdtex[1]);
|
||||
smalltexcur++;
|
||||
} else {
|
||||
texSize(vo, i->w, i->h, &sx, &sy);
|
||||
gl->BindTexture(p->target, *curtex++);
|
||||
}
|
||||
glDrawTex(gl, i->dst_x, i->dst_y, i->w, i->h, x, y, i->w, i->h, sx, sy,
|
||||
p->use_rectangle == 1, 0, 0);
|
||||
}
|
||||
gl->EndList();
|
||||
|
||||
gl->BindTexture(p->target, p->eosd_texture);
|
||||
|
||||
struct vertex_eosd *va = p->eosd_va;
|
||||
size_t stride = sizeof(struct vertex_eosd);
|
||||
|
||||
gl->VertexPointer(2, GL_FLOAT, stride, &va[0].x);
|
||||
gl->ColorPointer(4, GL_UNSIGNED_BYTE, stride, &va[0].color[0]);
|
||||
gl->TexCoordPointer(2, GL_FLOAT, stride, &va[0].u);
|
||||
|
||||
gl->EnableClientState(GL_VERTEX_ARRAY);
|
||||
gl->EnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
gl->EnableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
gl->DrawArrays(GL_TRIANGLES, 0, p->eosd->targets_count * 6);
|
||||
|
||||
gl->DisableClientState(GL_VERTEX_ARRAY);
|
||||
gl->DisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
gl->DisableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
gl->BindTexture(p->target, 0);
|
||||
}
|
||||
|
||||
@@ -450,10 +410,10 @@ static void uninitGl(struct vo *vo)
|
||||
gl->DeleteTextures(i, p->default_texs);
|
||||
p->default_texs[0] = 0;
|
||||
clearOSD(vo);
|
||||
clearEOSD(vo);
|
||||
if (p->largeeosdtex[0])
|
||||
gl->DeleteTextures(2, p->largeeosdtex);
|
||||
p->largeeosdtex[0] = 0;
|
||||
if (p->eosd_texture)
|
||||
gl->DeleteTextures(1, &p->eosd_texture);
|
||||
eosd_packer_reinit(p->eosd, 0, 0);
|
||||
p->eosd_texture = 0;
|
||||
if (gl->DeleteBuffers && p->buffer)
|
||||
gl->DeleteBuffers(1, &p->buffer);
|
||||
p->buffer = 0;
|
||||
@@ -633,6 +593,10 @@ static int initGl(struct vo *vo, uint32_t d_width, uint32_t d_height)
|
||||
update_yuvconv(vo);
|
||||
}
|
||||
|
||||
GLint max_texture_size;
|
||||
gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
|
||||
eosd_packer_reinit(p->eosd, max_texture_size, max_texture_size);
|
||||
|
||||
resize(vo, d_width, d_height);
|
||||
|
||||
gl->ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
@@ -786,7 +750,7 @@ static void do_render_osd(struct vo *vo, int type)
|
||||
GL *gl = p->gl;
|
||||
|
||||
int draw_osd = (type & RENDER_OSD) && p->osdtexCnt > 0;
|
||||
int draw_eosd = (type & RENDER_EOSD) && p->eosdDispList;
|
||||
int draw_eosd = (type & RENDER_EOSD);
|
||||
if (!draw_osd && !draw_eosd)
|
||||
return;
|
||||
// set special rendering parameters
|
||||
@@ -799,7 +763,7 @@ static void do_render_osd(struct vo *vo, int type)
|
||||
gl->Enable(GL_BLEND);
|
||||
if (draw_eosd) {
|
||||
gl->BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
gl->CallList(p->eosdDispList);
|
||||
drawEOSD(vo);
|
||||
}
|
||||
if (draw_osd) {
|
||||
gl->Color4ub((p->osd_color >> 16) & 0xff, (p->osd_color >> 8) & 0xff,
|
||||
@@ -1239,6 +1203,8 @@ static int preinit_internal(struct vo *vo, const char *arg, int allow_sw,
|
||||
.osd_color = 0xffffff,
|
||||
};
|
||||
|
||||
p->eosd = eosd_packer_create(vo);
|
||||
|
||||
//essentially unused; for legacy warnings only
|
||||
int user_colorspace = 0;
|
||||
int levelconv = -1;
|
||||
|
||||
+51
-198
@@ -56,6 +56,7 @@
|
||||
#include "libavutil/mathematics.h"
|
||||
|
||||
#include "sub/ass_mp.h"
|
||||
#include "eosd_packer.h"
|
||||
|
||||
#define WRAP_ADD(x, a, m) ((a) < 0 \
|
||||
? ((x)+(a)+(m) < (m) ? (x)+(a)+(m) : (x)+(a)) \
|
||||
@@ -85,9 +86,6 @@
|
||||
/* number of palette entries */
|
||||
#define PALETTE_SIZE 256
|
||||
|
||||
/* Initial size of EOSD surface in pixels (x*x) */
|
||||
#define EOSD_SURFACE_INITIAL_SIZE 256
|
||||
|
||||
/* Pixelformat used for output surfaces */
|
||||
#define OUTPUT_RGBA_FORMAT VDP_RGBA_FORMAT_B8G8R8A8
|
||||
|
||||
@@ -173,24 +171,8 @@ struct vdpctx {
|
||||
|
||||
// EOSD
|
||||
// Pool of surfaces
|
||||
struct eosd_bitmap_surface {
|
||||
VdpBitmapSurface surface;
|
||||
int w;
|
||||
int h;
|
||||
uint32_t max_width;
|
||||
uint32_t max_height;
|
||||
} eosd_surface;
|
||||
|
||||
// List of surfaces to be rendered
|
||||
struct eosd_target {
|
||||
VdpRect source;
|
||||
VdpRect dest;
|
||||
VdpColor color;
|
||||
} *eosd_targets;
|
||||
int eosd_targets_size;
|
||||
int *eosd_scratch;
|
||||
|
||||
int eosd_render_count;
|
||||
VdpBitmapSurface eosd_surface;
|
||||
struct eosd_packer *eosd_packer;
|
||||
|
||||
// Video equalizer
|
||||
struct mp_csp_equalizer video_eq;
|
||||
@@ -796,13 +778,16 @@ static int initialize_vdpau_objects(struct vo *vo)
|
||||
if (create_vdp_mixer(vo, vc->vdp_chroma_type) < 0)
|
||||
return -1;
|
||||
|
||||
int max_width = 0, max_height = 0;
|
||||
vdp_st = vdp->
|
||||
bitmap_surface_query_capabilities(vc->vdp_device,
|
||||
VDP_RGBA_FORMAT_A8,
|
||||
&(VdpBool){0},
|
||||
&vc->eosd_surface.max_width,
|
||||
&vc->eosd_surface.max_height);
|
||||
&max_width,
|
||||
&max_height);
|
||||
CHECK_ST_WARNING("Query to get max EOSD surface size failed");
|
||||
eosd_packer_reinit(vc->eosd_packer, max_width, max_height);
|
||||
|
||||
forget_frames(vo);
|
||||
resize(vo);
|
||||
return 0;
|
||||
@@ -822,11 +807,9 @@ static void mark_vdpau_objects_uninitialized(struct vo *vo)
|
||||
for (int i = 0; i <= MAX_OUTPUT_SURFACES; i++)
|
||||
vc->output_surfaces[i] = VDP_INVALID_HANDLE;
|
||||
vc->vdp_device = VDP_INVALID_HANDLE;
|
||||
vc->eosd_surface = (struct eosd_bitmap_surface){
|
||||
.surface = VDP_INVALID_HANDLE,
|
||||
};
|
||||
vc->eosd_surface = VDP_INVALID_HANDLE;
|
||||
eosd_packer_reinit(vc->eosd_packer, 0, 0);
|
||||
vc->output_surface_width = vc->output_surface_height = -1;
|
||||
vc->eosd_render_count = 0;
|
||||
}
|
||||
|
||||
static int handle_preemption(struct vo *vo)
|
||||
@@ -1022,6 +1005,8 @@ static void draw_osd_I8A8(void *ctx, int x0, int y0, int w, int h,
|
||||
"vdp_output_surface_render_output_surface");
|
||||
}
|
||||
|
||||
#define EOSD_VDP_RC(r) &(VdpRect){r.x0, r.y0, r.x1, r.y1}
|
||||
|
||||
static void draw_eosd(struct vo *vo)
|
||||
{
|
||||
struct vdpctx *vc = vo->priv;
|
||||
@@ -1044,200 +1029,66 @@ static void draw_eosd(struct vo *vo)
|
||||
.blend_equation_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD,
|
||||
};
|
||||
|
||||
for (i = 0; i < vc->eosd_render_count; i++) {
|
||||
for (i = 0; i < vc->eosd_packer->targets_count; i++) {
|
||||
struct eosd_target *target = &vc->eosd_packer->targets[i];
|
||||
VdpColor color = {
|
||||
.alpha = 1.0 - ((target->color >> 0) & 0xff) / 255.0,
|
||||
.blue = ((target->color >> 8) & 0xff) / 255.0,
|
||||
.green = ((target->color >> 16) & 0xff) / 255.0,
|
||||
.red = ((target->color >> 24) & 0xff) / 255.0,
|
||||
};
|
||||
vdp_st = vdp->
|
||||
output_surface_render_bitmap_surface(output_surface,
|
||||
&vc->eosd_targets[i].dest,
|
||||
vc->eosd_surface.surface,
|
||||
&vc->eosd_targets[i].source,
|
||||
&vc->eosd_targets[i].color,
|
||||
EOSD_VDP_RC(target->dest),
|
||||
vc->eosd_surface,
|
||||
EOSD_VDP_RC(target->source),
|
||||
&color,
|
||||
&blend_state,
|
||||
VDP_OUTPUT_SURFACE_RENDER_ROTATE_0);
|
||||
CHECK_ST_WARNING("EOSD: Error when rendering");
|
||||
}
|
||||
}
|
||||
|
||||
#define HEIGHT_SORT_BITS 4
|
||||
static int size_index(struct eosd_target *r)
|
||||
{
|
||||
unsigned int h = r->source.y1;
|
||||
int n = av_log2_16bit(h);
|
||||
return (n << HEIGHT_SORT_BITS)
|
||||
+ (- 1 - (h << HEIGHT_SORT_BITS >> n) & (1 << HEIGHT_SORT_BITS) - 1);
|
||||
}
|
||||
|
||||
/* Pack the given rectangles into an area of size w * h.
|
||||
* The size of each rectangle is read from .source.x1/.source.y1.
|
||||
* The height of each rectangle must be at least 1 and less than 65536.
|
||||
* The .source rectangle is then set corresponding to the packed position.
|
||||
* 'scratch' must point to work memory for num_rects+16 ints.
|
||||
* Return 0 on success, -1 if the rectangles did not fit in w*h.
|
||||
*
|
||||
* The rectangles are placed in rows in order approximately sorted by
|
||||
* height (the approximate sorting is simpler than a full one would be,
|
||||
* and allows the algorithm to work in linear time). Additionally, to
|
||||
* reduce wasted space when there are a few tall rectangles, empty
|
||||
* lower-right parts of rows are filled recursively when the size of
|
||||
* rectangles in the row drops past a power-of-two threshold. So if a
|
||||
* row starts with rectangles of size 3x50, 10x40 and 5x20 then the
|
||||
* free rectangle with corners (13, 20)-(w, 50) is filled recursively.
|
||||
*/
|
||||
static int pack_rectangles(struct eosd_target *rects, int num_rects,
|
||||
int w, int h, int *scratch)
|
||||
{
|
||||
int bins[16 << HEIGHT_SORT_BITS];
|
||||
int sizes[16 << HEIGHT_SORT_BITS] = {};
|
||||
for (int i = 0; i < num_rects; i++)
|
||||
sizes[size_index(rects + i)]++;
|
||||
int idx = 0;
|
||||
for (int i = 0; i < 16 << HEIGHT_SORT_BITS; i += 1 << HEIGHT_SORT_BITS) {
|
||||
for (int j = 0; j < 1 << HEIGHT_SORT_BITS; j++) {
|
||||
bins[i + j] = idx;
|
||||
idx += sizes[i + j];
|
||||
}
|
||||
scratch[idx++] = -1;
|
||||
}
|
||||
for (int i = 0; i < num_rects; i++)
|
||||
scratch[bins[size_index(rects + i)]++] = i;
|
||||
for (int i = 0; i < 16; i++)
|
||||
bins[i] = bins[i << HEIGHT_SORT_BITS] - sizes[i << HEIGHT_SORT_BITS];
|
||||
struct {
|
||||
int size, x, bottom;
|
||||
} stack[16] = {{15, 0, h}}, s = {};
|
||||
int stackpos = 1;
|
||||
int y;
|
||||
while (stackpos) {
|
||||
y = s.bottom;
|
||||
s = stack[--stackpos];
|
||||
s.size++;
|
||||
while (s.size--) {
|
||||
int maxy = -1;
|
||||
int obj;
|
||||
while ((obj = scratch[bins[s.size]]) >= 0) {
|
||||
int bottom = y + rects[obj].source.y1;
|
||||
if (bottom > s.bottom)
|
||||
break;
|
||||
int right = s.x + rects[obj].source.x1;
|
||||
if (right > w)
|
||||
break;
|
||||
bins[s.size]++;
|
||||
rects[obj].source.x0 = s.x;
|
||||
rects[obj].source.x1 += s.x;
|
||||
rects[obj].source.y0 = y;
|
||||
rects[obj].source.y1 += y;
|
||||
num_rects--;
|
||||
if (maxy <= 0)
|
||||
stack[stackpos++] = s;
|
||||
s.x = right;
|
||||
maxy = FFMAX(maxy, bottom);
|
||||
}
|
||||
if (maxy > 0)
|
||||
s.bottom = maxy;
|
||||
}
|
||||
}
|
||||
return num_rects ? -1 : 0;
|
||||
}
|
||||
|
||||
static void generate_eosd(struct vo *vo, mp_eosd_images_t *imgs)
|
||||
{
|
||||
struct vdpctx *vc = vo->priv;
|
||||
struct vdp_functions *vdp = vc->vdp;
|
||||
VdpStatus vdp_st;
|
||||
struct eosd_packer *packer = vc->eosd_packer;
|
||||
int i;
|
||||
ASS_Image *img = imgs->imgs;
|
||||
ASS_Image *p;
|
||||
struct eosd_bitmap_surface *sfc = &vc->eosd_surface;
|
||||
bool need_upload = false;
|
||||
|
||||
if (imgs->changed == 0)
|
||||
return; // Nothing changed, no need to redraw
|
||||
bool need_repos, need_upload, need_resize;
|
||||
eosd_packer_generate(packer, imgs, &need_repos, &need_upload, &need_resize);
|
||||
|
||||
vc->eosd_render_count = 0;
|
||||
if (!need_upload)
|
||||
return;
|
||||
|
||||
if (!img)
|
||||
return; // There's nothing to render!
|
||||
|
||||
if (imgs->changed == 1)
|
||||
goto eosd_skip_upload;
|
||||
|
||||
need_upload = true;
|
||||
bool reallocate = false;
|
||||
while (1) {
|
||||
for (p = img, i = 0; p; p = p->next) {
|
||||
if (p->w <= 0 || p->h <= 0)
|
||||
continue;
|
||||
// Allocate new space for surface/target arrays
|
||||
if (i >= vc->eosd_targets_size) {
|
||||
vc->eosd_targets_size = FFMAX(vc->eosd_targets_size * 2, 512);
|
||||
vc->eosd_targets =
|
||||
talloc_realloc_size(vc, vc->eosd_targets,
|
||||
vc->eosd_targets_size
|
||||
* sizeof(*vc->eosd_targets));
|
||||
vc->eosd_scratch =
|
||||
talloc_realloc_size(vc, vc->eosd_scratch,
|
||||
(vc->eosd_targets_size + 16)
|
||||
* sizeof(*vc->eosd_scratch));
|
||||
}
|
||||
vc->eosd_targets[i].source.x1 = p->w;
|
||||
vc->eosd_targets[i].source.y1 = p->h;
|
||||
i++;
|
||||
}
|
||||
if (pack_rectangles(vc->eosd_targets, i, sfc->w, sfc->h,
|
||||
vc->eosd_scratch) >= 0)
|
||||
break;
|
||||
int w = FFMIN(FFMAX(sfc->w * 2, EOSD_SURFACE_INITIAL_SIZE),
|
||||
sfc->max_width);
|
||||
int h = FFMIN(FFMAX(sfc->h * 2, EOSD_SURFACE_INITIAL_SIZE),
|
||||
sfc->max_height);
|
||||
if (w == sfc->w && h == sfc->h) {
|
||||
mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] EOSD bitmaps do not fit on "
|
||||
"a surface with the maximum supported size\n");
|
||||
return;
|
||||
} else {
|
||||
sfc->w = w;
|
||||
sfc->h = h;
|
||||
}
|
||||
reallocate = true;
|
||||
}
|
||||
if (reallocate) {
|
||||
if (sfc->surface != VDP_INVALID_HANDLE) {
|
||||
vdp_st = vdp->bitmap_surface_destroy(sfc->surface);
|
||||
if (need_resize) {
|
||||
if (vc->eosd_surface != VDP_INVALID_HANDLE) {
|
||||
vdp_st = vdp->bitmap_surface_destroy(vc->eosd_surface);
|
||||
CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy");
|
||||
}
|
||||
mp_msg(MSGT_VO, MSGL_V, "[vdpau] Allocating a %dx%d surface for "
|
||||
"EOSD bitmaps.\n", sfc->w, sfc->h);
|
||||
vdp_st = vdp->bitmap_surface_create(vc->vdp_device, VDP_RGBA_FORMAT_A8,
|
||||
sfc->w, sfc->h, true,
|
||||
&sfc->surface);
|
||||
packer->surface.w, packer->surface.h,
|
||||
true, &vc->eosd_surface);
|
||||
if (vdp_st != VDP_STATUS_OK)
|
||||
sfc->surface = VDP_INVALID_HANDLE;
|
||||
vc->eosd_surface = VDP_INVALID_HANDLE;
|
||||
CHECK_ST_WARNING("EOSD: error when creating surface");
|
||||
}
|
||||
|
||||
eosd_skip_upload:
|
||||
if (sfc->surface == VDP_INVALID_HANDLE)
|
||||
if (vc->eosd_surface == VDP_INVALID_HANDLE)
|
||||
return;
|
||||
for (p = img; p; p = p->next) {
|
||||
if (p->w <= 0 || p->h <= 0)
|
||||
continue;
|
||||
struct eosd_target *target = &vc->eosd_targets[vc->eosd_render_count];
|
||||
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++;
|
||||
|
||||
for (i = 0; i < vc->eosd_packer->targets_count; i++) {
|
||||
struct eosd_target *target = &vc->eosd_packer->targets[i];
|
||||
ASS_Image *p = target->ass_img;
|
||||
vdp_st = vdp->
|
||||
bitmap_surface_put_bits_native(vc->eosd_surface,
|
||||
(const void *) &p->bitmap,
|
||||
&p->stride,
|
||||
EOSD_VDP_RC(target->source));
|
||||
CHECK_ST_WARNING("EOSD: putbits failed");
|
||||
target->ass_img = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1603,8 +1454,8 @@ static void destroy_vdpau_objects(struct vo *vo)
|
||||
CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy");
|
||||
}
|
||||
|
||||
if (vc->eosd_surface.surface != VDP_INVALID_HANDLE) {
|
||||
vdp_st = vdp->bitmap_surface_destroy(vc->eosd_surface.surface);
|
||||
if (vc->eosd_surface != VDP_INVALID_HANDLE) {
|
||||
vdp_st = vdp->bitmap_surface_destroy(vc->eosd_surface);
|
||||
CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy");
|
||||
}
|
||||
|
||||
@@ -1639,6 +1490,8 @@ static int preinit(struct vo *vo, const char *arg)
|
||||
struct vdpctx *vc = talloc_zero(vo, struct vdpctx);
|
||||
vo->priv = vc;
|
||||
|
||||
vc->eosd_packer = eosd_packer_create(vo);
|
||||
|
||||
// Mark everything as invalid first so uninit() can tell what has been
|
||||
// allocated
|
||||
mark_vdpau_objects_uninitialized(vo);
|
||||
|
||||
Reference in New Issue
Block a user