0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-20 03:52:22 +02:00

screenshot, draw_bmp: use colorspace passed with mp_image

Remove the explicit struct mp_csp_details parameters from all related
functions, and use mp_image.colorspace/levels instead.
This commit is contained in:
wm4 2012-10-27 18:06:09 +02:00
parent d9839fe862
commit 9ba52ea6ef
12 changed files with 136 additions and 91 deletions

View File

@ -39,8 +39,8 @@
#include "libmpcodecs/vf.h"
#include "fmt-conversion.h"
//for sws_getContextFromCmdLine_hq and mp_sws_set_colorspace
#include "libmpcodecs/sws_utils.h"
#include "libmpcodecs/vf.h"
#include "libvo/csputils.h"
#include "m_option.h"
@ -284,28 +284,20 @@ int write_image(struct mp_image *image, const struct mp_csp_details *csp,
}
}
// Caveat: - no colorspace/levels conversion done if pixel formats equal
// - RGB->YUV assumes BT.601
if (image->imgfmt != destfmt || is_anamorphic) {
struct mp_image hack = *image;
hack.w = hack.width;
hack.h = hack.height;
struct mp_image *dst = alloc_mpi(image->w, image->h, destfmt);
vf_clone_mpi_attributes(dst, image);
struct SwsContext *sws = sws_getContextFromCmdLine_hq(image->width,
image->height,
image->imgfmt,
dst->width,
dst->height,
dst->imgfmt);
int flags = SWS_LANCZOS | SWS_FULL_CHR_H_INT | SWS_FULL_CHR_H_INP |
SWS_ACCURATE_RND | SWS_BITEXACT;
struct mp_csp_details colorspace = MP_CSP_DETAILS_DEFAULTS;
if (csp)
colorspace = *csp;
// This is a property of the output device; images always use
// full-range RGB.
colorspace.levels_out = MP_CSP_LEVELS_PC;
mp_sws_set_colorspace(sws, &colorspace);
sws_scale(sws, (const uint8_t **)image->planes, image->stride, 0,
image->height, dst->planes, dst->stride);
sws_freeContext(sws);
mp_image_swscale(dst, &hack, flags);
allocated_image = dst;
image = dst;

View File

@ -18,6 +18,8 @@
#include <assert.h>
#include <libavutil/opt.h>
#include "libmpcodecs/sws_utils.h"
#include "libmpcodecs/mp_image.h"
@ -139,27 +141,58 @@ bool mp_sws_supported_format(int imgfmt)
&& sws_isSupportedOutput(av_format);
}
void mp_image_swscale(struct mp_image *dst,
const struct mp_image *src,
struct mp_csp_details *csp,
static int mp_csp_to_sws_colorspace(enum mp_csp csp)
{
switch (csp) {
case MP_CSP_BT_601: return SWS_CS_ITU601;
case MP_CSP_BT_709: return SWS_CS_ITU709;
case MP_CSP_SMPTE_240M: return SWS_CS_SMPTE240M;
default: return SWS_CS_DEFAULT;
}
}
void mp_image_swscale(struct mp_image *dst, struct mp_image *src,
int my_sws_flags)
{
enum PixelFormat dfmt, sfmt;
dfmt = imgfmt2pixfmt(dst->imgfmt);
sfmt = imgfmt2pixfmt(src->imgfmt);
enum PixelFormat s_fmt = imgfmt2pixfmt(src->imgfmt);
if (src->imgfmt == IMGFMT_RGB8 || src->imgfmt == IMGFMT_BGR8)
sfmt = PIX_FMT_PAL8;
s_fmt = PIX_FMT_PAL8;
int s_csp = mp_csp_to_sws_colorspace(mp_image_csp(src));
int s_range = mp_image_levels(src) == MP_CSP_LEVELS_PC;
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);
enum PixelFormat d_fmt = imgfmt2pixfmt(dst->imgfmt);
int d_csp = mp_csp_to_sws_colorspace(mp_image_csp(dst));
int d_range = mp_image_levels(dst) == MP_CSP_LEVELS_PC;
// Work around libswscale bug #1852 (fixed in ffmpeg commit 8edf9b1fa):
// setting range flags for RGB gives random bogus results.
// Newer libswscale always ignores range flags for RGB.
bool s_yuv = src->flags & MP_IMGFLAG_YUV;
bool d_yuv = dst->flags & MP_IMGFLAG_YUV;
s_range = s_range && s_yuv;
d_range = d_range && d_yuv;
struct SwsContext *sws = sws_alloc_context();
av_opt_set_int(sws, "sws_flags", my_sws_flags, 0);
av_opt_set_int(sws, "srcw", src->w, 0);
av_opt_set_int(sws, "srch", src->h, 0);
av_opt_set_int(sws, "src_format", s_fmt, 0);
av_opt_set_int(sws, "dstw", dst->w, 0);
av_opt_set_int(sws, "dsth", dst->h, 0);
av_opt_set_int(sws, "dst_format", d_fmt, 0);
sws_setColorspaceDetails(sws, sws_getCoefficients(s_csp), s_range,
sws_getCoefficients(d_csp), d_range,
0, 1 << 16, 1 << 16);
int res = sws_init_context(sws, NULL, NULL);
assert(res >= 0);
sws_scale(sws, (const uint8_t *const *) src->planes, src->stride,
0, src->h, dst->planes, dst->stride);
sws_freeContext(sws);
}

