summaryrefslogtreecommitdiffstats
path: root/video/image_writer.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--video/image_writer.c117
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);
}