diff options
Diffstat (limited to '')
-rw-r--r-- | video/image_writer.c | 117 |
1 files changed, 58 insertions, 59 deletions
diff --git a/video/image_writer.c b/video/image_writer.c index 288d809..cc79573 100644 --- a/video/image_writer.c +++ b/video/image_writer.c @@ -19,12 +19,14 @@ #include <stdlib.h> #include <string.h> #include <inttypes.h> +#include <unistd.h> #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavutil/mem.h> #include <libavutil/opt.h> #include <libavutil/pixdesc.h> +#include <libplacebo/utils/libav.h> #include "common/msg.h" #include "config.h" @@ -35,6 +37,7 @@ #endif #include "osdep/io.h" +#include "misc/path_utils.h" #include "common/av_common.h" #include "common/msg.h" @@ -59,12 +62,10 @@ const struct image_writer_opts image_writer_opts_defaults = { .jxl_distance = 1.0, .jxl_effort = 4, .avif_encoder = "libaom-av1", - .avif_pixfmt = "yuv420p", .avif_opts = (char*[]){ "usage", "allintra", - "crf", "32", + "crf", "0", "cpu-used", "8", - "tune", "ssim", NULL }, .tag_csp = true, @@ -136,19 +137,18 @@ static void prepare_avframe(AVFrame *pic, AVCodecContext *avctx, pic->format = avctx->pix_fmt; pic->width = avctx->width; pic->height = avctx->height; - avctx->color_range = pic->color_range = - mp_csp_levels_to_avcol_range(image->params.color.levels); + pl_avframe_set_repr(pic, image->params.repr); + avctx->colorspace = pic->colorspace; + avctx->color_range = pic->color_range; if (!tag_csp) return; - avctx->color_primaries = pic->color_primaries = - mp_csp_prim_to_avcol_pri(image->params.color.primaries); - avctx->color_trc = pic->color_trc = - mp_csp_trc_to_avcol_trc(image->params.color.gamma); - avctx->colorspace = pic->colorspace = - mp_csp_to_avcol_spc(image->params.color.space); + pl_avframe_set_color(pic, image->params.color); + avctx->color_primaries = pic->color_primaries; + avctx->color_trc = pic->color_trc; avctx->chroma_sample_location = pic->chroma_location = - mp_chroma_location_to_av(image->params.chroma_location); + pl_chroma_to_av(image->params.chroma_location); + mp_dbg(log, "mapped color params:\n" " trc = %s\n" " primaries = %s\n" @@ -163,14 +163,8 @@ static void prepare_avframe(AVFrame *pic, AVCodecContext *avctx, ); } -static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, const char *filename) +static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp) { - FILE *fp = fopen(filename, "wb"); - if (!fp) { - MP_ERR(ctx, "Error opening '%s' for writing!\n", filename); - return false; - } - bool success = false; AVFrame *pic = NULL; AVPacket *pkt = NULL; @@ -195,7 +189,7 @@ static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, const ch avctx->pix_fmt = imgfmt2pixfmt(image->imgfmt); if (codec->id == AV_CODEC_ID_MJPEG) { // Annoying deprecated garbage for the jpg encoder. - if (image->params.color.levels == MP_CSP_LEVELS_PC) + if (image->params.repr.levels == PL_COLOR_LEVELS_FULL) avctx->pix_fmt = replace_j_format(avctx->pix_fmt); } if (avctx->pix_fmt == AV_PIX_FMT_NONE) { @@ -260,7 +254,7 @@ error_exit: avcodec_free_context(&avctx); av_frame_free(&pic); av_packet_free(&pkt); - return !fclose(fp) && success; + return success; } #if HAVE_JPEG @@ -274,15 +268,8 @@ static void write_jpeg_error_exit(j_common_ptr cinfo) longjmp(*(jmp_buf*)cinfo->client_data, 1); } -static bool write_jpeg(struct image_writer_ctx *ctx, mp_image_t *image, - const char *filename) +static bool write_jpeg(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp) { - FILE *fp = fopen(filename, "wb"); - if (!fp) { - MP_ERR(ctx, "Error opening '%s' for writing!\n", filename); - return false; - } - struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; @@ -293,7 +280,6 @@ static bool write_jpeg(struct image_writer_ctx *ctx, mp_image_t *image, cinfo.client_data = &error_return_jmpbuf; if (setjmp(cinfo.client_data)) { jpeg_destroy_compress(&cinfo); - fclose(fp); return false; } @@ -330,7 +316,7 @@ static bool write_jpeg(struct image_writer_ctx *ctx, mp_image_t *image, jpeg_destroy_compress(&cinfo); - return !fclose(fp); + return true; } #endif @@ -354,8 +340,7 @@ static void log_side_data(struct image_writer_ctx *ctx, AVPacketSideData *data, } } -static bool write_avif(struct image_writer_ctx *ctx, mp_image_t *image, - const char *filename) +static bool write_avif(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp) { const AVCodec *codec = NULL; const AVOutputFormat *ofmt = NULL; @@ -423,11 +408,8 @@ static bool write_avif(struct image_writer_ctx *ctx, mp_image_t *image, goto free_data; } - ret = avio_open(&avioctx, filename, AVIO_FLAG_WRITE); - if (ret < 0) { - MP_ERR(ctx, "Could not open file '%s' for saving images\n", filename); - goto free_data; - } + avio_open_dyn_buf(&avioctx); + MP_HANDLE_OOM(avioctx); fmtctx = avformat_alloc_context(); if (!fmtctx) { @@ -505,10 +487,12 @@ static bool write_avif(struct image_writer_ctx *ctx, mp_image_t *image, } MP_DBG(ctx, "write_avif(): avio_size() = %"PRIi64"\n", avio_size(avioctx)); - success = true; + uint8_t *buf = NULL; + int written_size = avio_close_dyn_buf(avioctx, &buf); + success = fwrite(buf, written_size, 1, fp) == 1; + av_freep(&buf); free_data: - success = !avio_closep(&avioctx) && success; avformat_free_context(fmtctx); avcodec_free_context(&avctx); av_packet_free(&pkt); @@ -616,7 +600,7 @@ int image_writer_format_from_ext(const char *ext) } static struct mp_image *convert_image(struct mp_image *image, int destfmt, - enum mp_csp_levels yuv_levels, + enum pl_color_levels yuv_levels, const struct image_writer_opts *opts, struct mpv_global *global, struct mp_log *log) @@ -631,19 +615,22 @@ static struct mp_image *convert_image(struct mp_image *image, int destfmt, .p_w = 1, .p_h = 1, .color = image->params.color, + .repr = image->params.repr, + .chroma_location = image->params.chroma_location, + .crop = {0, 0, d_w, d_h}, }; mp_image_params_guess_csp(&p); if (!image_writer_flexible_csp(opts)) { // If our format can't tag csps, set something sane - p.color.primaries = MP_CSP_PRIM_BT_709; - p.color.gamma = MP_CSP_TRC_AUTO; - p.color.light = MP_CSP_LIGHT_DISPLAY; + p.color.primaries = PL_COLOR_PRIM_BT_709; + p.color.transfer = PL_COLOR_TRC_UNKNOWN; + p.light = MP_CSP_LIGHT_DISPLAY; p.color.hdr = (struct pl_hdr_metadata){0}; - if (p.color.space != MP_CSP_RGB) { - p.color.levels = yuv_levels; - p.color.space = MP_CSP_BT_601; - p.chroma_location = MP_CHROMA_CENTER; + if (p.repr.sys != PL_COLOR_SYSTEM_RGB) { + p.repr.levels = yuv_levels; + p.repr.sys = PL_COLOR_SYSTEM_BT_601; + p.chroma_location = PL_CHROMA_CENTER; } mp_image_params_guess_csp(&p); } @@ -651,7 +638,7 @@ static struct mp_image *convert_image(struct mp_image *image, int destfmt, if (mp_image_params_equal(&p, &image->params)) return mp_image_new_ref(image); - mp_dbg(log, "will convert image to %s\n", mp_imgfmt_to_name(p.imgfmt)); + mp_verbose(log, "will convert image to %s\n", mp_imgfmt_to_name(p.imgfmt)); struct mp_image *src = image; if (mp_image_crop_valid(&src->params) && @@ -696,16 +683,16 @@ static struct mp_image *convert_image(struct mp_image *image, int destfmt, bool write_image(struct mp_image *image, const struct image_writer_opts *opts, const char *filename, struct mpv_global *global, - struct mp_log *log) + struct mp_log *log, bool overwrite) { struct image_writer_opts defs = image_writer_opts_defaults; if (!opts) opts = &defs; - mp_dbg(log, "input: %s\n", mp_image_params_to_str(&image->params)); + mp_verbose(log, "input: %s\n", mp_image_params_to_str(&image->params)); struct image_writer_ctx ctx = { log, opts, image->fmt }; - bool (*write)(struct image_writer_ctx *, mp_image_t *, const char *) = write_lavc; + bool (*write)(struct image_writer_ctx *, mp_image_t *, FILE *) = write_lavc; int destfmt = 0; #if HAVE_JPEG @@ -717,7 +704,8 @@ bool write_image(struct mp_image *image, const struct image_writer_opts *opts, #if HAVE_AVIF_MUXER if (opts->format == AV_CODEC_ID_AV1) { write = write_avif; - destfmt = mp_imgfmt_from_name(bstr0(opts->avif_pixfmt)); + if (opts->avif_pixfmt && opts->avif_pixfmt[0]) + destfmt = mp_imgfmt_from_name(bstr0(opts->avif_pixfmt)); } #endif if (opts->format == AV_CODEC_ID_WEBP && !opts->webp_lossless) { @@ -730,21 +718,32 @@ bool write_image(struct mp_image *image, const struct image_writer_opts *opts, if (!destfmt) destfmt = get_target_format(&ctx); - enum mp_csp_levels levels; // Ignored if destfmt is a RGB format + enum pl_color_levels levels; // Ignored if destfmt is a RGB format if (opts->format == AV_CODEC_ID_WEBP) { - levels = MP_CSP_LEVELS_TV; + levels = PL_COLOR_LEVELS_LIMITED; } else { - levels = MP_CSP_LEVELS_PC; + levels = PL_COLOR_LEVELS_FULL; } struct mp_image *dst = convert_image(image, destfmt, levels, opts, global, log); if (!dst) return false; - bool success = write(&ctx, dst, filename); - if (!success) + bool success = false; + FILE *fp = fopen(filename, overwrite ? "wb" : "wbx"); + if (!fp) { + mp_err(log, "Error creating '%s' for writing: %s!\n", + filename, mp_strerror(errno)); + goto done; + } + + success = write(&ctx, dst, fp); + if (fclose(fp) || !success) { mp_err(log, "Error writing file '%s'!\n", filename); + unlink(filename); + } +done: talloc_free(dst); return success; } @@ -753,5 +752,5 @@ void dump_png(struct mp_image *image, const char *filename, struct mp_log *log) { struct image_writer_opts opts = image_writer_opts_defaults; opts.format = AV_CODEC_ID_PNG; - write_image(image, &opts, filename, NULL, log); + write_image(image, &opts, filename, NULL, log, true); } |