56#include <condition_variable>
60#include <cmpto_j2k_enc.h>
80#define MOD_NAME "[Cmpto J2K enc.] "
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()); \
91#define NOOP ((void) 0)
92#define DEFAULT_QUALITY 0.7
95#define DEFAULT_POOL_SIZE 4
98#define DEFAULT_TILE_LIMIT 1
99#define DEFAULT_MEM_LIMIT 1000000000LLU
101using std::condition_variable;
104using std::shared_ptr;
105using std::unique_lock;
110struct cmpto_j2k_enc_cuda_buffer_data_allocator
112 void *
allocate(
size_t size)
override
120 MSG(ERROR,
"Cannot allocate host buffer: %s\n",
126 void deallocate(
void *ptr)
override { free(ptr); }
129 return new cmpto_j2k_enc_cuda_buffer_data_allocator(*
this);
173 assert(decoder !=
nullptr);
176 dst_pitch, src->
tiles[0].
data, src_pitch,
179 MSG(
DEBUG,
"pixfmt conversion duration: %f ms\n",
202 {
RG48, CMPTO_444_U12_MSB16LE_P012,
VC_NONE,
nullptr},
206#define CPU_CONV_PARAM "j2k-enc-cpu-conv"
210 " Enforce CPU conversion instead of CUDA (applicable to R12L now)\n");
217 MSG(WARNING,
"More than 1 CUDA device will use CPU buffers and "
223 cmpto_j2k_enc_cuda_buffer_data_allocator<
232 assert(!have_gpu_preprocess);
238 enum cmpto_sample_format_type sample_format;
245 sample_format =
codec.cmpto_sf;
259 unique_lock<mutex> lk(s->
lock);
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);
275 cmpto_j2k_enc_ctx_cfg_add_cuda_device(
277 "Setting CUDA device",
return false);
280 CHECK_OK(cmpto_j2k_enc_ctx_cfg_set_preprocessor_cuda(
282 "Setting CUDA preprocess",
return false);
286 "Context create",
return false);
287 CHECK_OK(cmpto_j2k_enc_ctx_cfg_destroy(ctx_cfg),
288 "Context configuration destroy",
NOOP);
291 "Creating context configuration:",
return false);
292 CHECK_OK(cmpto_j2k_enc_cfg_set_quantization(
296 "Setting quantization",
NOOP);
299 "Setting DWT levels",
NOOP);
302 "Setting sample format",
return false);
304 "Setting image size",
return false);
307 CMPTO_J2K_ENC_COMP_MASK_ALL,
308 CMPTO_J2K_ENC_RES_MASK_ALL, s->
rate / 8 /
desc.
fps),
309 "Setting rate limit",
324 "Using parameters: quality=%.2f, bitrate=%sbps, mem_limit=%sB, "
325 "tile_limit=%u, pool_size=%u, mct=%d\n",
357 (void) ret, (
void) in_frame;
397#define HANDLE_ERROR_COMPRESS_POP do { cmpto_j2k_enc_img_destroy(img); goto start; } while (0)
403 unique_lock<mutex> lk(s->lock);
404 s->configure_cv.wait(lk, [s] {
return s->configured ||
406 if (s->should_exit) {
411 struct cmpto_j2k_enc_img *img;
413 CHECK_OK(cmpto_j2k_enc_ctx_get_encoded_img(
414 s->context, 1, &img ,
417 if (img ==
nullptr) {
421 unique_lock<mutex> lk(s->lock);
423 s->frame_popped.notify_one();
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)");
434 CHECK_OK(cmpto_j2k_enc_img_get_custom_data(img, (
void **) &udata, &
len),
438 CHECK_OK(cmpto_j2k_enc_img_get_cstream(img, &ptr, &size),
444 out->
tiles[0].
data = (
char *) malloc(size);
446 CHECK_OK(cmpto_j2k_enc_img_destroy(img),
"Destroy image",
NOOP);
460 {
"Bitrate",
"quality",
"Target bitrate",
":rate=",
false,
"70M"},
465 {
"Use MCT",
"mct",
"use MCT",
":mct",
true,
""},
469 col() <<
"J2K compress usage:\n";
472 assert(strlen(opt.opt_str) >= 2);
473 col() <<
"[" << opt.opt_str;
474 if (!opt.is_boolean) {
475 col() <<
"<" << opt.opt_str[1] <<
">";
483 if (opt.is_boolean) {
484 col() <<
TBOLD(
"\t" << opt.opt_str + 1 <<);
486 col() <<
TBOLD(
"\t<" << opt.opt_str[1] <<
">");
488 col() <<
" - " << opt.description <<
"\n";
490 col() <<
TBOLD(
"\t<c_index>") <<
" - CUDA device(s) to use (comma separated)\n";
492 <<
" - use CPU for pixfmt conversion (useful if GPU\n\t\tis fully "
493 "occupied by the encoder; an option for decoder exists as "
495 color_printf(
"\nOption prefixes (eg. 'q=' for quality) can be used. SI "
496 "suffixes are recognized (eg. 'r=7.5M').\n");
498 constexpr char cuda_supported[] =
"YES";
500 constexpr char cuda_supported[] =
TRED(
"NO");
503 "\nUltraGrid compiled with " TBOLD(
"CUDA")
" support: %s\n",
507#define ASSIGN_CHECK_VAL(var, str, minval) \
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) \
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";
527 char *tmp = (
char *) alloca(strlen(c_cfg) + 1);
529 char *save_ptr, *
item;
530 while ((
item = strtok_r(tmp,
":", &save_ptr))) {
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;
544 }
else if (strcasecmp(
"help",
item) == 0) {
553 if (s->quality < 0.0 || s->quality > 1.0) {
560 s->module_data.priv_data = s;
564 return &s->module_data;
579 (void) codestream; (void) custom_data_size; (void) codestream_size;
586 int ,
const void *samples,
size_t samples_size)
592#define HANDLE_ERROR_COMPRESS_PUSH \
593 if (udata != nullptr) { \
594 udata->frame.~shared_ptr<video_frame>(); \
596 if (img != nullptr) { \
597 cmpto_j2k_enc_img_destroy(img); \
605 struct cmpto_j2k_enc_img *img = NULL;
609 unique_lock<mutex> lk(s->
lock);
637 assert(
tx->tile_count == 1);
640 "Image create",
return);
648 CHECK_OK(cmpto_j2k_enc_img_allocate_custom_data(
652 "Allocate custom image data",
662 ? udata->
frame->color_spec
664 const size_t data_len =
666 udata->
frame->tiles[0].height, device_codec);
667 CHECK_OK(cmpto_j2k_enc_img_set_samples_cuda(
672 CHECK_OK(cmpto_j2k_enc_img_set_samples(
673 img, udata->
frame->tiles[0].data,
678 unique_lock<mutex> lk(s->
lock);
683 "Encode image push", failed =
true);
686 cmpto_j2k_enc_img_destroy(img);
712 cmpto_j2k_enc_ctx_destroy(s->
context);
719 module_info.
name =
"cmpto_j2k";
723 opt.description, opt.placeholder, opt.key, opt.opt_str, opt.is_boolean});
struct video_frame * frame
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,...)
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,...)
#define LOG_LEVEL_INFO
normal reporting
#define LOG_LEVEL_ERROR
general errors
void module_init_default(struct module *module_data)
void module_register(struct module *module_data, struct module *parent)
#define VIDEO_COMPRESS_ABI_VERSION
unsigned int cuda_devices_count
const char * get_commandline_param(const char *key)
unsigned int cuda_devices[MAX_CUDA_DEVICES]
#define ADD_TO_PARAM(param, doc)
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)
@ LIBRARY_CLASS_VIDEO_COMPRESS
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
#define snprintf_ch(str,...)
shortcut for snprintf(var, sizeof var...), var must be a char array
#define IS_KEY_PREFIX(tok, key)
expands to true value if <k> from tok in format <k>=<v> is prefix of key
const char * format_in_si_units(unsigned long long int val)
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
const char * name
displayed name
std::vector< codec > codecs
std::vector< module_option > opts
auxilliary data structure passed with encoded frame
custom_data(custom_data &b)=delete
shared_ptr< video_frame > frame
custom_data & operator=(const custom_data &)=delete
char metadata[VF_METADATA_SIZE]
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
codec_t precompress_codec
condition_variable frame_popped
unsigned int in_frames
number of currently encoding frames
struct cmpto_j2k_enc_ctx * context
video_desc compressed_desc
char * data
Raw tile data. Pointer must be at least 4B aligned.
unsigned int data_len
length of the data
unsigned int width
width of every tile (!)
unsigned int height
height of every tile (!)
void(* dispose)(struct video_frame *)
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.
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
struct video_frame_callbacks callbacks
int64_t compress_end
in ns from epoch
static time_ns_t get_time_in_ns()
@ R10k
RGB 10-bit packed - RGBX, big-endian (2 bit padding)
@ RGB
RGB 8-bit (packed into 24-bit word)
@ UYVY
YCbCr 422 8-bit - Cb Y0 Cr Y1.
@ VIDEO_CODEC_NONE
dummy color spec
@ RG48
16-bit RGB little-endian (RlRhGl...)
@ R12L
RGB 12-bit packed, little-endian.
@ RGBA
RGBA 8-bit, big-endian.
@ v210
YCbCr 422 10-bit - xVY0U|xY2UY1|xUY3V|xY5VY4, little-endian (2 bit padding /'x'/),...
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[]
static void j2k_compress_push(struct module *state, std::shared_ptr< video_frame > tx)
enum cmpto_sample_format_type cmpto_sf
#define DEFAULT_POOL_SIZE
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 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)
static bool configure_with(struct state_video_compress_j2k *s, struct video_desc desc)
static compress_module_info get_cmpto_j2k_module_info()
static void j2k_compressed_frame_dispose(struct video_frame *frame)
#define DEFAULT_TILE_LIMIT
number of frames that encoder encodes at moment
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
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)