From 96373a1e735ff9018af65e801fef04c71a3e2002 Mon Sep 17 00:00:00 2001 From: Martin Pulec Date: Thu, 9 Nov 2023 15:13:52 +0100 Subject: [PATCH] tools/convert: support for storing PNM/Y4M --- src/video_frame.c | 41 ++++++++++++++++++++++++++++++++++------- src/video_frame.h | 2 ++ tools/Makefile | 4 +++- tools/convert.cpp | 35 +++++++++++++++++++++++++++++++++-- 4 files changed, 72 insertions(+), 10 deletions(-) diff --git a/src/video_frame.c b/src/video_frame.c index a6c418650..175add892 100644 --- a/src/video_frame.c +++ b/src/video_frame.c @@ -49,21 +49,27 @@ * */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#include "config_unix.h" -#include "config_win32.h" -#endif // HAVE_CONFIG_H -#include "debug.h" - +#include +#include +#include #include #include +#include #include +#ifdef __linux__ +#include +#endif + +#include "config_unix.h" +#include "config_win32.h" +#include "debug.h" #include "utils/pam.h" #include "utils/y4m.h" #include "video_codec.h" #include "video_frame.h" +#define MOD_NAME "[video frame] " + struct video_frame * vf_alloc(int count) { struct video_frame *buf; @@ -563,6 +569,27 @@ const char *save_video_frame(struct video_frame *frame, const char *name, bool r return filename; } +struct video_frame * +load_video_frame(const char *name, codec_t codec, int width, int height) +{ + FILE *in = fopen(name, "rb"); + if (!in) { + perror("fopen"); + return NULL; + } + struct video_frame *out = vf_alloc_desc_data( + (struct video_desc){ width, height, codec, 1.0, PROGRESSIVE, 1 }); + size_t bytes = fread(out->tiles[0].data, 1, out->tiles[0].data_len, in); + fclose(in); + if (bytes == out->tiles[0].data_len) { + return out; + } + MSG(ERROR, "Cannot read %u B from %s, got only %zu B!\n", + out->tiles[0].data_len, name, bytes); + vf_free(out); + return NULL; +} + void vf_copy_metadata(struct video_frame *dest, const struct video_frame *src) { diff --git a/src/video_frame.h b/src/video_frame.h index 24eb6184a..296edd36b 100644 --- a/src/video_frame.h +++ b/src/video_frame.h @@ -191,6 +191,8 @@ bool parse_fps(const char *fps, struct video_desc *desc); bool save_video_frame_as_pnm(struct video_frame *frame, const char *name); const char *save_video_frame(struct video_frame *frame, const char *name, bool raw); +struct video_frame *load_video_frame(const char *name, codec_t codec, int width, + int height); void vf_copy_metadata(struct video_frame *dest, const struct video_frame *src); void vf_store_metadata(const struct video_frame *f, void *); diff --git a/tools/Makefile b/tools/Makefile index 36005a6e7..b26b04320 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -21,7 +21,9 @@ astat_lib: astat.a astat.a: astat.o src/compat/platform_pipe.o ar rcs astat.a $^ -convert: src/pixfmt_conv.o src/video_codec.o convert.o src/debug.o src/utils/color_out.o src/utils/misc.o +convert: src/pixfmt_conv.o src/video_codec.o convert.o src/debug.o \ + src/utils/color_out.o src/utils/misc.o src/video_frame.o \ + src/utils/pam.c src/utils/y4m.c $(CXX) $^ -o convert decklink_temperature: decklink_temperature.cpp ext-deps/DeckLink/Linux/DeckLinkAPIDispatch.o diff --git a/tools/convert.cpp b/tools/convert.cpp index 0b3a05e4f..2db4b6cf2 100644 --- a/tools/convert.cpp +++ b/tools/convert.cpp @@ -8,6 +8,7 @@ #include "../src/config_unix.h" #include "../src/video_codec.h" +#include "../src/video_frame.h" using std::chrono::duration_cast; using std::chrono::high_resolution_clock; @@ -59,6 +60,28 @@ static void print_conversions() { } } +static int +write_to_container(int width, int height, const char *in_f, + const char *out_fname) +{ + const char *ext = strrchr(in_f, '.'); + if (ext == nullptr) { + fprintf(stderr, "File with no extension!\n"); + return 1; + } + codec_t c = get_codec_from_file_extension(ext + 1); + if (c == VIDEO_CODEC_NONE) { + fprintf(stderr, "wrong extension: %s!\n", ext); + return 1; + } + struct video_frame *f = load_video_frame(in_f, c, width, height); + if (f == nullptr) { + return 1; + } + save_video_frame(f, out_fname, false); + return 0; +} + int main(int argc, char *argv[]) { if (argc == 2 && string("list-conversions") == argv[1]) { print_conversions(); @@ -68,10 +91,15 @@ int main(int argc, char *argv[]) { benchmark(); return 0; } - if (argc < 7) { + if (argc != 5 && argc != 7) { cout << "Tool to convert between UltraGrid raw pixel format with supported conversions.\n\n" "Usage:\n" - "\t" << argv[0] << " | benchmark | help | list-conversions\n" + "\t" << argv[0] << " benchmark | help | list-conversions\n\n" + "\t" << argv[0] << " \n" + "\t\t" << "Eg.: " << argv[0] << " 1920 1080 UYVY RGB 00000001.yuv out.rgb\n\n" + "\t" << argv[0] << " \n" + "\t\t- converts to output Y4M or PNM file (depending on in_file extension color space)\n" + "\t\t" << "Eg.: " << argv[0] << " 1920 1080 00000001.yuv out # creates out.y4m\n\n" "\n" "where\n" "\t" << "benchmark - benchmark conversions\n" @@ -81,6 +109,9 @@ int main(int argc, char *argv[]) { } int width = stoi(argv[1]); int height = stoi(argv[2]); + if (argc == 5) { + return write_to_container(width, height, argv[3], argv[4]); + } codec_t in_codec = get_codec_from_name(argv[3]); codec_t out_codec = get_codec_from_name(argv[4]); ifstream in(argv[5], ifstream::ate | ifstream::binary);