Skip to content

Commit

Permalink
vcomp/cmpto_j2k: allow late (lazy) initialization
Browse files Browse the repository at this point in the history
Initialize the encoder stuff in configure_with, not _init.

It will allow the encoder parameter changes during the
reconfiguration. This will, however, require additional syncrhonization
and cleanup on the reconf.

There is no functional change in this commit but it changes the internal
behavior, namely the codec state is destroyed on reconfiguration and
newly created.
  • Loading branch information
MartinPulec committed Sep 12, 2024
1 parent 9b9105f commit caacebc
Showing 1 changed file with 93 additions and 53 deletions.
146 changes: 93 additions & 53 deletions src/video_compress/cmpto_j2k.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,20 +139,33 @@ struct state_video_compress_j2k {
int mct = -1; // force use of mct - -1 means default
bool pool_in_device_memory = false; ///< frames in pool are on GPU
video_frame_pool pool; ///< pool for frames allocated by us but not yet consumed by encoder
unsigned int max_in_frames = DEFAULT_POOL_SIZE; ///< max number of frames between push and pop

// settings
unsigned int max_in_frames =
DEFAULT_POOL_SIZE; ///< max number of frames between push and pop
double quality = DEFAULT_QUALITY;
long long int mem_limit = DEFAULT_MEM_LIMIT;
unsigned int tile_limit = DEFAULT_TILE_LIMIT;

unsigned int in_frames{}; ///< number of currently encoding frames
mutex lock;
condition_variable frame_popped;
video_desc saved_desc{};
codec_t precompress_codec = VC_NONE;
video_desc compressed_desc{};

condition_variable configure_cv;
bool configured = false;
bool should_exit = false;

cuda_convert_func_t cuda_convert_func = nullptr;
uint8_t *cuda_conv_tmp_buf = nullptr;
};

// prototypes
static void j2k_compressed_frame_dispose(struct video_frame *frame);
static void j2k_compress_done(struct module *mod);
static void cleanup_common(struct state_video_compress_j2k *s);

