From 843d7bebe1685d6ceefea91bbeda14094fea77ba Mon Sep 17 00:00:00 2001 From: Martin Pulec Date: Wed, 24 Jun 2020 13:26:38 +0200 Subject: [PATCH] Gamma: allow depth conversion --- src/capture_filter/gamma.cpp | 98 +++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 29 deletions(-) diff --git a/src/capture_filter/gamma.cpp b/src/capture_filter/gamma.cpp index edcfcc6b5..12bd11e38 100644 --- a/src/capture_filter/gamma.cpp +++ b/src/capture_filter/gamma.cpp @@ -66,68 +66,86 @@ using std::thread; struct state_capture_filter_gamma { public: - explicit state_capture_filter_gamma(double gamma) { - for (int i = 0; i <= numeric_limits::max(); ++i) { + int out_depth; ///< 0, 8 or 16 (0 menas keep) + + explicit state_capture_filter_gamma(double gamma, int out_depth) : out_depth(out_depth) { + for (int i = 0; i <= numeric_limits::max(); ++i) { // 8->8 lut8.push_back(pow(static_cast(i) / numeric_limits::max(), gamma) * numeric_limits::max()); } - for (int i = 0; i < numeric_limits::max(); ++i) { + for (int i = 0; i <= numeric_limits::max(); ++i) { // 8->16 lut16.push_back(pow(static_cast(i) / numeric_limits::max(), gamma) * numeric_limits::max()); } + for (int i = 0; i <= numeric_limits::max(); ++i) { // 8->16 + lut8_16.push_back(pow(static_cast(i) + / numeric_limits::max(), gamma) + * numeric_limits::max()); + } + for (int i = 0; i <= numeric_limits::max(); ++i) { // 16->8 + lut16_8.push_back(pow(static_cast(i) + / numeric_limits::max(), gamma) + * numeric_limits::max()); + } } - void apply_gamma(int depth, size_t len, void const * __restrict in, void * __restrict out) { - if (depth == CHAR_BIT) { - apply_lut(len, lut8, in, out); - } else if (depth == 2 * CHAR_BIT) { - apply_lut(len, lut16, in, out); + void apply_gamma(int in_depth, int out_depth, size_t in_len, void const * __restrict in, void * __restrict out) { + if (in_depth == CHAR_BIT && out_depth == CHAR_BIT) { + apply_lut(in_len, lut8, in, out); + } else if (in_depth == 2 * CHAR_BIT && out_depth == 2 * CHAR_BIT) { + apply_lut(in_len, lut16, in, out); + } else if (in_depth == CHAR_BIT && out_depth == 2 * CHAR_BIT) { + apply_lut(in_len, lut8_16, in, out); + } else if (in_depth == 2 * CHAR_BIT && out_depth == CHAR_BIT) { + apply_lut(in_len, lut16_8, in, out); } else { throw exception(); } } private: - template + template struct data { size_t len; - const vector &lut; - const T *in; - T *out; + const vector &lut; + const inT *in; + outT *out; }; - template + template static void *compute(void *arg) { - auto *d = static_cast *>(arg); + auto *d = static_cast *>(arg); for (size_t i = 0; i < d->len; ++i) { d->out[i] = d->lut[d->in[i]]; } return nullptr; } - template void apply_lut(size_t len, const vector &lut, void const *in, void *out) + template void apply_lut(size_t in_len, const vector &lut, void const *in, void *out) { - auto *in_data = static_cast(in); - auto *out_data = static_cast(out); + auto *in_data = static_cast(in); + auto *out_data = static_cast(out); unsigned int cpus = thread::hardware_concurrency(); - len /= sizeof(T); - vector> d; + in_len /= sizeof(inT); + vector> d; vector handles(cpus); for (unsigned int i = 0; i < cpus; i++) { - d.push_back({len / cpus, lut, in_data + i * (len / cpus), out_data + i * (len / cpus)}); + d.push_back({in_len / cpus, lut, in_data + i * (in_len / cpus), out_data + i * (in_len / cpus)}); } for (unsigned int i = 0; i < cpus; i++) { - handles[i] = task_run_async(state_capture_filter_gamma::compute, static_cast(&(d[i]))); + handles[i] = task_run_async(state_capture_filter_gamma::compute, static_cast(&(d[i]))); } for (unsigned int i = 0; i < cpus; i++) { - wait_task(handles[i]); + wait_task(handles[i]); } } vector lut8; vector lut16; + vector lut16_8; + vector lut8_16; }; static auto init(struct module *parent, const char *cfg, void **state) @@ -137,18 +155,31 @@ static auto init(struct module *parent, const char *cfg, void **state) if (cfg == nullptr || strcmp(cfg, "help") == 0) { cout << "Performs gamma transformation.\n\n" "usage:\n"; - cout << style::bold << "\t--capture-filter gamma:value\n" << style::reset; + cout << style::bold << "\t--capture-filter gamma:value[:8|:16]\n" << style::reset; + cout << "where:\n"; + cout << style::bold << "\t8|16" << style::reset << " - force output to 8 (16) bits regardless the input\n"; return 1; } char *endptr = nullptr; errno = 0; double gamma = strtod(cfg, &endptr); - if (gamma <= 0.0 || errno != 0 || *endptr != '\0') { + if (gamma <= 0.0 || errno != 0 || (*endptr != '\0' && *endptr != ':')) { LOG(LOG_LEVEL_WARNING) << MOD_NAME << "Using gamma value " << gamma << "\n"; } - auto *s = new state_capture_filter_gamma(gamma); + long int bits = 0; + if (*endptr != '\0') { + endptr += 1; + errno = 0; + bits = strtol(endptr, &endptr, 0); + if ((bits != 8 && bits != 16) || *endptr != '\0') { + LOG(LOG_LEVEL_ERROR) << MOD_NAME << "Wrong number of bits (only 8 or 16)!\n"; + return -1; + } + } + + auto *s = new state_capture_filter_gamma(gamma, bits); *state = s; return 0; @@ -159,15 +190,24 @@ static void done(void *state) delete static_cast(state); } -static auto filter(void *state, struct video_frame *in) +static auto filter(void *state, struct video_frame *in) -> video_frame * { + if (in->color_spec != RGB && in->color_spec != RG48) { + LOG(LOG_LEVEL_ERROR) << MOD_NAME << "Unable to apply lut on: " << get_codec_name(in->color_spec) << "\n"; + VIDEO_FRAME_DISPOSE(in); + return nullptr; + } + auto *s = static_cast(state); - struct video_desc desc = video_desc_from_frame(in); - struct video_frame *out = vf_alloc_desc_data(desc); + struct video_desc out_desc = video_desc_from_frame(in); + if (s->out_depth != 0) { + out_desc.color_spec = s->out_depth == 8 ? RGB : RG48; + } + struct video_frame *out = vf_alloc_desc_data(out_desc); out->callbacks.dispose = vf_free; try { - s->apply_gamma(get_bits_per_component(desc.color_spec), in->tiles[0].data_len, in->tiles[0].data, out->tiles[0].data); + s->apply_gamma(get_bits_per_component(in->color_spec), get_bits_per_component(out_desc.color_spec), in->tiles[0].data_len, in->tiles[0].data, out->tiles[0].data); } catch(...) { LOG(LOG_LEVEL_ERROR) << MOD_NAME << "Only 8-bit and 16-bit codecs are currently supported!\n"; vf_free(out);