From bda593c85b000cf34ddd508e4fd999947efb36a1 Mon Sep 17 00:00:00 2001 From: Martin Pulec Date: Wed, 28 Aug 2024 16:14:51 +0200 Subject: [PATCH] vcap/cmpto_j2k + video_frame_pool rework use pimpl for video_frame_pool use implicit constructor for vcomp/cmpto_j2k to allow switching of pools --- src/utils/video_frame_pool.cpp | 112 +++++++++++++++++++++++++++---- src/utils/video_frame_pool.h | 28 ++------ src/video_compress/cmpto_j2k.cpp | 31 ++++----- 3 files changed, 119 insertions(+), 52 deletions(-) diff --git a/src/utils/video_frame_pool.cpp b/src/utils/video_frame_pool.cpp index 778b9a9c3..9f404d29b 100644 --- a/src/utils/video_frame_pool.cpp +++ b/src/utils/video_frame_pool.cpp @@ -3,7 +3,7 @@ * @author Martin Pulec */ /* - * Copyright (c) 2020-2021 CESNET, z. s. p. o. + * Copyright (c) 2020-2024 CESNET * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,14 +37,92 @@ #include "config_msvc.h" +#include "video_frame_pool.h" + #include +#include // for free, malloc +#include +#include // for exception #include #include +#include +#include +#include #include #include -#include "video_frame_pool.h" +#include "video_codec.h" +#include "video_frame.h" +struct video_frame_pool::impl { + public: + explicit impl( + unsigned int max_used_frames = 0, + video_frame_pool_allocator const &alloc = default_data_allocator()); + ~impl(); + void reconfigure(struct video_desc new_desc, + size_t new_size = SIZE_MAX); + std::shared_ptr get_frame(); + struct video_frame *get_disposable_frame(); + struct video_frame *get_pod_frame(); + video_frame_pool_allocator const &get_allocator(); + + private: + void remove_free_frames(); + void deallocate_frame(struct video_frame *frame); + + std::unique_ptr m_allocator = std::unique_ptr(new default_data_allocator); + std::queue m_free_frames; + std::mutex m_lock; + std::condition_variable m_frame_returned; + int m_generation = 0; + struct video_desc m_desc{}; + size_t m_max_data_len = 0; + unsigned int m_unreturned_frames = 0; + unsigned int m_max_used_frames; +}; + +// _ +// . _| _ _ (_ _ _ _ _ _ _ _ | +// \/ | (_| (- (_) __ | | (_| ||| (- __ |_) (_) (_) | +// | +video_frame_pool &video_frame_pool::operator=(video_frame_pool &&) = default; +video_frame_pool::video_frame_pool(unsigned int max_used_frames, + video_frame_pool_allocator const &alloc) + : m_impl(std::make_unique(max_used_frames, alloc)) +{ +} +video_frame_pool::~video_frame_pool() = default; +void +video_frame_pool::reconfigure(struct video_desc new_desc, size_t new_size) +{ + m_impl->reconfigure(new_desc, new_size); +} +std::shared_ptr +video_frame_pool::get_frame() +{ + return m_impl->get_frame(); +} +struct video_frame * +video_frame_pool::get_disposable_frame() +{ + return m_impl->get_disposable_frame(); +} +struct video_frame * +video_frame_pool::get_pod_frame() +{ + return m_impl->get_pod_frame(); +} +video_frame_pool_allocator const & +video_frame_pool::get_allocator() +{ + return m_impl->get_allocator(); +} + +// _ +// _| _ (_ _ | |_ _| _ |_ _ _ | | _ _ _ |_ _ _ +// (_| (- | (_| |_| | |_ __ (_| (_| |_ (_| __ (_| | | (_) (_ (_| |_ (_) | +// void *default_data_allocator::allocate(size_t size) { return malloc(size); } @@ -55,17 +133,24 @@ struct video_frame_pool_allocator *default_data_allocator::clone() const { return new default_data_allocator(*this); } -video_frame_pool::video_frame_pool(unsigned int max_used_frames, video_frame_pool_allocator const &alloc) : m_allocator(alloc.clone()), m_generation(0), m_desc(), m_max_data_len(0), m_unreturned_frames(0), m_max_used_frames(max_used_frames) { +// _ +// . _| _ _ (_ _ _ _ _ _ _ _ | . . . _ _ | +// \/ | (_| (- (_) __ | | (_| ||| (- __ |_) (_) (_) | . . | ||| |_) | +// | | +video_frame_pool::impl::impl(unsigned int max_used_frames, + video_frame_pool_allocator const &alloc) + : m_allocator(alloc.clone()), m_max_used_frames(max_used_frames) +{ } -video_frame_pool::~video_frame_pool() { +video_frame_pool::impl::~impl() { std::unique_lock lk(m_lock); remove_free_frames(); // wait also for all frames we gave out to return us m_frame_returned.wait(lk, [this] {return m_unreturned_frames == 0;}); } -void video_frame_pool::reconfigure(struct video_desc new_desc, size_t new_size) { +void video_frame_pool::impl::reconfigure(struct video_desc new_desc, size_t new_size) { std::unique_lock lk(m_lock); m_desc = new_desc; m_max_data_len = new_size != SIZE_MAX ? new_size : new_desc.height * vc_get_linesize(new_desc.width, new_desc.color_spec); @@ -73,7 +158,7 @@ void video_frame_pool::reconfigure(struct video_desc new_desc, size_t new_size) m_generation++; } -std::shared_ptr video_frame_pool::get_frame() { +std::shared_ptr video_frame_pool::impl::get_frame() { struct video_frame *ret = NULL; std::unique_lock lk(m_lock); assert(m_generation != 0); @@ -118,7 +203,7 @@ std::shared_ptr video_frame_pool::get_frame() { }, std::placeholders::_1, m_generation)); } -struct video_frame *video_frame_pool::get_disposable_frame() { +struct video_frame *video_frame_pool::impl::get_disposable_frame() { auto && frame = get_frame(); struct video_frame *out = frame.get(); out->callbacks.dispose_udata = @@ -128,7 +213,7 @@ struct video_frame *video_frame_pool::get_disposable_frame() { return out; } -struct video_frame *video_frame_pool::get_pod_frame() { +struct video_frame *video_frame_pool::impl::get_pod_frame() { auto && frame = get_frame(); struct video_frame *out = vf_alloc_desc(video_desc_from_frame(frame.get())); for (unsigned int i = 0; i < frame->tile_count; ++i) { @@ -141,11 +226,11 @@ struct video_frame *video_frame_pool::get_pod_frame() { return out; } -video_frame_pool_allocator const & video_frame_pool::get_allocator() { +video_frame_pool_allocator const & video_frame_pool::impl::get_allocator() { return *m_allocator; } -void video_frame_pool::remove_free_frames() { +void video_frame_pool::impl::remove_free_frames() { while (!m_free_frames.empty()) { struct video_frame *frame = m_free_frames.front(); m_free_frames.pop(); @@ -153,7 +238,7 @@ void video_frame_pool::remove_free_frames() { } } -void video_frame_pool::deallocate_frame(struct video_frame *frame) { +void video_frame_pool::impl::deallocate_frame(struct video_frame *frame) { if (frame == NULL) return; for (unsigned int i = 0; i < frame->tile_count; ++i) { @@ -162,6 +247,10 @@ void video_frame_pool::deallocate_frame(struct video_frame *frame) { vf_free(frame); } +// __ __ +// / /\ |__) | +// \__ /--\ | | +// void *video_frame_pool_init(struct video_desc desc, int len) { auto *out = new video_frame_pool(len, default_data_allocator()); out->reconfigure(desc); @@ -177,4 +266,3 @@ void video_frame_pool_destroy(void *state) { auto *s = static_cast(state); delete s; } - diff --git a/src/utils/video_frame_pool.h b/src/utils/video_frame_pool.h index 1fba41092..f91612404 100644 --- a/src/utils/video_frame_pool.h +++ b/src/utils/video_frame_pool.h @@ -3,7 +3,7 @@ * @author Martin Pulec */ /* - * Copyright (c) 2014-2021 CESNET, z. s. p. o. + * Copyright (c) 2014-2024 CESNET * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,18 +38,13 @@ #ifndef VIDEO_FRAME_POOL_H_ #define VIDEO_FRAME_POOL_H_ -#include "debug.h" -#include "host.h" +#include "types.h" // for video_frame #include "utils/macros.h" -#include "video.h" #ifdef __cplusplus -#include -#include -#include +#include // for size_t #include -#include struct video_frame_pool_allocator { virtual void *allocate(size_t size) = 0; @@ -73,7 +68,8 @@ struct video_frame_pool { * is unreturned, get_frames() will block. */ video_frame_pool(unsigned int max_used_frames = 0, video_frame_pool_allocator const &alloc = default_data_allocator()); - virtual ~video_frame_pool(); + video_frame_pool &operator=(video_frame_pool &&); + ~video_frame_pool(); /** * @param new_size if omitted, deduce from video desc (only for pixel formats) @@ -97,18 +93,8 @@ struct video_frame_pool { video_frame_pool_allocator const & get_allocator(); private: - void remove_free_frames(); - void deallocate_frame(struct video_frame *frame); - - std::unique_ptr m_allocator; - std::queue m_free_frames; - std::mutex m_lock; - std::condition_variable m_frame_returned; - int m_generation; - struct video_desc m_desc; - size_t m_max_data_len; - unsigned int m_unreturned_frames; - unsigned int m_max_used_frames; + struct impl; + std::unique_ptr m_impl; }; #endif // __cplusplus diff --git a/src/video_compress/cmpto_j2k.cpp b/src/video_compress/cmpto_j2k.cpp index 9e637e0f1..8b7fadb32 100644 --- a/src/video_compress/cmpto_j2k.cpp +++ b/src/video_compress/cmpto_j2k.cpp @@ -123,19 +123,13 @@ using allocator = default_data_allocator; #endif struct state_video_compress_j2k { - state_video_compress_j2k(long long int bitrate, unsigned int pool_size, int mct) - : rate(bitrate), mct(mct), pool(pool_size, allocator()), - max_in_frames(pool_size) - { - } - struct module module_data{}; struct cmpto_j2k_enc_ctx *context{}; struct cmpto_j2k_enc_cfg *enc_settings{}; - long long int rate; ///< bitrate in bits per second - int mct; // force use of mct - -1 means default + long long int rate = 0; ///< bitrate in bits per second + int mct = -1; // force use of mct - -1 means default video_frame_pool pool; ///< pool for frames allocated by us but not yet consumed by encoder - unsigned int max_in_frames; ///< max number of frames between push and pop + unsigned int max_in_frames = DEFAULT_POOL_SIZE; ///< max number of frames between push and pop unsigned int in_frames{}; ///< number of currently encoding frames mutex lock; condition_variable frame_popped; @@ -366,48 +360,47 @@ static void usage() { static struct module * j2k_compress_init(struct module *parent, const char *c_cfg) { double quality = DEFAULT_QUALITY; - int mct = -1; - long long int bitrate = 0; long long int mem_limit = DEFAULT_MEM_LIMIT; unsigned int tile_limit = DEFAULT_TILE_LIMIT; - unsigned int pool_size = DEFAULT_POOL_SIZE; const auto *version = cmpto_j2k_enc_get_version(); LOG(LOG_LEVEL_INFO) << MOD_NAME << "Using codec version: " << (version == nullptr ? "(unknown)" : version->name) << "\n"; + auto *s = new state_video_compress_j2k(); + char *tmp = (char *) alloca(strlen(c_cfg) + 1); strcpy(tmp, c_cfg); char *save_ptr, *item; while ((item = strtok_r(tmp, ":", &save_ptr))) { tmp = NULL; if (strncasecmp("rate=", item, strlen("rate=")) == 0) { - ASSIGN_CHECK_VAL(bitrate, strchr(item, '=') + 1, 1); + ASSIGN_CHECK_VAL(s->rate, strchr(item, '=') + 1, 1); } else if (strncasecmp("quality=", item, strlen("quality=")) == 0) { quality = stod(strchr(item, '=') + 1); } else if (strcasecmp("mct", item) == 0 || strcasecmp("nomct", item) == 0) { - mct = strcasecmp("mct", item) == 0 ? 1 : 0; + s->mct = strcasecmp("mct", item) == 0 ? 1 : 0; } else if (strncasecmp("mem_limit=", item, strlen("mem_limit=")) == 0) { ASSIGN_CHECK_VAL(mem_limit, strchr(item, '=') + 1, 1); } else if (strncasecmp("tile_limit=", item, strlen("tile_limit=")) == 0) { ASSIGN_CHECK_VAL(tile_limit, strchr(item, '=') + 1, 0); } else if (strncasecmp("pool_size=", item, strlen("pool_size=")) == 0) { - ASSIGN_CHECK_VAL(pool_size, strchr(item, '=') + 1, 1); + ASSIGN_CHECK_VAL(s->max_in_frames, strchr(item, '=') + 1, 1); } else if (strcasecmp("help", item) == 0) { usage(); return static_cast(INIT_NOERR); } else { log_msg(LOG_LEVEL_ERROR, "[J2K] Wrong option: %s\n", item); - return NULL; + goto error; } } + s->pool = video_frame_pool(s->max_in_frames, allocator()); + if (quality < 0.0 || quality > 1.0) { LOG(LOG_LEVEL_ERROR) << "[J2K] Quality should be in interval [0-1]!\n"; - return nullptr; + goto error; } - auto *s = new state_video_compress_j2k(bitrate, pool_size, mct); - struct cmpto_j2k_enc_ctx_cfg *ctx_cfg; CHECK_OK(cmpto_j2k_enc_ctx_cfg_create(&ctx_cfg), "Context configuration create", goto error);