UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
cmpto_j2k.cpp
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2013-2024 CESNET
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
50#ifdef HAVE_CONFIG_H
51#include "config.h"
52#endif // HAVE_CONFIG_H
53
54#include <cassert>
55#include <climits>
56#include <condition_variable>
57#include <mutex>
58#include <utility>
59
60#include <cmpto_j2k_enc.h>
61
62#ifdef HAVE_CUDA
63#include "cuda_wrapper.h"
65#endif
66#include "debug.h"
67#include "host.h"
68#include "lib_common.h"
69#include "module.h"
70#include "tv.h"
71#include "utils/color_out.h"
72#include "utils/macros.h" // for IS_KEY_PREFIX, TOSTRING
73#include "utils/misc.h"
74#include "utils/parallel_conv.h"
76#include "video_codec.h" // for vc_get_linesize, codec_is_a_rgb
77#include "video_compress.h"
78#include "video_frame.h" // for vf_alloc_desc, vf_free, vf_resto...
79
80#define MOD_NAME "[Cmpto J2K enc.] "
81
82#define CHECK_OK(cmd, err_msg, action_fail) do { \
83 int j2k_error = cmd; \
84 if (j2k_error != CMPTO_OK) {\
85 log_msg(LOG_LEVEL_ERROR, "[J2K enc.] %s: %s\n", \
86 err_msg, cmpto_j2k_enc_get_last_error()); \
87 action_fail;\
88 } \
89} while(0)
90
91#define NOOP ((void) 0)
92#define DEFAULT_QUALITY 0.7
95#define DEFAULT_POOL_SIZE 4
96
98#define DEFAULT_TILE_LIMIT 1
99#define DEFAULT_MEM_LIMIT 1000000000LLU
100
101using std::condition_variable;
102using std::mutex;
103using std::stod;
104using std::shared_ptr;
105using std::unique_lock;
106
107#ifdef HAVE_CUDA
108template <decltype(cuda_wrapper_malloc_host) alloc,
109 decltype(cuda_wrapper_free_host) free>
110struct cmpto_j2k_enc_cuda_buffer_data_allocator
112 void *allocate(size_t size) override
113 {
114 if (alloc == cuda_wrapper_malloc) {
116 }
117 void *ptr = nullptr;
119 alloc(&ptr, size)) {
120 MSG(ERROR, "Cannot allocate host buffer: %s\n",
122 return nullptr;
123 }
124 return ptr;
125 }
126 void deallocate(void *ptr) override { free(ptr); }
127 [[nodiscard]] video_frame_pool_allocator *clone() const override
128 {
129 return new cmpto_j2k_enc_cuda_buffer_data_allocator(*this);
130 }
131};
132#endif
133
136 struct cmpto_j2k_enc_ctx *context{};
137 struct cmpto_j2k_enc_cfg *enc_settings{};
138 long long int rate = 0;
139 int mct = -1; // force use of mct - -1 means default
142
143 // settings
144 unsigned int max_in_frames =
149
150 unsigned int in_frames{};
151 mutex lock;
152 condition_variable frame_popped;
156
157 condition_variable configure_cv;
158 bool configured = false;
159 bool should_exit = false;
160};
161
162// prototypes
164static void j2k_compress_done(struct module *mod);
165static void cleanup_common(struct state_video_compress_j2k *s);
166
167static void parallel_conv(video_frame *dst, video_frame *src){
168 int src_pitch = vc_get_linesize(src->tiles[0].width, src->color_spec);
169 int dst_pitch = vc_get_linesize(dst->tiles[0].width, dst->color_spec);
170
171 decoder_t decoder =
173 assert(decoder != nullptr);
175 parallel_pix_conv((int) src->tiles[0].height, dst->tiles[0].data,
176 dst_pitch, src->tiles[0].data, src_pitch,
177 decoder, 0);
178 if (log_level >= LOG_LEVEL_DEBUG) {
179 MSG(DEBUG, "pixfmt conversion duration: %f ms\n",
180 NS_TO_MS((double) (get_time_in_ns() - t0)));
181 }
182}
183
184const cmpto_j2k_enc_preprocessor_run_callback_cuda r12l_to_rg48_cuda =
185#ifdef HAVE_CUDA
187#else
188 nullptr;
189#endif
190
191static struct {
193 enum cmpto_sample_format_type cmpto_sf;
195 cmpto_j2k_enc_preprocessor_run_callback_cuda cuda_convert_func;
196} codecs[] = {
197 {UYVY, CMPTO_422_U8_P1020, VIDEO_CODEC_NONE, nullptr},
198 {v210, CMPTO_422_U10_V210, VIDEO_CODEC_NONE, nullptr},
199 {RGB, CMPTO_444_U8_P012, VIDEO_CODEC_NONE, nullptr},
200 {RGBA, CMPTO_444_U8_P012Z, VIDEO_CODEC_NONE, nullptr},
201 {R10k, CMPTO_444_U10U10U10_MSB32BE_P210, VIDEO_CODEC_NONE, nullptr},
202 {RG48, CMPTO_444_U12_MSB16LE_P012, VC_NONE, nullptr},
203 {R12L, CMPTO_444_U12_MSB16LE_P012, RG48, r12l_to_rg48_cuda},
205
206#define CPU_CONV_PARAM "j2k-enc-cpu-conv"
209 "* " CPU_CONV_PARAM "\n"
210 " Enforce CPU conversion instead of CUDA (applicable to R12L now)\n");
211static void
212set_pool(struct state_video_compress_j2k *s, bool have_gpu_preprocess)
213{
214#ifdef HAVE_CUDA
215 s->pool_in_device_memory = false;
216 if (cuda_devices_count > 1) {
217 MSG(WARNING, "More than 1 CUDA device will use CPU buffers and "
218 "conversion...\n");
219 } else if (s->precompress_codec == VC_NONE || have_gpu_preprocess) {
220 s->pool_in_device_memory = true;
222 s->max_in_frames,
223 cmpto_j2k_enc_cuda_buffer_data_allocator<
225 return;
226 }
228 s->max_in_frames,
229 cmpto_j2k_enc_cuda_buffer_data_allocator<cuda_wrapper_malloc_host,
231#else
232 assert(!have_gpu_preprocess); // if CUDA not found, we shouldn't have
234#endif
235}
236
238 enum cmpto_sample_format_type sample_format;
239 cmpto_j2k_enc_preprocessor_run_callback_cuda cuda_convert_func =
240 nullptr;
241 bool found = false;
242
243 for(const auto &codec : codecs){
244 if(codec.ug_codec == desc.color_spec){
245 sample_format = codec.cmpto_sf;
246 s->precompress_codec = codec.convert_codec;
247 cuda_convert_func = codec.cuda_convert_func;
248 found = true;
249 break;
250 }
251 }
252
253 if(!found){
254 log_msg(LOG_LEVEL_ERROR, "[J2K] Failed to find suitable pixel format\n");
255 return false;
256 }
257
258 if (s->configured) {
259 unique_lock<mutex> lk(s->lock);
260 CHECK_OK(cmpto_j2k_enc_ctx_stop(s->context), "stop", abort());
261 s->frame_popped.wait(lk, [s] { return s->in_frames == 0; });
263 s->configured = false;
264 }
265
266 if (get_commandline_param(CPU_CONV_PARAM) != nullptr) {
267 cuda_convert_func = nullptr;
268 }
269
270 struct cmpto_j2k_enc_ctx_cfg *ctx_cfg = nullptr;
271 CHECK_OK(cmpto_j2k_enc_ctx_cfg_create(&ctx_cfg),
272 "Context configuration create", return false);
273 for (unsigned int i = 0; i < cuda_devices_count; ++i) {
274 CHECK_OK(
275 cmpto_j2k_enc_ctx_cfg_add_cuda_device(
276 ctx_cfg, cuda_devices[i], s->mem_limit, s->tile_limit),
277 "Setting CUDA device", return false);
278 }
279 if (cuda_convert_func != nullptr) {
280 CHECK_OK(cmpto_j2k_enc_ctx_cfg_set_preprocessor_cuda(
281 ctx_cfg, nullptr, nullptr, cuda_convert_func),
282 "Setting CUDA preprocess", return false);
283 }
284
285 CHECK_OK(cmpto_j2k_enc_ctx_create(ctx_cfg, &s->context),
286 "Context create", return false);
287 CHECK_OK(cmpto_j2k_enc_ctx_cfg_destroy(ctx_cfg),
288 "Context configuration destroy", NOOP);
289
290 CHECK_OK(cmpto_j2k_enc_cfg_create(s->context, &s->enc_settings),
291 "Creating context configuration:", return false);
292 CHECK_OK(cmpto_j2k_enc_cfg_set_quantization(
293 s->enc_settings,
294 s->quality /* 0.0 = poor quality, 1.0 = full quality */
295 ),
296 "Setting quantization", NOOP);
297
298 CHECK_OK(cmpto_j2k_enc_cfg_set_resolutions(s->enc_settings, 6),
299 "Setting DWT levels", NOOP);
300
301 CHECK_OK(cmpto_j2k_enc_cfg_set_samples_format_type(s->enc_settings, sample_format),
302 "Setting sample format", return false);
303 CHECK_OK(cmpto_j2k_enc_cfg_set_size(s->enc_settings, desc.width, desc.height),
304 "Setting image size", return false);
305 if (s->rate) {
306 CHECK_OK(cmpto_j2k_enc_cfg_set_rate_limit(s->enc_settings,
307 CMPTO_J2K_ENC_COMP_MASK_ALL,
308 CMPTO_J2K_ENC_RES_MASK_ALL, s->rate / 8 / desc.fps),
309 "Setting rate limit",
310 NOOP);
311 }
312
313 int mct = s->mct;
314 if (mct == -1) {
315 mct = codec_is_a_rgb(desc.color_spec) ? 1 : 0;
316 }
317 CHECK_OK(cmpto_j2k_enc_cfg_set_mct(s->enc_settings, mct),
318 "Setting MCT",
319 NOOP);
320
321 char rate[100];
322 snprintf_ch(rate, "%s", s->rate == 0 ? "unset" : format_in_si_units(s->rate));
323 MSG(INFO,
324 "Using parameters: quality=%.2f, bitrate=%sbps, mem_limit=%sB, "
325 "tile_limit=%u, pool_size=%u, mct=%d\n",
327 s->max_in_frames, mct);
328
329 set_pool(s, cuda_convert_func != nullptr);
330
334
335 s->saved_desc = desc;
336
337 s->configured = true;
338 s->configure_cv.notify_one();
339
340 return true;
341}
342
348static void
349do_gpu_copy(std::shared_ptr<video_frame> &ret, video_frame *in_frame)
350{
351#ifdef HAVE_CUDA
353 cuda_wrapper_memcpy(ret->tiles[0].data, in_frame->tiles[0].data,
354 in_frame->tiles[0].data_len,
356#else
357 (void) ret, (void) in_frame;
358 abort(); // must not reach here
359#endif
360}
361
362static shared_ptr<video_frame> get_copy(struct state_video_compress_j2k *s, video_frame *frame){
363 std::shared_ptr<video_frame> ret = s->pool.get_frame();
364
365 if (s->pool_in_device_memory) {
366 do_gpu_copy(ret, frame);
367 } else if (s->precompress_codec != VC_NONE) {
368 parallel_conv(ret.get(), frame);
369 } else {
370 memcpy(ret->tiles[0].data, frame->tiles[0].data,
371 frame->tiles[0].data_len);
372 }
373
374 return ret;
375}
376
379 custom_data() = delete;
382 ~custom_data() = delete;
383 shared_ptr<video_frame> frame;
385 // metadata stored separately, frame may have already been deallocated
386 // by our release_cstream callback
388};
389
397#define HANDLE_ERROR_COMPRESS_POP do { cmpto_j2k_enc_img_destroy(img); goto start; } while (0)
398static std::shared_ptr<video_frame> j2k_compress_pop(struct module *state)
399{
400 auto *s = (struct state_video_compress_j2k *) state;
401start:
402 {
403 unique_lock<mutex> lk(s->lock);
404 s->configure_cv.wait(lk, [s] { return s->configured ||
405 s->should_exit; });
406 if (s->should_exit) {
407 return {}; // pass poison pill further
408 }
409 }
410
411 struct cmpto_j2k_enc_img *img;
412 int status;
413 CHECK_OK(cmpto_j2k_enc_ctx_get_encoded_img(
414 s->context, 1, &img /* Set to NULL if encoder stopped */,
415 &status),
416 "Encode image pop", HANDLE_ERROR_COMPRESS_POP);
417 if (img == nullptr) {
418 // this happens when cmpto_j2k_enc_ctx_stop() is called
419 goto start; // reconfiguration or exit
420 } else {
421 unique_lock<mutex> lk(s->lock);
422 s->in_frames--;
423 s->frame_popped.notify_one();
424 }
425 if (status != CMPTO_J2K_ENC_IMG_OK) {
426 const char * encoding_error = "";
427 CHECK_OK(cmpto_j2k_enc_img_get_error(img, &encoding_error), "get error status",
428 encoding_error = "(failed)");
429 log_msg(LOG_LEVEL_ERROR, "Image encoding failed: %s\n", encoding_error);
430 goto start;
431 }
432 struct custom_data *udata = nullptr;
433 size_t len;
434 CHECK_OK(cmpto_j2k_enc_img_get_custom_data(img, (void **) &udata, &len),
435 "get custom data", HANDLE_ERROR_COMPRESS_POP);
436 size_t size;
437 void * ptr;
438 CHECK_OK(cmpto_j2k_enc_img_get_cstream(img, &ptr, &size),
439 "get cstream", HANDLE_ERROR_COMPRESS_POP);
440
441 struct video_frame *out = vf_alloc_desc(udata->desc);
442 vf_restore_metadata(out, udata->metadata);
443 out->tiles[0].data_len = size;
444 out->tiles[0].data = (char *) malloc(size);
445 memcpy(out->tiles[0].data, ptr, size);
446 CHECK_OK(cmpto_j2k_enc_img_destroy(img), "Destroy image", NOOP);
449 return shared_ptr<video_frame>(out, out->callbacks.dispose);
450}
451
452struct {
453 const char *label;
454 const char *key;
455 const char *description;
456 const char *opt_str;
457 const bool is_boolean;
458 const char *placeholder;
459} usage_opts[] = {
460 {"Bitrate", "quality", "Target bitrate", ":rate=", false, "70M"},
461 {"Quality", "quant_coeff", "Quality in range [0-1], default: " TOSTRING(DEFAULT_QUALITY), ":quality=", false, TOSTRING(DEFAULT_QUALITY)},
462 {"Mem limit", "mem_limit", "CUDA device memory limit (in bytes), default: " TOSTRING(DEFAULT_MEM_LIMIT), ":mem_limit=", false, TOSTRING(DEFAULT_MEM_LIMIT)},
463 {"Tile limit", "tile_limit", "Number of tiles encoded at moment (less to reduce latency, more to increase performance, 0 means infinity), default: " TOSTRING(DEFAULT_TILE_LIMIT), ":tile_limit=", false, TOSTRING(DEFAULT_TILE_LIMIT)},
464 {"Pool size", "pool_size", "Total number of tiles encoder can hold at moment (same meaning as above), default: " TOSTRING(DEFAULT_POOL_SIZE) ", should be greater than <t>", ":pool_size=", false, TOSTRING(DEFAULT_POOL_SIZE)},
465 {"Use MCT", "mct", "use MCT", ":mct", true, ""},
467
468static void usage() {
469 col() << "J2K compress usage:\n";
470 col() << TERM_BOLD << TRED("\t-c cmpto_j2k");
471 for(const auto& opt : usage_opts){
472 assert(strlen(opt.opt_str) >= 2);
473 col() << "[" << opt.opt_str;
474 if (!opt.is_boolean) {
475 col() << "<" << opt.opt_str[1] << ">"; // :quality -> <q> (first letter used as ":quality=<q>")
476 }
477 col() << "]";
478 }
479 col() << "\n\t\t[--cuda-device <c_index>] [--param " CPU_CONV_PARAM "]\n" << TERM_RESET;
480
481 col() << "where:\n";
482 for(const auto& opt : usage_opts){
483 if (opt.is_boolean) {
484 col() << TBOLD("\t" << opt.opt_str + 1 <<);
485 } else {
486 col() << TBOLD("\t<" << opt.opt_str[1] << ">");
487 }
488 col() << " - " << opt.description << "\n";
489 }
490 col() << TBOLD("\t<c_index>") << " - CUDA device(s) to use (comma separated)\n";
491 col() << TBOLD("\t--param " CPU_CONV_PARAM)
492 << " - use CPU for pixfmt conversion (useful if GPU\n\t\tis fully "
493 "occupied by the encoder; an option for decoder exists as "
494 "well)\n";
495 color_printf("\nOption prefixes (eg. 'q=' for quality) can be used. SI "
496 "suffixes are recognized (eg. 'r=7.5M').\n");
497#ifdef HAVE_CUDA
498 constexpr char cuda_supported[] = "YES";
499#else
500 constexpr char cuda_supported[] = TRED("NO");
501#endif
503 "\nUltraGrid compiled with " TBOLD("CUDA") " support: %s\n",
504 cuda_supported);
505}
506
507#define ASSIGN_CHECK_VAL(var, str, minval) \
508 do { \
509 long long val = unit_evaluate_dbl(str, false, nullptr); \
510 if (val < (minval) || val > UINT_MAX) { \
511 LOG(LOG_LEVEL_ERROR) \
512 << "[J2K] Wrong value " << (str) \
513 << " for " #var "! Value must be >= " << (minval) \
514 << ".\n"; \
515 return NULL; \
516 } \
517 (var) = val; \
518 } while (0)
519
520static struct module * j2k_compress_init(struct module *parent, const char *c_cfg)
521{
522 const auto *version = cmpto_j2k_enc_get_version();
523 LOG(LOG_LEVEL_INFO) << MOD_NAME << "Using codec version: " << (version == nullptr ? "(unknown)" : version->name) << "\n";
524
525 auto *s = new state_video_compress_j2k();
526
527 char *tmp = (char *) alloca(strlen(c_cfg) + 1);
528 strcpy(tmp, c_cfg);
529 char *save_ptr, *item;
530 while ((item = strtok_r(tmp, ":", &save_ptr))) {
531 tmp = NULL;
532 if (IS_KEY_PREFIX(item, "rate")) {
533 ASSIGN_CHECK_VAL(s->rate, strchr(item, '=') + 1, 1);
534 } else if (IS_KEY_PREFIX(item, "quality")) {
535 s->quality = stod(strchr(item, '=') + 1);
536 } else if (strcasecmp("mct", item) == 0 || strcasecmp("nomct", item) == 0) {
537 s->mct = strcasecmp("mct", item) == 0 ? 1 : 0;
538 } else if (IS_KEY_PREFIX(item, "mem_limit")) {
539 ASSIGN_CHECK_VAL(s->mem_limit, strchr(item, '=') + 1, 1);
540 } else if (IS_KEY_PREFIX(item, "tile_limit")) {
541 ASSIGN_CHECK_VAL(s->tile_limit, strchr(item, '=') + 1, 0);
542 } else if (IS_KEY_PREFIX(item, "pool_size")) {
543 ASSIGN_CHECK_VAL(s->max_in_frames, strchr(item, '=') + 1, 1);
544 } else if (strcasecmp("help", item) == 0) {
545 usage();
546 return static_cast<module*>(INIT_NOERR);
547 } else {
548 log_msg(LOG_LEVEL_ERROR, "[J2K] Wrong option: %s\n", item);
549 goto error;
550 }
551 }
552
553 if (s->quality < 0.0 || s->quality > 1.0) {
554 LOG(LOG_LEVEL_ERROR) << "[J2K] Quality should be in interval [0-1]!\n";
555 goto error;
556 }
557
558 module_init_default(&s->module_data);
559 s->module_data.cls = MODULE_CLASS_DATA;
560 s->module_data.priv_data = s;
561 s->module_data.deleter = j2k_compress_done;
562 module_register(&s->module_data, parent);
563
564 return &s->module_data;
565
566error:
567 delete s;
568 return NULL;
569}
570
572{
573 free(frame->tiles[0].data);
574 vf_free(frame);
575}
576
577static void release_cstream(void * custom_data, size_t custom_data_size, const void * codestream, size_t codestream_size)
578{
579 (void) codestream; (void) custom_data_size; (void) codestream_size;
580 auto *udata = static_cast<struct custom_data *>(custom_data);
581 udata->frame.~shared_ptr<video_frame>();
582}
583
584static void
585release_cstream_cuda(void *img_custom_data, size_t img_custom_data_size,
586 int /* device_id */, const void *samples, size_t samples_size)
587{
588 release_cstream(img_custom_data, img_custom_data_size, samples,
589 samples_size);
590}
591
592#define HANDLE_ERROR_COMPRESS_PUSH \
593 if (udata != nullptr) { \
594 udata->frame.~shared_ptr<video_frame>(); \
595 } \
596 if (img != nullptr) { \
597 cmpto_j2k_enc_img_destroy(img); \
598 } \
599 return
600
601static void j2k_compress_push(struct module *state, std::shared_ptr<video_frame> tx)
602{
603 struct state_video_compress_j2k *s =
605 struct cmpto_j2k_enc_img *img = NULL;
606 struct custom_data *udata = nullptr;
607
608 if (tx == NULL) { // pass poison pill through encoder
609 unique_lock<mutex> lk(s->lock);
610 s->should_exit = true;
611 if (s->configured) {
612 CHECK_OK(cmpto_j2k_enc_ctx_stop(s->context), "stop",
613 NOOP);
614 } else {
615 s->configure_cv.notify_one();
616 }
617 return;
618 }
619
620 const struct video_desc desc = video_desc_from_frame(tx.get());
621 if (!video_desc_eq(s->saved_desc, desc)) {
622 int ret = configure_with(s, desc);
623 if (!ret) {
624 return;
625 }
626 struct video_desc pool_desc = desc;
627 if (s->precompress_codec != VC_NONE &&
629 pool_desc.color_spec = s->precompress_codec;
630 }
631 s->pool.reconfigure(
632 pool_desc, (size_t) vc_get_linesize(pool_desc.width,
633 pool_desc.color_spec) *
634 pool_desc.height);
635 }
636
637 assert(tx->tile_count == 1); // TODO
638
639 CHECK_OK(cmpto_j2k_enc_img_create(s->context, &img),
640 "Image create", return);
641
642 /*
643 * Copy video desc to udata (to be able to reconstruct in j2k_compress_pop().
644 * Further make a place for a shared pointer of allocated data, deleter
645 * returns frame to pool in call of release_cstream() callback (called when
646 * encoder no longer needs the input data).
647 */
648 CHECK_OK(cmpto_j2k_enc_img_allocate_custom_data(
649 img,
650 sizeof *udata,
651 (void **) &udata),
652 "Allocate custom image data",
654 memcpy(&udata->desc, &s->compressed_desc, sizeof(s->compressed_desc));
655 new (&udata->frame) shared_ptr<video_frame>(get_copy(s, tx.get()));
656 vf_store_metadata(tx.get(), udata->metadata);
657
658 if (s->pool_in_device_memory) {
659 // cmpto_j2k_enc requires the size after postprocess, which
660 // doesn't equeal the IN frame data_len for R12L
661 const codec_t device_codec = s->precompress_codec == VC_NONE
662 ? udata->frame->color_spec
664 const size_t data_len =
665 vc_get_datalen(udata->frame->tiles[0].width,
666 udata->frame->tiles[0].height, device_codec);
667 CHECK_OK(cmpto_j2k_enc_img_set_samples_cuda(
668 img, cuda_devices[0], udata->frame->tiles[0].data,
669 data_len, release_cstream_cuda),
670 "Setting image samples", HANDLE_ERROR_COMPRESS_PUSH);
671 } else {
672 CHECK_OK(cmpto_j2k_enc_img_set_samples(
673 img, udata->frame->tiles[0].data,
674 udata->frame->tiles[0].data_len, release_cstream),
675 "Setting image samples", HANDLE_ERROR_COMPRESS_PUSH);
676 }
677
678 unique_lock<mutex> lk(s->lock);
679 s->frame_popped.wait(lk, [s]{return s->in_frames < s->max_in_frames;});
680 lk.unlock();
681 bool failed = false;
682 CHECK_OK(cmpto_j2k_enc_img_encode(img, s->enc_settings),
683 "Encode image push", failed = true);
684 if (failed) {
685 udata->frame.~shared_ptr<video_frame>();
686 cmpto_j2k_enc_img_destroy(img);
687 return;
688 }
689 lk.lock();
690 s->in_frames++;
691 lk.unlock();
692
693}
694
695static void j2k_compress_done(struct module *mod)
696{
697 struct state_video_compress_j2k *s =
698 (struct state_video_compress_j2k *) mod->priv_data;
700 delete s;
701}
702
703static void
705{
706
707 if (s->enc_settings != nullptr) {
708 cmpto_j2k_enc_cfg_destroy(s->enc_settings);
709 }
710 s->enc_settings = nullptr;
711 if (s->context != nullptr) {
712 cmpto_j2k_enc_ctx_destroy(s->context);
713 }
714 s->context = nullptr;
715}
716
718 compress_module_info module_info;
719 module_info.name = "cmpto_j2k";
720
721 for(const auto& opt : usage_opts){
722 module_info.opts.emplace_back(module_option{opt.label,
723 opt.description, opt.placeholder, opt.key, opt.opt_str, opt.is_boolean});
724 }
725
727 codec_info.name = "Comprimato jpeg2000";
728 codec_info.priority = 400;
729 codec_info.encoders.emplace_back(encoder{"default", ""});
730
731 module_info.codecs.emplace_back(std::move(codec_info));
732
733 return module_info;
734}
735
737 "cmpto_j2k",
739 NULL,
740 NULL,
741 NULL,
742 NULL,
746};
747
749
void ** state
struct video_desc desc
struct video_frame * frame
int void size_t * len
void vf_free(struct video_frame *buf)
Frees video_frame structure.
struct video_desc video_desc_from_frame(const struct video_frame *frame)
Returns struct video_desc from video frame.
int vc_get_linesize(unsigned int width, codec_t codec)
struct video_frame * vf_alloc_desc(struct video_desc desc)
Allocates video frame accordig given desc.
int color_printf(const char *format,...)
#define TERM_BOLD
Definition color_out.h:48
#define TERM_RESET
Definition color_out.h:47
#define TRED(x)
Definition color_out.h:75
#define TBOLD(x)
Definition color_out.h:70
int cuda_wrapper_set_device(int index)
int cuda_wrapper_malloc_host(void **buffer, size_t data_len)
int cuda_wrapper_free_host(void *buffer)
int cuda_wrapper_free(void *buffer)
const char * cuda_wrapper_last_error_string(void)
int cuda_wrapper_memcpy(void *dst, const void *src, size_t count, int kind)
int cuda_wrapper_malloc(void **buffer, size_t data_len)
This file contais wrapper around CUDA functions.
#define CUDA_WRAPPER_SUCCESS
#define CUDA_WRAPPER_MEMCPY_HOST_TO_DEVICE
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define MSG(l, fmt,...)
Definition debug.h:96
#define LOG(level)
Definition debug.h:313
void module_init_default(struct module *module_data)
Definition module.c:48
void module_register(struct module *module_data, struct module *parent)
Definition module.c:82
@ MODULE_CLASS_DATA
Definition module.h:86
#define VIDEO_COMPRESS_ABI_VERSION
unsigned int cuda_devices_count
Definition host.cpp:168
const char * get_commandline_param(const char *key)
Definition host.cpp:894
unsigned int cuda_devices[MAX_CUDA_DEVICES]
Definition host.cpp:167
#define ADD_TO_PARAM(param, doc)
Definition host.h:203
#define INIT_NOERR
Definition host.h:73
#define LOG_LEVEL_DEBUG
Definition kernels.cu:48
volatile int log_level
Definition debug.cpp:65
int preprocess_r12l_to_rg48(void *preprocessor, void *img_custom_data, size_t img_custom_data_size, int size_x, int size_y, struct cmpto_j2k_enc_comp_format *comp_formats, int comp_count, void *input_samples, size_t input_samples_size, void *output_samples, size_t output_samples_size, void *vstream)
Definition kernels.cu:453
@ LIBRARY_CLASS_VIDEO_COMPRESS
Definition lib_common.h:82
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
#define snprintf_ch(str,...)
shortcut for snprintf(var, sizeof var...), var must be a char array
Definition macros.h:101
#define TOSTRING(A)
Definition macros.h:49
#define IS_KEY_PREFIX(tok, key)
expands to true value if <k> from tok in format <k>=<v> is prefix of key
Definition macros.h:138
#define DEBUG
Definition main.c:27
const char * format_in_si_units(unsigned long long int val)
Definition misc.cpp:154
void parallel_pix_conv(int height, char *out, int out_linesize, const char *in, int in_linesize, decoder_t decode, int threads)
decoder_t get_decoder_from_to(codec_t in, codec_t out)
decoder_func_t * decoder_t
Definition pixfmt_conv.h:96
static void start()
Definition sdp.c:202
const char * parent
Definition settings.cpp:198
const char * name
displayed name
std::vector< codec > codecs
std::vector< module_option > opts
auxilliary data structure passed with encoded frame
~custom_data()=delete
custom_data(custom_data &b)=delete
shared_ptr< video_frame > frame
custom_data()=delete
custom_data & operator=(const custom_data &)=delete
char metadata[VF_METADATA_SIZE]
video_desc desc
Definition hd-rum.c:27
void * priv_data
Definition module.h:126
unsigned int max_in_frames
max number of frames between push and pop
video_frame_pool pool
pool for frames allocated by us but not yet consumed by encoder
condition_variable configure_cv
struct cmpto_j2k_enc_cfg * enc_settings
bool pool_in_device_memory
frames in pool are on GPU
long long int rate
bitrate in bits per second
condition_variable frame_popped
unsigned int in_frames
number of currently encoding frames
struct cmpto_j2k_enc_ctx * context
unsigned int width
Definition types.h:280
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
unsigned int data_len
length of the data
Definition types.h:288
unsigned int height
Definition types.h:281
unsigned int tile_count
Definition types.h:185
codec_t color_spec
Definition types.h:182
double fps
Definition types.h:183
unsigned int width
width of every tile (!)
Definition types.h:179
unsigned int height
height of every tile (!)
Definition types.h:180
void(* dispose)(struct video_frame *)
Definition types.h:245
virtual void * allocate(size_t size)=0
virtual struct video_frame_pool_allocator * clone() const =0
virtual void deallocate(void *ptr)=0
std::shared_ptr< video_frame > get_frame()
void reconfigure(struct video_desc new_desc, size_t new_size=SIZE_MAX)
Struct video_frame represents a video frame and contains video description.
Definition types.h:305
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
Definition types.h:345
struct video_frame_callbacks callbacks
Definition types.h:324
int64_t compress_end
in ns from epoch
Definition types.h:339
codec_t color_spec
Definition types.h:306
long long time_ns_t
Definition tv.h:81
static time_ns_t get_time_in_ns()
Definition tv.h:101
#define NS_TO_MS(val_ns)
Definition tv.h:98
#define VF_METADATA_SIZE
Definition types.h:348
codec_t
Definition types.h:65
@ R10k
RGB 10-bit packed - RGBX, big-endian (2 bit padding)
Definition types.h:73
@ RGB
RGB 8-bit (packed into 24-bit word)
Definition types.h:80
@ UYVY
YCbCr 422 8-bit - Cb Y0 Cr Y1.
Definition types.h:71
@ VIDEO_CODEC_NONE
dummy color spec
Definition types.h:66
@ RG48
16-bit RGB little-endian (RlRhGl...)
Definition types.h:95
@ VC_NONE
Definition types.h:67
@ J2KR
JPEG 2000 RGB.
Definition types.h:90
@ J2K
JPEG 2000.
Definition types.h:89
@ R12L
RGB 12-bit packed, little-endian.
Definition types.h:74
@ RGBA
RGBA 8-bit, big-endian.
Definition types.h:70
@ v210
YCbCr 422 10-bit - xVY0U|xY2UY1|xUY3V|xY5VY4, little-endian (2 bit padding /'x'/),...
Definition types.h:75
codec_t ug_codec
Definition v4l2_common.h:68
bool codec_is_a_rgb(codec_t codec)
Returns TRUE if specified pixelformat is some form of RGB (not YUV).
size_t vc_get_datalen(unsigned int width, unsigned int height, codec_t codec)
static const struct codec_info_t codec_info[]
const char * placeholder
Definition cineform.cpp:128
const char * opt_str
Definition cineform.cpp:127
const char * description
Definition cineform.cpp:126
const char * label
Definition cineform.cpp:124
const char * key
Definition cineform.cpp:125
static void j2k_compress_push(struct module *state, std::shared_ptr< video_frame > tx)
#define CPU_CONV_PARAM
enum cmpto_sample_format_type cmpto_sf
#define DEFAULT_POOL_SIZE
Definition cmpto_j2k.cpp:95
#define DEFAULT_QUALITY
Definition cmpto_j2k.cpp:92
codec_t convert_codec
static shared_ptr< video_frame > get_copy(struct state_video_compress_j2k *s, video_frame *frame)
static void do_gpu_copy(std::shared_ptr< video_frame > &ret, video_frame *in_frame)
copies frame from RAM to GPU
static void usage()
static void release_cstream(void *custom_data, size_t custom_data_size, const void *codestream, size_t codestream_size)
#define ASSIGN_CHECK_VAL(var, str, minval)
static std::shared_ptr< video_frame > j2k_compress_pop(struct module *state)
static void j2k_compress_done(struct module *mod)
static void release_cstream_cuda(void *img_custom_data, size_t img_custom_data_size, int, const void *samples, size_t samples_size)
#define HANDLE_ERROR_COMPRESS_PUSH
static struct video_compress_info j2k_compress_info
#define CHECK_OK(cmd, err_msg, action_fail)
Definition cmpto_j2k.cpp:82
static bool configure_with(struct state_video_compress_j2k *s, struct video_desc desc)
static compress_module_info get_cmpto_j2k_module_info()
#define NOOP
Definition cmpto_j2k.cpp:91
#define MOD_NAME
Definition cmpto_j2k.cpp:80
struct @78 usage_opts[]
static void j2k_compressed_frame_dispose(struct video_frame *frame)
#define DEFAULT_TILE_LIMIT
number of frames that encoder encodes at moment
Definition cmpto_j2k.cpp:98
const bool is_boolean
static void parallel_conv(video_frame *dst, video_frame *src)
const cmpto_j2k_enc_preprocessor_run_callback_cuda r12l_to_rg48_cuda
cmpto_j2k_enc_preprocessor_run_callback_cuda cuda_convert_func
static void set_pool(struct state_video_compress_j2k *s, bool have_gpu_preprocess)
static struct module * j2k_compress_init(struct module *parent, const char *c_cfg)
#define HANDLE_ERROR_COMPRESS_POP
static struct @77 codecs[]
#define DEFAULT_MEM_LIMIT
Definition cmpto_j2k.cpp:99
static void cleanup_common(struct state_video_compress_j2k *s)
API for video compress drivers.
void vf_store_metadata(const struct video_frame *f, void *s)
bool video_desc_eq(struct video_desc a, struct video_desc b)
Compares two video descriptions.
void vf_restore_metadata(struct video_frame *f, void *s)