summaryrefslogtreecommitdiff
path: root/gpr/source/lib/vc5_common/companding.c
diff options
context:
space:
mode:
Diffstat (limited to 'gpr/source/lib/vc5_common/companding.c')
-rwxr-xr-xgpr/source/lib/vc5_common/companding.c259
1 files changed, 259 insertions, 0 deletions
diff --git a/gpr/source/lib/vc5_common/companding.c b/gpr/source/lib/vc5_common/companding.c
new file mode 100755
index 0000000..00b0fb5
--- /dev/null
+++ b/gpr/source/lib/vc5_common/companding.c
@@ -0,0 +1,259 @@
+/*! @file companding.c
+ *
+ * @brief Implementation of the routines for computing the companding curves
+ * that is applied to the quantized coefficient magnitudes.
+ *
+ * @version 1.0.0
+ *
+ * (C) Copyright 2018 GoPro Inc (http://gopro.com/).
+ *
+ * Licensed under either:
+ * - Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0
+ * - MIT license, http://opensource.org/licenses/MIT
+ * at your option.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common.h"
+
+//TODO: Change the companding parameter into a global constant
+
+#ifndef COMPANDING
+#define COMPANDING 1
+#define COMPANDING_MORE (54) // Zero means no companding (54 is a good value)
+#endif
+
+
+/*!
+ @brief Maximum coefficient magnitude in the codebook
+
+ @todo Need to calculate the maximum value from the codebook
+*/
+const int maximum_codebook_value = 255;
+
+
+/*!
+ @brief Apply the default companding curve to the specified value
+
+ Note that this companding curve has been superceeded by the cubic curve.
+*/
+int32_t CompandedValue(int32_t value)
+{
+ const int midpoint_rounding = 2;
+
+ int32_t magnitude = absolute(value);
+
+#if COMPANDING
+ if (magnitude >= 40)
+ {
+ magnitude -= 40;
+ magnitude += midpoint_rounding;
+ magnitude >>= 2;
+ magnitude += 40;
+
+ #if COMPANDING_MORE
+ if (magnitude >= COMPANDING_MORE)
+ {
+ magnitude -= COMPANDING_MORE;
+ magnitude += midpoint_rounding;
+ magnitude >>= 2;
+ magnitude += COMPANDING_MORE;
+ }
+#endif
+ }
+#endif
+
+ // Restore the sign to the companded value
+ return ((value >= 0) ? magnitude : neg(magnitude));
+}
+
+/*!
+ @brief Return the parameter that controls the companding curve
+
+ This parameter does not apply if the cubic companding curve is used.
+*/
+uint32_t CompandingParameter()
+{
+ return COMPANDING_MORE;
+}
+
+/*!
+ @brief Compute a table of values for the cubic companding curve
+
+ The companding curve is f(x) = x + (x ^ 3 / (255 ^ 3)) * 768
+ so the range of coefficient magnitudes from 0 to 255 becomess 0 to 1023.
+*/
+CODEC_ERROR ComputeCubicTable(int16_t cubic_table[], int cubic_table_length, int16_t maximum_value)
+{
+ size_t cubic_table_size = cubic_table_length * sizeof(cubic_table[0]);
+ int last_cubic_table_index = cubic_table_length - 2;
+ int16_t last_magnitude;
+ int16_t index;
+
+ // Clear the cubic table
+ memset(cubic_table, 0, cubic_table_size);
+
+ for (index = 1; index <= maximum_value; index++)
+ {
+ double cubic = index;
+
+ int magnitude = index;
+
+ cubic *= index;
+ cubic *= index;
+ cubic *= 768;
+ //cubic /= 256*256*256;
+ cubic /= 255*255*255;
+
+ magnitude += (int)cubic;
+
+ //if (mag > 1023) mag = 1023;
+ if (magnitude > last_cubic_table_index) {
+ magnitude = last_cubic_table_index;
+ }
+
+ cubic_table[magnitude] = index;
+ }
+
+ // Fill unused entries in the cubic table
+ last_magnitude = 0;
+ for (index = 0; index < cubic_table_length; index++)
+ {
+ if (cubic_table[index])
+ {
+ last_magnitude = cubic_table[index];
+ }
+ else
+ {
+ cubic_table[index] = last_magnitude;
+ }
+ }
+
+ return CODEC_ERROR_OKAY;
+}
+
+/*!
+ @brief Invert the companding curve applied during encoding
+*/
+int32_t UncompandedValue(int32_t value)
+{
+#if 1 //CUBIC_COMPANDING
+ double cubic;
+ int32_t magnitude = absolute(value);
+
+ cubic = magnitude;
+ cubic *= magnitude;
+ cubic *= magnitude;
+ cubic *= 768;
+ //cubic /= 256*256*256;
+ cubic /= 255*255*255;
+
+ magnitude += (int32_t)cubic;
+
+ // Restore the sign
+ value = ((value < 0) ? neg(magnitude) : magnitude);
+#else
+ if (40 <= value && value < 264)
+ {
+#if COMPANDING_MORE
+ if (value >= COMPANDING_MORE)
+ {
+ value -= COMPANDING_MORE;
+ value <<= 2;
+ value += COMPANDING_MORE;
+ }
+#endif
+ value -= 40;
+ value <<= 2;
+ value += 40;
+ }
+ else if (value <= -40)
+ {
+ // Apply the inverse companding formula to the absolute value
+ value = -value;
+
+#if COMPANDING_MORE
+ if (value >= COMPANDING_MORE)
+ {
+ value -= COMPANDING_MORE;
+ value <<= 2;
+ value += COMPANDING_MORE;
+ }
+#endif
+ value -= 40;
+ value <<= 2;
+ value += 40;
+
+ // Restore the sign
+ value = -value;
+ }
+#endif
+
+ return value;
+}
+
+/*!
+ @brief Invert the companding curve applied to a pixel
+*/
+PIXEL UncompandedPixel(PIXEL value)
+{
+#if 1 //CUBIC_COMPANDING
+ double cubic;
+ int32_t magnitude = absolute(value);
+
+ cubic = magnitude;
+ cubic *= magnitude;
+ cubic *= magnitude;
+ cubic *= 768;
+ //cubic /= 256*256*256;
+ cubic /= 255*255*255;
+
+ magnitude += (int32_t)cubic;
+
+ // Restore the sign
+ value = ClampPixel((value < 0) ? neg(magnitude) : magnitude);
+#else
+ if (40 <= value && value < 264)
+ {
+#if COMPANDING_MORE
+ if (value >= COMPANDING_MORE)
+ {
+ value -= COMPANDING_MORE;
+ value <<= 2;
+ value += COMPANDING_MORE;
+ }
+#endif
+ value -= 40;
+ value <<= 2;
+ value += 40;
+ }
+ else if (value <= -40)
+ {
+ // Apply the inverse companding formula to the absolute value
+ value = neg(value);
+
+#if COMPANDING_MORE
+ if (value >= COMPANDING_MORE)
+ {
+ value -= COMPANDING_MORE;
+ value <<= 2;
+ value += COMPANDING_MORE;
+ }
+#endif
+ value -= 40;
+ value <<= 2;
+ value += 40;
+
+ // Restore the sign
+ value = neg(value);
+ }
+#endif
+
+ return value;
+}
+