static void parallel_conv(video_frame *dst, video_frame *src){
int src_pitch = vc_get_linesize(src->tiles[0].width, src->color_spec);
Expand Down Expand Up @@ -201,18 +214,17 @@ ADD_TO_PARAM(
static void
set_pool(struct state_video_compress_j2k *s, struct video_desc desc)
{
#ifdef HAVE_CUDA
const bool force_cpu_conv =
get_commandline_param(CPU_CONV_PARAM) != nullptr;
s->pool_in_device_memory = false;
#ifdef HAVE_CUDA
if (cuda_devices_count > 1) {
MSG(WARNING, "More than 1 CUDA device will use CPU buffers and "
"conversion...\n");
} else if (!force_cpu_conv || s->cuda_convert_func == nullptr) {
cuda_wrapper_set_device((int) cuda_devices[0]);

if (s->cuda_convert_func != nullptr) {
cuda_wrapper_free(s->cuda_conv_tmp_buf);
cuda_wrapper_malloc(
(void **) &s->cuda_conv_tmp_buf,
vc_get_datalen(desc.width, desc.height, desc.color_spec) +
Expand Down Expand Up @@ -255,6 +267,40 @@ static bool configure_with(struct state_video_compress_j2k *s, struct video_desc
return false;
}

if (s->configured) {
unique_lock<mutex> lk(s->lock);
CHECK_OK(cmpto_j2k_enc_ctx_stop(s->context), "stop", abort());
s->frame_popped.wait(lk, [s] { return s->in_frames == 0; });
cleanup_common(s);
s->configured = false;
}

struct cmpto_j2k_enc_ctx_cfg *ctx_cfg = nullptr;
CHECK_OK(cmpto_j2k_enc_ctx_cfg_create(&ctx_cfg),
"Context configuration create", return false);
for (unsigned int i = 0; i < cuda_devices_count; ++i) {
CHECK_OK(
cmpto_j2k_enc_ctx_cfg_add_cuda_device(
ctx_cfg, cuda_devices[i], s->mem_limit, s->tile_limit),
"Setting CUDA device", return false);
}

CHECK_OK(cmpto_j2k_enc_ctx_create(ctx_cfg, &s->context),
"Context create", return false);
CHECK_OK(cmpto_j2k_enc_ctx_cfg_destroy(ctx_cfg),
"Context configuration destroy", NOOP);

CHECK_OK(cmpto_j2k_enc_cfg_create(s->context, &s->enc_settings),
"Creating context configuration:", return false);
CHECK_OK(cmpto_j2k_enc_cfg_set_quantization(
s->enc_settings,
s->quality /* 0.0 = poor quality, 1.0 = full quality */
),
"Setting quantization", NOOP);

CHECK_OK(cmpto_j2k_enc_cfg_set_resolutions(s->enc_settings, 6),
"Setting DWT levels", NOOP);

CHECK_OK(cmpto_j2k_enc_cfg_set_samples_format_type(s->enc_settings, sample_format),
"Setting sample format", return false);
CHECK_OK(cmpto_j2k_enc_cfg_set_size(s->enc_settings, desc.width, desc.height),
Expand Down Expand Up @@ -283,6 +329,9 @@ static bool configure_with(struct state_video_compress_j2k *s, struct video_desc

s->saved_desc = desc;

s->configured = true;
s->configure_cv.notify_one();

return true;
}

Expand Down Expand Up @@ -354,26 +403,31 @@ struct custom_data {
#define HANDLE_ERROR_COMPRESS_POP do { cmpto_j2k_enc_img_destroy(img); goto start; } while (0)
static std::shared_ptr<video_frame> j2k_compress_pop(struct module *state)
{
auto *s = (struct state_video_compress_j2k *) state;
start:
struct state_video_compress_j2k *s =
(struct state_video_compress_j2k *) state;
{
unique_lock<mutex> lk(s->lock);
s->configure_cv.wait(lk, [s] { return s->configured ||
s->should_exit; });
if (s->should_exit) {
return {}; // pass poison pill further
}
}

struct cmpto_j2k_enc_img *img;
int status;
CHECK_OK(cmpto_j2k_enc_ctx_get_encoded_img(
s->context, 1, &img /* Set to NULL if encoder stopped */,
&status),
"Encode image pop", HANDLE_ERROR_COMPRESS_POP);
{
if (img == nullptr) {
// this happens when cmpto_j2k_enc_ctx_stop() is called
goto start; // reconfiguration or exit
} else {
unique_lock<mutex> lk(s->lock);
s->in_frames--;
s->frame_popped.notify_one();
}
if (!img) {
// this happens cmpto_j2k_enc_ctx_stop() is called
// pass poison pill further
return {};
}
if (status != CMPTO_J2K_ENC_IMG_OK) {
const char * encoding_error = "";
CHECK_OK(cmpto_j2k_enc_img_get_error(img, &encoding_error), "get error status",
Expand Down Expand Up @@ -456,10 +510,6 @@ static void usage() {

static struct module * j2k_compress_init(struct module *parent, const char *c_cfg)
{
double quality = DEFAULT_QUALITY;
long long int mem_limit = DEFAULT_MEM_LIMIT;
unsigned int tile_limit = DEFAULT_TILE_LIMIT;

const auto *version = cmpto_j2k_enc_get_version();
LOG(LOG_LEVEL_INFO) << MOD_NAME << "Using codec version: " << (version == nullptr ? "(unknown)" : version->name) << "\n";

Expand All @@ -473,13 +523,13 @@ static struct module * j2k_compress_init(struct module *parent, const char *c_cf
if (strncasecmp("rate=", item, strlen("rate=")) == 0) {
ASSIGN_CHECK_VAL(s->rate, strchr(item, '=') + 1, 1);
} else if (strncasecmp("quality=", item, strlen("quality=")) == 0) {
quality = stod(strchr(item, '=') + 1);
s->quality = stod(strchr(item, '=') + 1);
} else if (strcasecmp("mct", item) == 0 || strcasecmp("nomct", item) == 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);
ASSIGN_CHECK_VAL(s->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);
ASSIGN_CHECK_VAL(s->tile_limit, strchr(item, '=') + 1, 0);
} else if (strncasecmp("pool_size=", item, strlen("pool_size=")) == 0) {
ASSIGN_CHECK_VAL(s->max_in_frames, strchr(item, '=') + 1, 1);
} else if (strcasecmp("help", item) == 0) {
Expand All @@ -491,40 +541,11 @@ static struct module * j2k_compress_init(struct module *parent, const char *c_cf
}
}

if (quality < 0.0 || quality > 1.0) {
if (s->quality < 0.0 || s->quality > 1.0) {
LOG(LOG_LEVEL_ERROR) << "[J2K] Quality should be in interval [0-1]!\n";
goto error;
}

struct cmpto_j2k_enc_ctx_cfg *ctx_cfg;
CHECK_OK(cmpto_j2k_enc_ctx_cfg_create(&ctx_cfg), "Context configuration create",
goto error);
for (unsigned int i = 0; i < cuda_devices_count; ++i) {
CHECK_OK(cmpto_j2k_enc_ctx_cfg_add_cuda_device(ctx_cfg, cuda_devices[i], mem_limit, tile_limit),
"Setting CUDA device", goto error);
}

CHECK_OK(cmpto_j2k_enc_ctx_create(ctx_cfg, &s->context), "Context create",
goto error);
CHECK_OK(cmpto_j2k_enc_ctx_cfg_destroy(ctx_cfg), "Context configuration destroy",
NOOP);

CHECK_OK(cmpto_j2k_enc_cfg_create(
s->context,
&s->enc_settings),
"Creating context configuration:",
goto error);
CHECK_OK(cmpto_j2k_enc_cfg_set_quantization(
s->enc_settings,
quality /* 0.0 = poor quality, 1.0 = full quality */
),
"Setting quantization",
NOOP);

CHECK_OK(cmpto_j2k_enc_cfg_set_resolutions( s->enc_settings, 6),
"Setting DWT levels",
NOOP);

module_init_default(&s->module_data);
s->module_data.cls = MODULE_CLASS_DATA;
s->module_data.priv_data = s;
Expand Down Expand Up @@ -576,7 +597,14 @@ static void j2k_compress_push(struct module *state, std::shared_ptr<video_frame>
struct custom_data *udata = nullptr;

if (tx == NULL) { // pass poison pill through encoder
CHECK_OK(cmpto_j2k_enc_ctx_stop(s->context), "stop", NOOP);
unique_lock<mutex> lk(s->lock);
s->should_exit = true;
if (s->configured) {
CHECK_OK(cmpto_j2k_enc_ctx_stop(s->context), "stop",
NOOP);
} else {
s->configure_cv.notify_one();
}
return;
}

Expand Down Expand Up @@ -650,15 +678,27 @@ static void j2k_compress_done(struct module *mod)
{
struct state_video_compress_j2k *s =
(struct state_video_compress_j2k *) mod->priv_data;
cleanup_common(s);
delete s;
}

static void
cleanup_common(struct state_video_compress_j2k *s)
{

cmpto_j2k_enc_cfg_destroy(s->enc_settings);
cmpto_j2k_enc_ctx_destroy(s->context);
if (s->enc_settings != nullptr) {
cmpto_j2k_enc_cfg_destroy(s->enc_settings);
}
s->enc_settings = nullptr;
if (s->context != nullptr) {
cmpto_j2k_enc_ctx_destroy(s->context);
}
s->context = nullptr;

#ifdef HAVE_CUDA
cuda_wrapper_free(s->cuda_conv_tmp_buf);
s->cuda_conv_tmp_buf = nullptr;
#endif

delete s;
}

static compress_module_info get_cmpto_j2k_module_info(){
Expand Down

0 comments on commit caacebc

Please sign in to comment.