View File

@ -25,9 +25,7 @@ int mp_sws_set_colorspace(struct SwsContext *sws, struct mp_csp_details *csp);
bool mp_sws_supported_format(int imgfmt);
void mp_image_swscale(struct mp_image *dst,
const struct mp_image *src,
struct mp_csp_details *csp,
void mp_image_swscale(struct mp_image *dst, struct mp_image *src,
int my_sws_flags);
#endif /* MP_SWS_UTILS_H */

View File

@ -221,11 +221,10 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
struct osd_state *osd = priv->osd;
prepare_image(vf, mpi);
mp_image_set_colorspace_details(mpi, &priv->csp);
if (pts != MP_NOPTS_VALUE) {
osd_draw_on_image(osd, priv->dim, pts, OSD_DRAW_SUB_FILTER, vf->dmpi,
&priv->csp);
}
if (pts != MP_NOPTS_VALUE)
osd_draw_on_image(osd, priv->dim, pts, OSD_DRAW_SUB_FILTER, vf->dmpi);
return vf_next_put_image(vf, vf->dmpi, pts);
}

View File

@ -501,8 +501,9 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
.video_par = dar / sar,
};
osd_draw_on_image(osd, dim, osd->vo_pts, OSD_DRAW_SUB_ONLY, vc->lastimg,
&vc->colorspace);
mp_image_set_colorspace_details(vc->lastimg, &vc->colorspace);
osd_draw_on_image(osd, dim, osd->vo_pts, OSD_DRAW_SUB_ONLY, vc->lastimg);
}
}

View File

@ -440,8 +440,6 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
struct mp_image img = get_x_buffer(p);
struct mp_csp_details csp = MP_CSP_DETAILS_DEFAULTS;
struct mp_osd_res res = {
.w = img.w,
.h = img.h,
@ -449,7 +447,7 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
.video_par = vo->aspdat.par,
};
osd_draw_on_image(osd, res, osd->vo_pts, 0, &img, &csp);
osd_draw_on_image(osd, res, osd->vo_pts, 0, &img);
}
static void flip_page(struct vo *vo)

View File

@ -309,6 +309,10 @@ static struct mp_image get_xv_buffer(struct vo *vo, int buf_index)
img.stride[n] = xv_image->pitches[sn];
}
struct mp_csp_details csp = {0};
vo_control(vo, VOCTRL_GET_YUV_COLORSPACE, &csp);
mp_image_set_colorspace_details(&img, &csp);
return img;
}
@ -336,9 +340,6 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
struct mp_image img = get_xv_buffer(vo, ctx->current_buf);
struct mp_csp_details csp = {0};
vo_control(vo, VOCTRL_GET_YUV_COLORSPACE, &csp);
struct vo_rect *src = &ctx->src_rect;
struct vo_rect *dst = &ctx->dst_rect;
double xvpar = (double)dst->width / dst->height * src->height / src->width;
@ -350,7 +351,7 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
.video_par = vo->aspdat.par,
};
if (osd_draw_on_image(osd, res, osd->vo_pts, 0, &img, &csp))
if (osd_draw_on_image(osd, res, osd->vo_pts, 0, &img))
ctx->unchanged_image = false;
}

