mirror of
https://github.com/mpv-player/mpv
synced 2024-12-28 06:03:45 +01:00
sub: add helper to draw sub-bitmaps into an image
Merged by wm4 from commits 93978f17b76d..13211ef5fc20. Changed copyright header in draw_bmp.c to "mpv", and removed the one in draw_bmp.h.
This commit is contained in:
parent
1282f9d79e
commit
aa1047a35a
1
Makefile
1
Makefile
@ -217,6 +217,7 @@ SRCS_COMMON = asxparser.c \
|
||||
sub/spudec.c \
|
||||
sub/sub.c \
|
||||
sub/img_convert.c \
|
||||
sub/draw_bmp.c \
|
||||
sub/subassconvert.c \
|
||||
sub/subreader.c \
|
||||
sub/vobsub.c \
|
||||
|
@ -131,4 +131,28 @@ struct SwsContext *sws_getContextFromCmdLine_hq(int srcW, int srcH,
|
||||
SWS_ACCURATE_RND | SWS_BITEXACT);
|
||||
}
|
||||
|
||||
void mp_image_swscale(struct mp_image *dst,
|
||||
const struct mp_image *src,
|
||||
struct mp_csp_details *csp,
|
||||
int my_sws_flags)
|
||||
{
|
||||
enum PixelFormat dfmt, sfmt;
|
||||
dfmt = imgfmt2pixfmt(dst->imgfmt);
|
||||
sfmt = imgfmt2pixfmt(src->imgfmt);
|
||||
if (src->imgfmt == IMGFMT_RGB8 || src->imgfmt == IMGFMT_BGR8)
|
||||
sfmt = PIX_FMT_PAL8;
|
||||
|
||||
struct SwsContext *sws =
|
||||
sws_getContext(src->w, src->h, sfmt, dst->w, dst->h, dfmt,
|
||||
my_sws_flags, NULL, NULL, NULL);
|
||||
struct mp_csp_details mycsp = MP_CSP_DETAILS_DEFAULTS;
|
||||
if (csp)
|
||||
mycsp = *csp;
|
||||
mp_sws_set_colorspace(sws, &mycsp);
|
||||
sws_scale(sws, (const unsigned char *const *) src->planes, src->stride,
|
||||
0, src->h,
|
||||
dst->planes, dst->stride);
|
||||
sws_freeContext(sws);
|
||||
}
|
||||
|
||||
// vim: ts=4 sw=4 et tw=80
|
||||
|
@ -22,6 +22,9 @@ struct SwsContext *sws_getContextFromCmdLine_hq(int srcW, int srcH,
|
||||
int dstFormat);
|
||||
int mp_sws_set_colorspace(struct SwsContext *sws, struct mp_csp_details *csp);
|
||||
|
||||
void mp_image_swscale(struct mp_image *dst, const struct mp_image *src,
|
||||
struct mp_csp_details *csp, int my_sws_flags);
|
||||
|
||||
#endif /* MP_SWS_UTILS_H */
|
||||
|
||||
// vim: ts=4 sw=4 et tw=80
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <libavutil/common.h>
|
||||
#include "mp_msg.h"
|
||||
|
||||
#include "csputils.h"
|
||||
|
||||
@ -317,3 +318,56 @@ int mp_csp_equalizer_set(struct mp_csp_equalizer *eq, const char *property,
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void mp_invert_yuv2rgb(float out[3][4], float in[3][4])
|
||||
{
|
||||
// this is from the DarkPlaces engine, reduces to 3x3. Original code
|
||||
// released under GPL2 or any later version.
|
||||
float det;
|
||||
|
||||
// this seems to help gcc's common subexpression elimination, and also makes the code look nicer
|
||||
float m00 = in[0][0], m01 = in[0][1], m02 = in[0][2], m03 = in[0][3],
|
||||
m10 = in[1][0], m11 = in[1][1], m12 = in[1][2], m13 = in[1][3],
|
||||
m20 = in[2][0], m21 = in[2][1], m22 = in[2][2], m23 = in[2][3];
|
||||
|
||||
// calculate the adjoint
|
||||
out[0][0] = (m11 * m22 - m21 * m12);
|
||||
out[0][1] = -(m01 * m22 - m21 * m02);
|
||||
out[0][2] = (m01 * m12 - m11 * m02);
|
||||
out[1][0] = -(m10 * m22 - m20 * m12);
|
||||
out[1][1] = (m00 * m22 - m20 * m02);
|
||||
out[1][2] = -(m00 * m12 - m10 * m02);
|
||||
out[2][0] = (m10 * m21 - m20 * m11);
|
||||
out[2][1] = -(m00 * m21 - m20 * m01);
|
||||
out[2][2] = (m00 * m11 - m10 * m01);
|
||||
|
||||
// calculate the determinant (as inverse == 1/det * adjoint, adjoint * m == identity * det, so this calculates the det)
|
||||
det = m00 * out[0][0] + m10 * out[0][1] + m20 * out[0][2];
|
||||
if (det == 0.0f) {
|
||||
//mp_msg(MSGT_VO, MSGL_ERR, "cannot invert yuv2rgb matrix\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// multiplications are faster than divisions, usually
|
||||
det = 1.0f / det;
|
||||
|
||||
// manually unrolled loop to multiply all matrix elements by 1/det
|
||||
out[0][0] *= det;
|
||||
out[0][1] *= det;
|
||||
out[0][2] *= det;
|
||||
out[1][0] *= det;
|
||||
out[1][1] *= det;
|
||||
out[1][2] *= det;
|
||||
out[2][0] *= det;
|
||||
out[2][1] *= det;
|
||||
out[2][2] *= det;
|
||||
|
||||
// fix the constant coefficient
|
||||
// rgb = M * yuv + C
|
||||
// M^-1 * rgb = yuv + M^-1 * C
|
||||
// yuv = M^-1 * rgb - M^-1 * C
|
||||
// ^^^^^^^^^^
|
||||
out[0][3] = -(out[0][0] * m03 + out[0][1] * m13 + out[0][2] * m23);
|
||||
out[1][3] = -(out[1][0] * m03 + out[1][1] * m13 + out[1][2] * m23);
|
||||
out[2][3] = -(out[2][0] * m03 + out[2][1] * m13 + out[2][2] * m23);
|
||||
}
|
||||
|
@ -133,4 +133,14 @@ void mp_gen_gamma_map(unsigned char *map, int size, float gamma);
|
||||
void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float yuv2rgb[3][4]);
|
||||
void mp_gen_yuv2rgb_map(struct mp_csp_params *params, uint8_t *map, int size);
|
||||
|
||||
#define MP_MAP_YUV2RGB_COLOR(m, y, u, v, scale, c) ((m)[c][0] * (y) + \
|
||||
(m)[c][1] * (u) + \
|
||||
(m)[c][2] * (v) + \
|
||||
(m)[c][3] * (scale))
|
||||
#define MP_MAP_RGB2YUV_COLOR(minv, r, g, b, scale, c) ((minv)[c][0] * (r) + \
|
||||
(minv)[c][1] * (g) + \
|
||||
(minv)[c][2] * (b) + \
|
||||
(minv)[c][3] * (scale))
|
||||
void mp_invert_yuv2rgb(float out[3][4], float in[3][4]);
|
||||
|
||||
#endif /* MPLAYER_CSPUTILS_H */
|
||||
|
580
sub/draw_bmp.c
Normal file
580
sub/draw_bmp.c
Normal file
@ -0,0 +1,580 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv 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.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "sub/draw_bmp.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "sub/sub.h"
|
||||
#include "libmpcodecs/mp_image.h"
|
||||
#include "libmpcodecs/sws_utils.h"
|
||||
#include "libmpcodecs/img_format.h"
|
||||
#include "libvo/csputils.h"
|
||||
|
||||
#define ACCURATE
|
||||
#define CONDITIONAL
|
||||
#define CONDITIONAL2
|
||||
|
||||
static void blend_const16_alpha(uint8_t *dst,
|
||||
ssize_t dstRowStride,
|
||||
uint16_t srcp,
|
||||
const uint8_t *srca,
|
||||
ssize_t srcaRowStride,
|
||||
uint8_t srcamul, int rows,
|
||||
int cols)
|
||||
{
|
||||
int i, j;
|
||||
#ifdef CONDITIONAL
|
||||
if (!srcamul)
|
||||
return;
|
||||
#endif
|
||||
for (i = 0; i < rows; ++i) {
|
||||
uint16_t *dstr = (uint16_t *) (dst + dstRowStride * i);
|
||||
const uint8_t *srcar = srca + srcaRowStride * i;
|
||||
for (j = 0; j < cols; ++j) {
|
||||
uint32_t srcap = srcar[j];
|
||||
// 32bit to force the math ops to operate on 32 bit
|
||||
#ifdef CONDITIONAL
|
||||
if (!srcap)
|
||||
continue;
|
||||
#endif
|
||||
#ifdef CONDITIONAL2
|
||||
if (srcap == 255 && srcamul == 255) {
|
||||
dstr[j] = srcp;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
uint16_t dstp = dstr[j];
|
||||
srcap *= srcamul; // now 0..65025
|
||||
uint16_t outp =
|
||||
(srcp * srcap + dstp * (65025 - srcap) + 32512) / 65025;
|
||||
dstr[j] = outp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void blend_src16_alpha(uint8_t *dst,
|
||||
ssize_t dstRowStride,
|
||||
const uint8_t *src,
|
||||
ssize_t srcRowStride,
|
||||
const uint8_t *srca,
|
||||
ssize_t srcaRowStride,
|
||||
int rows,
|
||||
int cols)
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0; i < rows; ++i) {
|
||||
uint16_t *dstr = (uint16_t *) (dst + dstRowStride * i);
|
||||
const uint16_t *srcr = (const uint16_t *) (src + srcRowStride * i);
|
||||
const uint8_t *srcar = srca + srcaRowStride * i;
|
||||
for (j = 0; j < cols; ++j) {
|
||||
uint32_t srcap = srcar[j];
|
||||
// 32bit to force the math ops to operate on 32 bit
|
||||
#ifdef CONDITIONAL
|
||||
if (!srcap)
|
||||
continue;
|
||||
#endif
|
||||
uint16_t srcp = srcr[j];
|
||||
#ifdef CONDITIONAL2
|
||||
if (srcap == 255) {
|
||||
dstr[j] = srcp;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
uint16_t dstp = dstr[j];
|
||||
uint16_t outp =
|
||||
(srcp * srcap + dstp * (255 - srcap) + 127) / 255;
|
||||
dstr[j] = outp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void blend_const8_alpha(uint8_t *dst,
|
||||
ssize_t dstRowStride,
|
||||
uint16_t srcp,
|
||||
const uint8_t *srca,
|
||||
ssize_t srcaRowStride,
|
||||
uint8_t srcamul, int rows,
|
||||
int cols)
|
||||
{
|
||||
int i, j;
|
||||
#ifdef CONDITIONAL
|
||||
if (!srcamul)
|
||||
return;
|
||||
#endif
|
||||
for (i = 0; i < rows; ++i) {
|
||||
uint8_t *dstr = dst + dstRowStride * i;
|
||||
const uint8_t *srcar = srca + srcaRowStride * i;
|
||||
for (j = 0; j < cols; ++j) {
|
||||
uint32_t srcap = srcar[j];
|
||||
// 32bit to force the math ops to operate on 32 bit
|
||||
#ifdef CONDITIONAL
|
||||
if (!srcap)
|
||||
continue;
|
||||
#endif
|
||||
#ifdef CONDITIONAL2
|
||||
if (srcap == 255 && srcamul == 255) {
|
||||
dstr[j] = srcp;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
uint8_t dstp = dstr[j];
|
||||
#ifdef ACCURATE
|
||||
srcap *= srcamul; // now 0..65025
|
||||
uint8_t outp =
|
||||
(srcp * srcap + dstp * (65025 - srcap) + 32512) / 65025;
|
||||
dstr[j] = outp;
|
||||
#else
|
||||
srcap = (srcap * srcamul + 255) >> 8;
|
||||
uint8_t outp =
|
||||
(srcp * srcap + dstp * (255 - srcap) + 255) >> 8;
|
||||
dstr[j] = outp;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void blend_src8_alpha(uint8_t *dst,
|
||||
ssize_t dstRowStride,
|
||||
const uint8_t *src,
|
||||
ssize_t srcRowStride,
|
||||
const uint8_t *srca,
|
||||
ssize_t srcaRowStride,
|
||||
int rows,
|
||||
int cols)
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0; i < rows; ++i) {
|
||||
uint8_t *dstr = dst + dstRowStride * i;
|
||||
const uint8_t *srcr = src + srcRowStride * i;
|
||||
const uint8_t *srcar = srca + srcaRowStride * i;
|
||||
for (j = 0; j < cols; ++j) {
|
||||
uint16_t srcap = srcar[j];
|
||||
// 16bit to force the math ops to operate on 16 bit
|
||||
#ifdef CONDITIONAL
|
||||
if (!srcap)
|
||||
continue;
|
||||
#endif
|
||||
uint8_t srcp = srcr[j];
|
||||
#ifdef CONDITIONAL2
|
||||
if (srcap == 255) {
|
||||
dstr[j] = srcp;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
uint8_t dstp = dstr[j];
|
||||
#ifdef ACCURATE
|
||||
uint8_t outp =
|
||||
(srcp * srcap + dstp * (255 - srcap) + 127) / 255;
|
||||
#else
|
||||
uint8_t outp =
|
||||
(srcp * srcap + dstp * (255 - srcap) + 255) >> 8;
|
||||
#endif
|
||||
dstr[j] = outp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void blend_src_alpha(uint8_t *dst, ssize_t dstRowStride,
|
||||
const uint8_t *src, ssize_t srcRowStride,
|
||||
const uint8_t *srca, ssize_t srcaRowStride,
|
||||
int rows, int cols, int bytes)
|
||||
{
|
||||
if (bytes == 2) {
|
||||
blend_src16_alpha(dst, dstRowStride, src,
|
||||
srcRowStride, srca,
|
||||
srcaRowStride, rows, cols);
|
||||
} else if (bytes == 1) {
|
||||
blend_src8_alpha(dst, dstRowStride, src,
|
||||
srcRowStride, srca,
|
||||
srcaRowStride, rows, cols);
|
||||
}
|
||||
}
|
||||
|
||||
static void blend_const_alpha(uint8_t *dst, ssize_t dstRowStride,
|
||||
uint16_t srcp,
|
||||
const uint8_t *srca, ssize_t srcaRowStride,
|
||||
uint8_t srcamul,
|
||||
int rows, int cols, int bytes)
|
||||
{
|
||||
if (bytes == 2) {
|
||||
blend_const16_alpha(dst, dstRowStride, srcp,
|
||||
srca, srcaRowStride,
|
||||
srcamul, rows,
|
||||
cols);
|
||||
} else if (bytes == 1) {
|
||||
blend_const8_alpha(dst, dstRowStride, srcp,
|
||||
srca, srcaRowStride, srcamul,
|
||||
rows,
|
||||
cols);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int min(int x, int y)
|
||||
{
|
||||
if (x < y)
|
||||
return x;
|
||||
else
|
||||
return y;
|
||||
}
|
||||
|
||||
static void unpremultiply_and_split_bgra(mp_image_t *img, mp_image_t *alpha)
|
||||
{
|
||||
int x, y;
|
||||
for (y = 0; y < img->h; ++y) {
|
||||
unsigned char *irow = &img->planes[0][img->stride[0] * y];
|
||||
unsigned char *arow = &alpha->planes[0][alpha->stride[0] * y];
|
||||
for (x = 0; x < img->w; ++x) {
|
||||
unsigned char aval = irow[4 * x + 3];
|
||||
// multiplied = separate * alpha / 255
|
||||
// separate = rint(multiplied * 255 / alpha)
|
||||
// = floor(multiplied * 255 / alpha + 0.5)
|
||||
// = floor((multiplied * 255 + 0.5 * alpha) / alpha)
|
||||
// = floor((multiplied * 255 + floor(0.5 * alpha)) / alpha)
|
||||
int div = (int) aval;
|
||||
int add = div / 2;
|
||||
if (aval) {
|
||||
irow[4 * x + 0] = min(255, (irow[4 * x + 0] * 255 + add) / div);
|
||||
irow[4 * x + 1] = min(255, (irow[4 * x + 1] * 255 + add) / div);
|
||||
irow[4 * x + 2] = min(255, (irow[4 * x + 2] * 255 + add) / div);
|
||||
}
|
||||
arow[x] = aval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool sub_bitmap_to_mp_images(struct mp_image **sbi, int *color_yuv,
|
||||
int *color_a, struct mp_image **sba,
|
||||
struct sub_bitmap *sb,
|
||||
int format, struct mp_csp_details *csp,
|
||||
float rgb2yuv[3][4], int imgfmt, int bits)
|
||||
{
|
||||
*sbi = NULL;
|
||||
*sba = NULL;
|
||||
if (format == SUBBITMAP_RGBA && sb->w >= 8) {
|
||||
// >= 8 because of libswscale madness
|
||||
// swscale the bitmap from w*h to dw*dh, changing BGRA8 into YUV444P16
|
||||
// and make a scaled copy of A8
|
||||
mp_image_t *sbisrc = new_mp_image(sb->w, sb->h);
|
||||
mp_image_setfmt(sbisrc, IMGFMT_BGRA);
|
||||
sbisrc->planes[0] = sb->bitmap;
|
||||
sbisrc->stride[0] = sb->stride;
|
||||
mp_image_t *sbisrc2 = alloc_mpi(sb->dw, sb->dh, IMGFMT_BGRA);
|
||||
mp_image_swscale(sbisrc2, sbisrc, csp, SWS_BILINEAR);
|
||||
|
||||
// sbisrc2 now is the original image in premultiplied alpha, but
|
||||
// properly scaled...
|
||||
// now, un-premultiply so we can work in YUV color space, also extract
|
||||
// alpha
|
||||
*sba = alloc_mpi(sb->dw, sb->dh, IMGFMT_Y8);
|
||||
unpremultiply_and_split_bgra(sbisrc2, *sba);
|
||||
|
||||
// convert to the output format
|
||||
*sbi = alloc_mpi(sb->dw, sb->dh, imgfmt);
|
||||
mp_image_swscale(*sbi, sbisrc2, csp, SWS_BILINEAR);
|
||||
|
||||
free_mp_image(sbisrc);
|
||||
free_mp_image(sbisrc2);
|
||||
|
||||
color_yuv[0] = 255;
|
||||
color_yuv[1] = 128;
|
||||
color_yuv[2] = 128;
|
||||
*color_a = 255;
|
||||
return true;
|
||||
} else if (format == SUBBITMAP_LIBASS &&
|
||||
sb->w == sb->dw && sb->h == sb->dh) {
|
||||
// swscale alpha only
|
||||
*sba = new_mp_image(sb->w, sb->h);
|
||||
mp_image_setfmt(*sba, IMGFMT_Y8);
|
||||
(*sba)->planes[0] = sb->bitmap;
|
||||
(*sba)->stride[0] = sb->stride;
|
||||
int r = (sb->libass.color >> 24) & 0xFF;
|
||||
int g = (sb->libass.color >> 16) & 0xFF;
|
||||
int b = (sb->libass.color >> 8) & 0xFF;
|
||||
int a = sb->libass.color & 0xFF;
|
||||
color_yuv[0] =
|
||||
rint(MP_MAP_RGB2YUV_COLOR(rgb2yuv, r, g, b, 255, 0)
|
||||
* (1 << (bits - 8)));
|
||||
color_yuv[1] =
|
||||
rint(MP_MAP_RGB2YUV_COLOR(rgb2yuv, r, g, b, 255, 1)
|
||||
* (1 << (bits - 8)));
|
||||
color_yuv[2] =
|
||||
rint(MP_MAP_RGB2YUV_COLOR(rgb2yuv, r, g, b, 255, 2)
|
||||
* (1 << (bits - 8)));
|
||||
*color_a = 255 - a;
|
||||
// NOTE: these overflows can actually happen (when subtitles use color
|
||||
// 0,0,0 while output levels only allows 16,16,16 upwards...)
|
||||
if (color_yuv[0] < 0)
|
||||
color_yuv[0] = 0;
|
||||
if (color_yuv[1] < 0)
|
||||
color_yuv[1] = 0;
|
||||
if (color_yuv[2] < 0)
|
||||
color_yuv[2] = 0;
|
||||
if (*color_a < 0)
|
||||
*color_a = 0;
|
||||
if (color_yuv[0] > ((1 << bits) - 1))
|
||||
color_yuv[0] = ((1 << bits) - 1);
|
||||
if (color_yuv[1] > ((1 << bits) - 1))
|
||||
color_yuv[1] = ((1 << bits) - 1);
|
||||
if (color_yuv[2] > ((1 << bits) - 1))
|
||||
color_yuv[2] = ((1 << bits) - 1);
|
||||
if (*color_a > 255)
|
||||
*color_a = 255;
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
static void mp_image_crop(struct mp_image *img, int x, int y, int w, int h)
|
||||
{
|
||||
int p;
|
||||
for (p = 0; p < img->num_planes; ++p) {
|
||||
int bits = MP_IMAGE_BITS_PER_PIXEL_ON_PLANE(img, p);
|
||||
img->planes[p] +=
|
||||
(y >> (p ? img->chroma_y_shift : 0)) * img->stride[p] +
|
||||
((x >> (p ? img->chroma_x_shift : 0)) * bits) / 8;
|
||||
}
|
||||
img->w = w;
|
||||
img->h = h;
|
||||
}
|
||||
|
||||
static bool clip_to_bounds(int *x, int *y, int *w, int *h,
|
||||
int bx, int by, int bw, int bh)
|
||||
{
|
||||
if (*x < bx) {
|
||||
*w += *x - bx;
|
||||
*x = bx;
|
||||
}
|
||||
if (*y < 0) {
|
||||
*h += *y - by;
|
||||
*y = by;
|
||||
}
|
||||
if (*x + *w > bx + bw)
|
||||
*w = bx + bw - *x;
|
||||
if (*y + *h > by + bh)
|
||||
*h = by + bh - *y;
|
||||
|
||||
if (*w <= 0 || *h <= 0)
|
||||
return false; // nothing left
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void get_swscale_requirements(int *sx, int *sy,
|
||||
const struct mp_image *img)
|
||||
{
|
||||
int p;
|
||||
|
||||
if (img->chroma_x_shift == 31)
|
||||
*sx = 1;
|
||||
else
|
||||
*sx = (1 << img->chroma_x_shift);
|
||||
|
||||
if (img->chroma_y_shift == 31)
|
||||
*sy = 1;
|
||||
else
|
||||
*sy = (1 << img->chroma_y_shift);
|
||||
|
||||
for (p = 0; p < img->num_planes; ++p) {
|
||||
int bits = MP_IMAGE_BITS_PER_PIXEL_ON_PLANE(img, p);
|
||||
while (((*sx >> img->chroma_x_shift) * bits) % (SWS_MIN_BYTE_ALIGN * 8))
|
||||
*sx *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void align_bbox(int *x1, int *y1, int *x2, int *y2, int xstep, int ystep)
|
||||
{
|
||||
*x1 -= (*x1 % xstep);
|
||||
*y1 -= (*y1 % ystep);
|
||||
|
||||
*x2 += xstep - 1;
|
||||
*y2 += ystep - 1;
|
||||
*x2 -= (*x2 % xstep);
|
||||
*y2 -= (*y2 % ystep);
|
||||
}
|
||||
|
||||
static bool align_bbox_to_swscale_requirements(int *x1, int *y1,
|
||||
int *x2, int *y2,
|
||||
struct mp_image *img)
|
||||
{
|
||||
int xstep, ystep;
|
||||
get_swscale_requirements(&xstep, &ystep, img);
|
||||
align_bbox(x1, y1, x2, y2, xstep, ystep);
|
||||
|
||||
if (*x1 < 0)
|
||||
*x1 = 0;
|
||||
if (*y1 < 0)
|
||||
*y1 = 0;
|
||||
if (*x2 > img->w)
|
||||
*x2 = img->w;
|
||||
if (*y2 > img->h)
|
||||
*y2 = img->h;
|
||||
|
||||
return (*x2 > *x1) && (*y2 > *y1);
|
||||
}
|
||||
|
||||
void mp_draw_sub_bitmaps(struct mp_image *dst, struct sub_bitmaps *sbs,
|
||||
struct mp_csp_details *csp)
|
||||
{
|
||||
int i;
|
||||
int x1, y1, x2, y2;
|
||||
int color_yuv[3];
|
||||
int color_a;
|
||||
float yuv2rgb[3][4];
|
||||
float rgb2yuv[3][4];
|
||||
|
||||
#ifdef ACCURATE
|
||||
int format = IMGFMT_444P16;
|
||||
int bits = 16;
|
||||
// however, we can try matching 8bit, 9bit, 10bit yuv formats!
|
||||
if (dst->flags & MP_IMGFLAG_YUV) {
|
||||
if (mp_get_chroma_shift(dst->imgfmt, NULL, NULL, &bits)) {
|
||||
switch (bits) {
|
||||
case 8:
|
||||
format = IMGFMT_444P;
|
||||
break;
|
||||
case 9:
|
||||
format = IMGFMT_444P9;
|
||||
break;
|
||||
case 10:
|
||||
format = IMGFMT_444P10;
|
||||
break;
|
||||
default:
|
||||
// revert back
|
||||
bits = 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
int format = IMGFMT_444P;
|
||||
int bits = 8;
|
||||
#endif
|
||||
int bytes = (bits + 7) / 8;
|
||||
|
||||
struct mp_csp_params cspar = {
|
||||
.colorspace = *csp,
|
||||
.brightness = 0, .contrast = 1,
|
||||
.hue = 0, .saturation = 1,
|
||||
.rgamma = 1, .ggamma = 1, .bgamma = 1,
|
||||
.texture_bits = 8, .input_bits = 8
|
||||
};
|
||||
|
||||
// prepare YUV/RGB conversion values
|
||||
mp_get_yuv2rgb_coeffs(&cspar, yuv2rgb);
|
||||
mp_invert_yuv2rgb(rgb2yuv, yuv2rgb);
|
||||
|
||||
//mp_msg(MSGT_VO, MSGL_ERR, "%f %f %f %f // %f %f %f %f // %f %f %f %f\n",
|
||||
// rgb2yuv[0][0],
|
||||
// rgb2yuv[0][1],
|
||||
// rgb2yuv[0][2],
|
||||
// rgb2yuv[0][3],
|
||||
// rgb2yuv[1][0],
|
||||
// rgb2yuv[1][1],
|
||||
// rgb2yuv[1][2],
|
||||
// rgb2yuv[1][3],
|
||||
// rgb2yuv[2][0],
|
||||
// rgb2yuv[2][1],
|
||||
// rgb2yuv[2][2],
|
||||
// rgb2yuv[2][3]);
|
||||
|
||||
// calculate bounding range
|
||||
if (!sub_bitmaps_bb(sbs, &x1, &y1, &x2, &y2))
|
||||
return;
|
||||
|
||||
if (!align_bbox_to_swscale_requirements(&x1, &y1, &x2, &y2, dst))
|
||||
return; // nothing to do
|
||||
|
||||
// convert to a temp image
|
||||
mp_image_t *temp;
|
||||
mp_image_t dst_region = *dst;
|
||||
if (dst->imgfmt == format) {
|
||||
mp_image_crop(&dst_region, x1, y1, x2 - x1, y2 - y1);
|
||||
temp = &dst_region;
|
||||
} else {
|
||||
mp_image_crop(&dst_region, x1, y1, x2 - x1, y2 - y1);
|
||||
temp = alloc_mpi(x2 - x1, y2 - y1, format);
|
||||
mp_image_swscale(temp, &dst_region, csp, SWS_POINT); // chroma up
|
||||
}
|
||||
|
||||
for (i = 0; i < sbs->num_parts; ++i) {
|
||||
struct sub_bitmap *sb = &sbs->parts[i];
|
||||
mp_image_t *sbi = NULL;
|
||||
mp_image_t *sba = NULL;
|
||||
|
||||
// cut off areas outside the image
|
||||
int dst_x = sb->x - x1; // coordinates are relative to the bbox
|
||||
int dst_y = sb->y - y1; // coordinates are relative to the bbox
|
||||
int dst_w = sb->dw;
|
||||
int dst_h = sb->dh;
|
||||
if (!clip_to_bounds(&dst_x, &dst_y, &dst_w, &dst_h,
|
||||
0, 0, temp->w, temp->h))
|
||||
continue;
|
||||
|
||||
if (!sub_bitmap_to_mp_images(&sbi, color_yuv, &color_a, &sba, sb,
|
||||
sbs->format, csp, rgb2yuv, format, bits)) {
|
||||
mp_msg(MSGT_VO, MSGL_ERR,
|
||||
"render_sub_bitmap: invalid sub bitmap type\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// call blend_alpha 3 times
|
||||
int p;
|
||||
int src_x = (dst_x + x1) - sb->x;
|
||||
int src_y = (dst_y + y1) - sb->y;
|
||||
unsigned char *alpha_p =
|
||||
sba->planes[0] + src_y * sba->stride[0] + src_x;
|
||||
for (p = 0; p < 3; ++p) {
|
||||
unsigned char *dst_p =
|
||||
temp->planes[p] + dst_y * temp->stride[p] + dst_x * bytes;
|
||||
if (sbi) {
|
||||
unsigned char *src_p =
|
||||
sbi->planes[p] + src_y * sbi->stride[p] + src_x * bytes;
|
||||
blend_src_alpha(
|
||||
dst_p, temp->stride[p],
|
||||
src_p, sbi->stride[p],
|
||||
alpha_p, sba->stride[0],
|
||||
dst_h, dst_w, bytes
|
||||
);
|
||||
} else {
|
||||
blend_const_alpha(
|
||||
dst_p, temp->stride[p],
|
||||
color_yuv[p],
|
||||
alpha_p, sba->stride[0], color_a,
|
||||
dst_h, dst_w, bytes
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (sbi)
|
||||
free_mp_image(sbi);
|
||||
if (sba)
|
||||
free_mp_image(sba);
|
||||
}
|
||||
|
||||
if (temp != &dst_region) {
|
||||
// convert back
|
||||
mp_image_swscale(&dst_region, temp, csp, SWS_AREA); // chroma down
|
||||
|
||||
// clean up
|
||||
free_mp_image(temp);
|
||||
}
|
||||
}
|
||||
|
||||
// vim: ts=4 sw=4 et tw=80
|
12
sub/draw_bmp.h
Normal file
12
sub/draw_bmp.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef MPLAYER_DRAW_BMP_H
|
||||
#define MPLAYER_DRAW_BMP_H
|
||||
|
||||
struct mp_image;
|
||||
struct sub_bitmaps;
|
||||
struct mp_csp_details;
|
||||
void mp_draw_sub_bitmaps(struct mp_image *dst, struct sub_bitmaps *sbs,
|
||||
struct mp_csp_details *csp);
|
||||
|
||||
#endif /* MPLAYER_DRAW_BMP_H */
|
||||
|
||||
// vim: ts=4 sw=4 et tw=80
|
Loading…
Reference in New Issue
Block a user