summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUmang Jain <umang.jain@ideasonboard.com>2021-05-10 17:27:04 +0530
committerUmang Jain <umang.jain@ideasonboard.com>2021-06-28 14:12:06 +0530
commit2ed7faa7cb7e7b164a75bc249fa24bde1006db38 (patch)
treef759b4a3ce93a229968c98c5f54c477b7f46ec52
parent249b42db7cd39d7ec20094242cd7a8c41ea3b442 (diff)
aiq: Provide managed AIQ Results structures
The AIQ results structures returned from the AIQ library has many complex and deeply nested data structures which must be copied out. This class handles the correct initialisation of a full set of AIQ results, along with the allocations required, and the ability to copy data into those structures correctly. Signed-off-by: Umang Jain <umang.jain@ideasonboard.com> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
-rw-r--r--aiq/aiq_results.cpp297
-rw-r--r--aiq/aiq_results.h115
-rw-r--r--aiq/meson.build5
-rw-r--r--meson.build1
4 files changed, 418 insertions, 0 deletions
diff --git a/aiq/aiq_results.cpp b/aiq/aiq_results.cpp
new file mode 100644
index 0000000..9dda17c
--- /dev/null
+++ b/aiq/aiq_results.cpp
@@ -0,0 +1,297 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+/*
+ * Copyright (C) 2021, Google Inc.
+ *
+ * aiq_results.cpp - Intel IA Imaging library C++ wrapper
+ *
+ * AIQ results container, capable of depth copies and assignments
+ * of the aiq result structures.
+ */
+
+#include "aiq/aiq_results.h"
+
+#include <algorithm>
+
+#include <libcamera/base/log.h>
+
+/* Macros used by imported code */
+#define STDCOPY(dst, src, size) std::copy((src), ((src) + (size)), (dst))
+
+namespace libcamera {
+
+LOG_DEFINE_CATEGORY(AIQResults)
+
+namespace ipa::ipu3::aiq {
+
+AiqResults::AiqResults()
+{
+ /* Initialise AE */
+ ae_.exposures = &aeExposureResult_;
+ ae_.exposures->exposure = &aeExposureParameters_;
+ ae_.exposures->sensor_exposure = &aeSensorParaemeters_;
+ ae_.weight_grid = &aeWeightGrid_;
+ ae_.weight_grid->weights = aeWeights_;
+ ae_.flashes = aeFlashes_;
+
+ /* GBCE */
+ gbce_.r_gamma_lut = RGammaLut_;
+ gbce_.g_gamma_lut = GGammaLut_;
+ gbce_.b_gamma_lut = BGammaLut_;
+ gbce_.gamma_lut_size = MAX_GAMMA_LUT_SIZE;
+ gbce_.tone_map_lut = toneMapLut_;
+ gbce_.tone_map_lut_size = MAX_NUM_TONE_MAP_LUTS;
+
+ /* Initialise afBracket */
+ afBracket_.distances_bracketing = &distanceBracketing_;
+ afBracket_.lens_positions_bracketing = &lensPosBracketing_;
+
+ /* Initialise PA */
+ pa_.preferred_acm = &prefAcm_;
+ pa_.preferred_acm->hue_of_sectors = &hueOfSectors_;
+ pa_.preferred_acm->advanced_color_conversion_matrices =
+ &advancedColorConversionMatrices_;
+ pa_.ir_weight = &irWeight_;
+ pa_.ir_weight->ir_weight_grid_R = &irWeightGridR_;
+ pa_.ir_weight->ir_weight_grid_G = &irWeightGridG_;
+ pa_.ir_weight->ir_weight_grid_B = &irWeightGridB_;
+
+ /* Initialise SA */
+ channelGr_.reserve(DEFAULT_LSC_SIZE);
+ channelGb_.reserve(DEFAULT_LSC_SIZE);
+ channelR_.reserve(DEFAULT_LSC_SIZE);
+ channelB_.reserve(DEFAULT_LSC_SIZE);
+ sa_.channel_gr = channelGr_.data();
+ sa_.channel_gb = channelGb_.data();
+ sa_.channel_r = channelR_.data();
+ sa_.channel_b = channelB_.data();
+}
+
+void AiqResults::setAe(ia_aiq_ae_results *ae)
+{
+ /* Todo: Potentially Requires copying
+ * ia_aiq_aperture_control *aperture_control;
+ */
+
+ ASSERT(ae);
+
+ if (!ae) {
+ LOG(AIQResults, Error) << "Invalid AE argument";
+ return;
+ }
+
+ ae_.lux_level_estimate = ae->lux_level_estimate;
+ ae_.flicker_reduction_mode = ae->flicker_reduction_mode;
+ ae_.multiframe = ae->multiframe;
+ ae_.num_flashes = ae->num_flashes;
+ ae_.num_exposures = ae->num_exposures;
+
+ ae_.exposures->converged = ae->exposures->converged;
+ ae_.exposures->distance_from_convergence = ae->exposures->distance_from_convergence;
+ ae_.exposures->exposure_index = ae->exposures->exposure_index;
+
+ if (ae_.exposures->exposure && ae->exposures->exposure) {
+ *ae_.exposures->exposure = *ae->exposures->exposure;
+ } else {
+ LOG(AIQResults, Error) << "Not copying AE Exposure";
+ }
+
+ if (ae_.exposures->sensor_exposure && ae->exposures->sensor_exposure) {
+ *ae_.exposures->sensor_exposure = *ae->exposures->sensor_exposure;
+ } else {
+ LOG(AIQResults, Error) << "Not copying AE Sensor Exposure";
+ }
+
+ // Copy weight grid
+ if (ae_.weight_grid && ae->weight_grid &&
+ ae_.weight_grid->weights && ae->weight_grid->weights) {
+ ae_.weight_grid->width = ae->weight_grid->width;
+ ae_.weight_grid->height = ae->weight_grid->height;
+
+ unsigned int gridElements = ae->weight_grid->width *
+ ae->weight_grid->height;
+ gridElements = std::clamp<unsigned int>(gridElements, 1, MAX_AE_GRID_SIZE);
+
+ STDCOPY(ae_.weight_grid->weights,
+ ae->weight_grid->weights,
+ gridElements * sizeof(char));
+ } else {
+ LOG(AIQResults, Error) << "Not copying AE Weight Grids";
+ }
+
+ // Copy the flash info structure
+ if (ae_.flashes && ae->flashes) {
+ STDCOPY((int8_t *)ae_.flashes, (int8_t *)ae->flashes,
+ NUM_FLASH_LEDS * sizeof(ia_aiq_flash_parameters));
+ } else {
+ LOG(AIQResults, Error) << "Not copying AE Flashes";
+ }
+}
+
+void AiqResults::setAf(ia_aiq_af_results *af)
+{
+ ASSERT(af);
+
+ af_.status = af->status;
+ af_.current_focus_distance = af->current_focus_distance;
+ af_.next_lens_position = af->next_lens_position;
+ af_.lens_driver_action = af->lens_driver_action;
+ af_.use_af_assist = af->use_af_assist;
+ af_.final_lens_position_reached = af->final_lens_position_reached;
+}
+
+void AiqResults::setAfBracket(ia_aiq_af_bracket_results *afBracket)
+{
+ ASSERT(afBracket);
+
+ /* todo:
+ * Distances Bracketing and lens_positions_bracketing are arrays,
+ * but it's not clear what size they are.
+ */
+ afBracket_.distances_bracketing = afBracket->distances_bracketing;
+ afBracket_.lens_positions_bracketing = afBracket->lens_positions_bracketing;
+}
+
+void AiqResults::setAwb(ia_aiq_awb_results *awb)
+{
+ ASSERT(awb);
+
+ awb_.accurate_r_per_g = awb->accurate_r_per_g;
+ awb_.accurate_b_per_g = awb->accurate_b_per_g;
+ awb_.final_r_per_g = awb->final_r_per_g;
+ awb_.final_b_per_g = awb->final_b_per_g;
+ awb_.cct_estimate = awb->cct_estimate;
+ awb_.distance_from_convergence = awb->distance_from_convergence;
+}
+
+void AiqResults::setGbce(ia_aiq_gbce_results *gbce)
+{
+ ASSERT(gbce);
+
+ if (gbce->gamma_lut_size > 0) {
+ ASSERT(gbce->gamma_lut_size <= MAX_GAMMA_LUT_SIZE);
+
+ gbce_.gamma_lut_size = gbce->gamma_lut_size;
+
+ STDCOPY((int8_t *)gbce_.r_gamma_lut, (int8_t *)gbce->r_gamma_lut,
+ gbce->gamma_lut_size * sizeof(float));
+ STDCOPY((int8_t *)gbce_.b_gamma_lut, (int8_t *)gbce->b_gamma_lut,
+ gbce->gamma_lut_size * sizeof(float));
+ STDCOPY((int8_t *)gbce_.g_gamma_lut, (int8_t *)gbce->g_gamma_lut,
+ gbce->gamma_lut_size * sizeof(float));
+ } else {
+ LOG(AIQResults, Error) << "Not copying Gamma LUT channels";
+ }
+
+ if (gbce->tone_map_lut_size > 0) {
+ gbce_.tone_map_lut_size = gbce->tone_map_lut_size;
+ STDCOPY((int8_t *)gbce_.tone_map_lut, (int8_t *)gbce->tone_map_lut,
+ gbce->tone_map_lut_size * sizeof(float));
+ } else {
+ LOG(AIQResults, Error) << "Not copying Tone Mapping Gain LUT";
+ }
+}
+
+void AiqResults::setDetectedSceneMode(ia_aiq_scene_mode dsm)
+{
+ detectedSceneMode_ = dsm;
+}
+
+void AiqResults::setPa(ia_aiq_pa_results *pa)
+{
+ ASSERT(pa);
+
+ STDCOPY(&pa_.color_conversion_matrix[0][0], &pa->color_conversion_matrix[0][0],
+ MAX_COLOR_CONVERSION_MATRIX * MAX_COLOR_CONVERSION_MATRIX *
+ sizeof(pa->color_conversion_matrix[0][0]));
+
+ if (pa_.preferred_acm && pa->preferred_acm) {
+ pa_.preferred_acm->sector_count = pa->preferred_acm->sector_count;
+
+ STDCOPY(pa_.preferred_acm->hue_of_sectors,
+ pa->preferred_acm->hue_of_sectors,
+ sizeof(*pa->preferred_acm->hue_of_sectors) * pa->preferred_acm->sector_count);
+
+ STDCOPY(pa_.preferred_acm->advanced_color_conversion_matrices[0][0],
+ pa->preferred_acm->advanced_color_conversion_matrices[0][0],
+ sizeof(*pa->preferred_acm->advanced_color_conversion_matrices) * pa->preferred_acm->sector_count);
+ } else {
+ LOG(AIQResults, Error) << "Not copying PA hue of sectors";
+ }
+
+ if (pa_.ir_weight && pa->ir_weight) {
+ pa_.ir_weight->height = pa->ir_weight->height;
+ pa_.ir_weight->width = pa->ir_weight->width;
+
+ STDCOPY(pa_.ir_weight->ir_weight_grid_R,
+ pa->ir_weight->ir_weight_grid_R,
+ sizeof(*pa->ir_weight->ir_weight_grid_R) * pa->ir_weight->height * pa->ir_weight->width);
+
+ STDCOPY(pa_.ir_weight->ir_weight_grid_G,
+ pa->ir_weight->ir_weight_grid_G,
+ sizeof(*pa->ir_weight->ir_weight_grid_G) * pa->ir_weight->height * pa->ir_weight->width);
+
+ STDCOPY(pa_.ir_weight->ir_weight_grid_B,
+ pa->ir_weight->ir_weight_grid_B,
+ sizeof(*pa->ir_weight->ir_weight_grid_B) * pa->ir_weight->height * pa->ir_weight->width);
+ } else {
+ LOG(AIQResults, Error) << "Not copying IR weight";
+ }
+
+ pa_.black_level = pa->black_level;
+ pa_.color_gains = pa->color_gains;
+ pa_.linearization = pa->linearization;
+ pa_.saturation_factor = pa->saturation_factor;
+ pa_.brightness_level = pa->brightness_level;
+}
+
+void AiqResults::setSa(ia_aiq_sa_results *sa)
+{
+ ASSERT(sa && sa->channel_r && sa->channel_gr &&
+ sa->channel_gb && sa->channel_b);
+
+ sa_.width = sa->width;
+ sa_.height = sa->height;
+ sa_.lsc_update = sa->lsc_update;
+
+ /* Check against one of the vectors but resize applicable to all. */
+ if (channelGr_.size() < (sa_.width * sa_.height)) {
+ int lscNewSize = sa_.width * sa_.height;
+ channelGr_.resize(lscNewSize);
+ channelGb_.resize(lscNewSize);
+ channelR_.resize(lscNewSize);
+ channelB_.resize(lscNewSize);
+
+ /* Update the SA data pointers to new memory locations. */
+ sa_.channel_gr = channelGr_.data();
+ sa_.channel_gb = channelGb_.data();
+ sa_.channel_r = channelR_.data();
+ sa_.channel_b = channelB_.data();
+ }
+
+ if (sa->lsc_update) {
+ uint32_t memCopySize = sa->width * sa->height * sizeof(float);
+
+ STDCOPY((int8_t *)sa_.channel_gr, (int8_t *)sa->channel_gb,
+ memCopySize);
+ STDCOPY((int8_t *)sa_.channel_gb, (int8_t *)sa->channel_gr,
+ memCopySize);
+ STDCOPY((int8_t *)sa_.channel_r, (int8_t *)sa->channel_r,
+ memCopySize);
+ STDCOPY((int8_t *)sa_.channel_b, (int8_t *)sa->channel_b,
+ memCopySize);
+ } else {
+ LOG(AIQResults, Error) << "Not copying LSC tables.";
+ }
+
+ STDCOPY(&sa_.light_source[0],
+ &sa->light_source[0],
+ CMC_NUM_LIGHTSOURCES * sizeof(sa->light_source[0]));
+ sa_.scene_difficulty = sa->scene_difficulty;
+ sa_.num_patches = sa->num_patches;
+ sa_.covered_area = sa->covered_area;
+ sa_.frame_params = sa->frame_params;
+}
+
+} /* namespace ipa::ipu3::aiq */
+
+} /* namespace libcamera */
diff --git a/aiq/aiq_results.h b/aiq/aiq_results.h
new file mode 100644
index 0000000..ae19a6c
--- /dev/null
+++ b/aiq/aiq_results.h
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+/*
+ * Copyright (C) 2021, Google Inc.
+ *
+ * aiq_results.h - Intel IA Imaging library C++ wrapper
+ *
+ * AIQ results container, capable of depth copies and assignments
+ * of the aiq result structures.
+ */
+
+#include <vector>
+
+#include <ia_imaging/ia_aiq.h>
+
+#ifndef IPA_IPU3_AIQ_RESULTS_H
+#define IPA_IPU3_AIQ_RESULTS_H
+
+namespace libcamera::ipa::ipu3::aiq {
+
+static const unsigned int NUM_FLASH_LEDS = 1; /*!> Number of leds AEC algorithm
+ provides output for */
+
+/**
+ * The result structures for 3A algorithm are full of pointers to other structs,
+ * some of those depends on the RGBS grid size or LSC grid size
+ * We should query those at init time and initialize the struct with the correct
+ * amount of memory. This is a TODO as an optimization
+ * for now we just allocate statically big values.
+ */
+static const unsigned int MAX_AE_GRID_SIZE = 2048; /*!> Top limit for the RGBS grid size
+ This is an upper limit to avoid dynamic allocation*/
+static const unsigned int DEFAULT_LSC_SIZE = 2048;
+static const unsigned int MAX_GAMMA_LUT_SIZE = 1024;
+static const unsigned int MAX_NUM_TONE_MAP_LUTS = 1024;
+
+class AiqResults
+{
+public:
+ AiqResults();
+
+ const ia_aiq_ae_results *ae() { return &ae_; }
+ ia_aiq_af_results *af() { return &af_; }
+ const ia_aiq_af_bracket_results *afBracket() { return &afBracket_; }
+ ia_aiq_awb_results *awb() { return &awb_; }
+ const ia_aiq_gbce_results *gbce() { return &gbce_; }
+ const ia_aiq_pa_results *pa() { return &pa_; }
+ const ia_aiq_sa_results *sa() { return &sa_; }
+
+ void setAe(ia_aiq_ae_results *ae);
+ void setAf(ia_aiq_af_results *af);
+ void setAfBracket(ia_aiq_af_bracket_results *afBracket);
+ void setAwb(ia_aiq_awb_results *awb);
+ void setGbce(ia_aiq_gbce_results *gbce);
+ void setDetectedSceneMode(ia_aiq_scene_mode dsm);
+ void setPa(ia_aiq_pa_results *pa);
+ void setSa(ia_aiq_sa_results *sa);
+
+private:
+ ia_aiq_ae_results ae_;
+ ia_aiq_af_results af_;
+ ia_aiq_af_bracket_results afBracket_;
+ ia_aiq_awb_results awb_;
+ ia_aiq_gbce_results gbce_;
+ ia_aiq_pa_results pa_;
+ ia_aiq_sa_results sa_;
+
+ ia_aiq_scene_mode detectedSceneMode_;
+
+ /*!< ia_aiq_ae_results pointer contents */
+ ia_aiq_ae_exposure_result aeExposureResult_;
+ ia_aiq_hist_weight_grid aeWeightGrid_;
+ unsigned char aeWeights_[MAX_AE_GRID_SIZE];
+ ia_aiq_flash_parameters aeFlashes_[NUM_FLASH_LEDS];
+
+ /*!< ia_aiq_ae_exposure_result pointer contents */
+ ia_aiq_exposure_parameters aeExposureParameters_;
+ ia_aiq_exposure_sensor_parameters aeSensorParaemeters_;
+
+ /*!< ia_aiq_gbce results */
+ /* The actual size of this table can be calculated by running cold
+ * GBCE, it will provide those tables. TODO!!
+ */
+ float RGammaLut_[MAX_GAMMA_LUT_SIZE];
+ float GGammaLut_[MAX_GAMMA_LUT_SIZE];
+ float BGammaLut_[MAX_GAMMA_LUT_SIZE];
+ float toneMapLut_[MAX_NUM_TONE_MAP_LUTS];
+
+ /*!< ia_aiq_af_bracket_results pointer contents */
+ unsigned short distanceBracketing_;
+ int lensPosBracketing_;
+
+ /*!< ia_aiq_pa_results */
+ ia_aiq_advanced_ccm_t prefAcm_;
+ ia_aiq_ir_weight_t irWeight_;
+
+ /*!< ia_aiq_advanced_ccm_t pointer contents */
+ unsigned int hueOfSectors_;
+ float advancedColorConversionMatrices_[3][3];
+
+ /*!< ia_aiq_ir_weight_t pointer contents */
+ unsigned short irWeightGridR_;
+ unsigned short irWeightGridG_;
+ unsigned short irWeightGridB_;
+
+ /*!< ia_aiq_sa_results pointer contents */
+ std::vector<float> channelGr_;
+ std::vector<float> channelR_;
+ std::vector<float> channelB_;
+ std::vector<float> channelGb_;
+};
+
+} /* namespace libcamera::ipa::ipu3::aiq */
+
+#endif /* IPA_IPU3_AIQ_RESULTS_H */
+
diff --git a/aiq/meson.build b/aiq/meson.build
new file mode 100644
index 0000000..b65fd46
--- /dev/null
+++ b/aiq/meson.build
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: CC0-1.0
+
+ipu3_ipa_files += files([
+ 'aiq_results.cpp',
+])
diff --git a/meson.build b/meson.build
index 5be3a94..ae51789 100644
--- a/meson.build
+++ b/meson.build
@@ -92,6 +92,7 @@ ipu3_ipa_deps = [
ia_imaging_dep,
]
+subdir('aiq')
subdir('data')
subdir('src')