View File

@ -235,13 +235,13 @@ static char *gen_fname(screenshot_ctx *ctx, const char *file_ext)
}
static struct mp_image *add_subs(struct MPContext *mpctx,
struct mp_image *image,
struct mp_csp_details *csp)
struct mp_image *image)
{
if (!(image->flags & MP_IMGFLAG_ALLOCATED)) {
struct mp_image *new_image = alloc_mpi(image->width, image->height,
image->imgfmt);
copy_mpi(new_image, image);
vf_clone_mpi_attributes(new_image, image);
new_image->w = image->w;
new_image->h = image->h;
image = new_image;
@ -260,7 +260,7 @@ static struct mp_image *add_subs(struct MPContext *mpctx,
hack.w = hack.width;
hack.h = hack.height;
osd_draw_on_image(mpctx->osd, res, mpctx->osd->vo_pts,
OSD_DRAW_SUB_ONLY, &hack, csp);
OSD_DRAW_SUB_ONLY, &hack);
return image;
}
@ -272,12 +272,17 @@ static void screenshot_save(struct MPContext *mpctx, struct mp_image *image,
struct mp_csp_details colorspace;
get_detected_video_colorspace(mpctx->sh_video, &colorspace);
// This is a property of the output device; images always use
// full-range RGB.
colorspace.levels_out = MP_CSP_LEVELS_PC;
// This is a bad hack, until the VOs set image->colorspace correctly
mp_image_set_colorspace_details(image, &colorspace);
struct image_writer_opts *opts = mpctx->opts.screenshot_image_opts;
struct mp_image *new_image = image;
if (with_subs)
new_image = add_subs(mpctx, new_image, &colorspace);
new_image = add_subs(mpctx, new_image);
char *filename = gen_fname(ctx, image_writer_file_ext(opts));
if (filename) {

View File

@ -43,6 +43,9 @@ struct sub_cache {
struct part {
int bitmap_pos_id;
int imgfmt;
enum mp_csp colorspace;
enum mp_csp_levels levels;
int num_imgs;
struct sub_cache *imgs;
};
@ -53,7 +56,7 @@ struct mp_draw_sub_cache
};
static struct part *get_cache(struct mp_draw_sub_cache **cache,
struct sub_bitmaps *sbs);
struct sub_bitmaps *sbs, struct mp_image *format);
static bool get_sub_area(struct mp_rect bb, struct mp_image *temp,
struct sub_bitmap *sb, struct mp_image *out_area,
int *out_src_x, int *out_src_y);
@ -206,22 +209,24 @@ static void unpremultiply_and_split_BGR32(struct mp_image *img,
}
}
static void scale_sb_rgba(struct sub_bitmap *sb, struct mp_csp_details *csp,
int imgfmt, struct mp_image **out_sbi,
struct mp_image **out_sba)
// dst_format merely contains the target colorspace/format information
static void scale_sb_rgba(struct sub_bitmap *sb, struct mp_image *dst_format,
struct mp_image **out_sbi, struct mp_image **out_sba)
{
struct mp_image *sbisrc = new_mp_image(sb->w, sb->h);
mp_image_setfmt(sbisrc, IMGFMT_BGR32);
sbisrc->planes[0] = sb->bitmap;
sbisrc->stride[0] = sb->stride;
struct mp_image *sbisrc2 = alloc_mpi(sb->dw, sb->dh, IMGFMT_BGR32);
mp_image_swscale(sbisrc2, sbisrc, csp, SWS_BILINEAR);
mp_image_swscale(sbisrc2, sbisrc, SWS_BILINEAR);
struct mp_image *sba = alloc_mpi(sb->dw, sb->dh, IMGFMT_Y8);
unpremultiply_and_split_BGR32(sbisrc2, sba);
struct mp_image *sbi = alloc_mpi(sb->dw, sb->dh, imgfmt);
mp_image_swscale(sbi, sbisrc2, csp, SWS_BILINEAR);
struct mp_image *sbi = alloc_mpi(sb->dw, sb->dh, dst_format->imgfmt);
sbi->colorspace = dst_format->colorspace;
sbi->levels = dst_format->levels;
mp_image_swscale(sbi, sbisrc2, SWS_BILINEAR);
free_mp_image(sbisrc);
free_mp_image(sbisrc2);
@ -231,10 +236,10 @@ static void scale_sb_rgba(struct sub_bitmap *sb, struct mp_csp_details *csp,
}
static void draw_rgba(struct mp_draw_sub_cache **cache, struct mp_rect bb,
struct mp_image *temp, int bits, struct mp_csp_details *csp,
struct mp_image *temp, int bits,
struct sub_bitmaps *sbs)
{
struct part *part = get_cache(cache, sbs);
struct part *part = get_cache(cache, sbs, temp);
for (int i = 0; i < sbs->num_parts; ++i) {
struct sub_bitmap *sb = &sbs->parts[i];
@ -257,7 +262,7 @@ static void draw_rgba(struct mp_draw_sub_cache **cache, struct mp_rect bb,
}
if (!(sbi && sba))
scale_sb_rgba(sb, csp, temp->imgfmt, &sbi, &sba);
scale_sb_rgba(sb, temp, &sbi, &sba);
int bytes = (bits + 7) / 8;
uint8_t *alpha_p = sba->planes[0] + src_y * sba->stride[0] + src_x;
@ -278,11 +283,12 @@ static void draw_rgba(struct mp_draw_sub_cache **cache, struct mp_rect bb,
}
static void draw_ass(struct mp_draw_sub_cache **cache, struct mp_rect bb,
struct mp_image *temp, int bits, struct mp_csp_details *csp,
struct sub_bitmaps *sbs)
struct mp_image *temp, int bits, struct sub_bitmaps *sbs)
{
struct mp_csp_params cspar = MP_CSP_PARAMS_DEFAULTS;
cspar.colorspace = *csp;
cspar.colorspace.format = temp->colorspace;
cspar.colorspace.levels_in = temp->levels;
cspar.colorspace.levels_out = MP_CSP_LEVELS_PC; // RGB (libass.color)
cspar.int_bits_in = bits;
cspar.int_bits_out = 8;
@ -416,7 +422,7 @@ static void get_closest_y444_format(int imgfmt, int *out_format, int *out_bits)
}
static struct part *get_cache(struct mp_draw_sub_cache **cache,
struct sub_bitmaps *sbs)
struct sub_bitmaps *sbs, struct mp_image *format)
{
if (cache && !*cache)
*cache = talloc_zero(NULL, struct mp_draw_sub_cache);
@ -426,14 +432,25 @@ static struct part *get_cache(struct mp_draw_sub_cache **cache,
bool use_cache = sbs->format == SUBBITMAP_RGBA;
if (cache && use_cache) {
part = (*cache)->parts[sbs->render_index];
if (part && part->bitmap_pos_id != sbs->bitmap_pos_id) {
talloc_free(part);
part = NULL;
if (part) {
if (part->bitmap_pos_id != sbs->bitmap_pos_id
|| part->imgfmt != format->imgfmt
|| part->colorspace != format->colorspace
|| part->levels != format->levels)
{
talloc_free(part);
part = NULL;
}
}
if (!part) {
part = talloc_zero(*cache, struct part);
part->bitmap_pos_id = sbs->bitmap_pos_id;
part->num_imgs = sbs->num_parts;
part = talloc(*cache, struct part);
*part = (struct part) {
.bitmap_pos_id = sbs->bitmap_pos_id,
.num_imgs = sbs->num_parts,
.imgfmt = format->imgfmt,
.levels = format->levels,
.colorspace = format->colorspace,
};
part->imgs = talloc_zero_array(part, struct sub_cache,
part->num_imgs);
}
@ -468,7 +485,7 @@ static bool get_sub_area(struct mp_rect bb, struct mp_image *temp,
// containing scaled versions of sbs contents - free the cache with
// talloc_free()
void mp_draw_sub_bitmaps(struct mp_draw_sub_cache **cache, struct mp_image *dst,
struct sub_bitmaps *sbs, struct mp_csp_details *csp)
struct sub_bitmaps *sbs)
{
assert(mp_draw_sub_formats[sbs->format]);
if (!mp_sws_supported_format(dst->imgfmt))
@ -491,17 +508,23 @@ void mp_draw_sub_bitmaps(struct mp_draw_sub_cache **cache, struct mp_image *dst,
temp = &dst_region;
} else {
temp = alloc_mpi(bb.x1 - bb.x0, bb.y1 - bb.y0, format);
mp_image_swscale(temp, &dst_region, csp, SWS_POINT); // chroma up
// temp is always YUV, dst_region not
// reduce amount of conversions in YUV case (upsampling/shifting only)
if (dst_region.flags & MP_IMGFLAG_YUV) {
temp->colorspace = dst_region.colorspace;
temp->levels = dst_region.levels;
}
mp_image_swscale(temp, &dst_region, SWS_POINT); // chroma up
}
if (sbs->format == SUBBITMAP_RGBA) {
draw_rgba(cache, bb, temp, bits, csp, sbs);
draw_rgba(cache, bb, temp, bits, sbs);
} else if (sbs->format == SUBBITMAP_LIBASS) {
draw_ass(cache, bb, temp, bits, csp, sbs);
draw_ass(cache, bb, temp, bits, sbs);
}
if (temp != &dst_region) {
mp_image_swscale(&dst_region, temp, csp, SWS_AREA); // chroma down
mp_image_swscale(&dst_region, temp, SWS_AREA); // chroma down
free_mp_image(temp);
}
}

View File

@ -8,7 +8,7 @@ struct sub_bitmaps;
struct mp_csp_details;
struct mp_draw_sub_cache;
void mp_draw_sub_bitmaps(struct mp_draw_sub_cache **cache, struct mp_image *dst,
struct sub_bitmaps *sbs, struct mp_csp_details *csp);
struct sub_bitmaps *sbs);
extern const bool mp_draw_sub_formats[SUBBITMAP_COUNT];

View File

@ -234,7 +234,6 @@ void osd_draw(struct osd_state *osd, struct mp_osd_res res,
struct draw_on_image_closure {
struct osd_state *osd;
struct mp_image *dest;
struct mp_csp_details *dest_csp;
bool changed;
};
@ -242,18 +241,16 @@ static void draw_on_image(void *ctx, struct sub_bitmaps *imgs)
{
struct draw_on_image_closure *closure = ctx;
struct osd_state *osd = closure->osd;
mp_draw_sub_bitmaps(&osd->draw_cache, closure->dest, imgs,
closure->dest_csp);
mp_draw_sub_bitmaps(&osd->draw_cache, closure->dest, imgs);
talloc_steal(osd, osd->draw_cache);
closure->changed = true;
}
// Returns whether anything was drawn.
bool osd_draw_on_image(struct osd_state *osd, struct mp_osd_res res,
double video_pts, int draw_flags, struct mp_image *dest,
struct mp_csp_details *dest_csp)
double video_pts, int draw_flags, struct mp_image *dest)
{
struct draw_on_image_closure closure = {osd, dest, dest_csp};
struct draw_on_image_closure closure = {osd, dest};
osd_draw(osd, res, video_pts, draw_flags, mp_draw_sub_formats,
&draw_on_image, &closure);
return closure.changed;

View File

@ -205,10 +205,8 @@ void osd_draw(struct osd_state *osd, struct mp_osd_res res,
void (*cb)(void *ctx, struct sub_bitmaps *imgs), void *cb_ctx);
struct mp_image;
struct mp_csp_details;
bool osd_draw_on_image(struct osd_state *osd, struct mp_osd_res res,
double video_pts, int draw_flags, struct mp_image *dest,
struct mp_csp_details *dest_csp);
double video_pts, int draw_flags, struct mp_image *dest);
struct mp_rect;
bool sub_bitmaps_bb(struct sub_bitmaps *imgs, struct mp_rect *out_bb);