image_writer: refactor screenshot write functions

When 3cb9119984 introduced AVIF screenshot
support, FILE * in write functions were replaced by filenames. This
resulted in unnecessary duplication of FILE * handling code and the usage
of avio_open API made it hard to use exclusive open with it.

To unify file handling, use avio_open_dyn_buf instead which writes to
memory instead. This way FILE * can be used for the write functions
and file handling code can be deduplicated. Since we now control
the file opening, exclusive open can now be used for AVIF screenshots.
This commit is contained in:
nanahi 2024-03-19 05:06:44 -04:00 committed by Kacper Michajłow
parent 9a861c930b
commit df01ebaafc
1 changed files with 25 additions and 51 deletions

View File

@ -163,19 +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, bool overwrite)
static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp)
{
FILE *fp = fopen(filename, overwrite ? "wb" : "wbx");
if (!fp && errno == EEXIST) {
MP_ERR(ctx, "File '%s' already exists!\n", filename);
return false;
}
if (!fp) {
MP_ERR(ctx, "Error opening '%s' for writing!\n", filename);
return false;
}
bool success = false;
AVFrame *pic = NULL;
AVPacket *pkt = NULL;
@ -265,9 +254,6 @@ error_exit:
avcodec_free_context(&avctx);
av_frame_free(&pic);
av_packet_free(&pkt);
success = success && !fclose(fp);
if (!success)
unlink(filename);
return success;
}
@ -282,19 +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, bool overwrite)
static bool write_jpeg(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp)
{
FILE *fp = fopen(filename, overwrite ? "wb" : "wbx");
if (!fp && errno == EEXIST) {
MP_ERR(ctx, "File '%s' already exists!\n", filename);
return false;
}
if (!fp) {
MP_ERR(ctx, "Error opening '%s' for writing!\n", filename);
return false;
}
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
@ -305,8 +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);
unlink(filename);
return false;
}
@ -343,10 +316,7 @@ static bool write_jpeg(struct image_writer_ctx *ctx, mp_image_t *image,
jpeg_destroy_compress(&cinfo);
if (!fclose(fp))
return true;
unlink(filename);
return false;
return true;
}
#endif
@ -370,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, bool overwrite)
static bool write_avif(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp)
{
const AVCodec *codec = NULL;
const AVOutputFormat *ofmt = NULL;
@ -439,16 +408,8 @@ static bool write_avif(struct image_writer_ctx *ctx, mp_image_t *image,
goto free_data;
}
if (!overwrite && mp_path_exists(filename)) {
MP_ERR(ctx, "File '%s' already exists\n", filename);
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) {
@ -526,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);
@ -729,7 +692,7 @@ bool write_image(struct mp_image *image, const struct image_writer_opts *opts,
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 *, bool) = write_lavc;
bool (*write)(struct image_writer_ctx *, mp_image_t *, FILE *) = write_lavc;
int destfmt = 0;
#if HAVE_JPEG
@ -766,10 +729,21 @@ bool write_image(struct mp_image *image, const struct image_writer_opts *opts,
if (!dst)
return false;
bool success = write(&ctx, dst, filename, overwrite);
if (!success)
mp_err(log, "Error writing file '%s'!\n", filename);
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;
}