|
@@ -0,0 +1,797 @@
|
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
|
+/*
|
|
|
+ * Copyright 2016 Tom aan de Wiel
|
|
|
+ * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
|
|
+ *
|
|
|
+ * 8x8 Fast Walsh Hadamard Transform in sequency order based on the paper:
|
|
|
+ *
|
|
|
+ * A Recursive Algorithm for Sequency-Ordered Fast Walsh Transforms,
|
|
|
+ * R.D. Brown, 1977
|
|
|
+ */
|
|
|
+
|
|
|
+#include <linux/string.h>
|
|
|
+#include "vicodec-codec.h"
|
|
|
+
|
|
|
+#define ALL_ZEROS 15
|
|
|
+#define DEADZONE_WIDTH 20
|
|
|
+
|
|
|
+static const uint8_t zigzag[64] = {
|
|
|
+ 0,
|
|
|
+ 1, 8,
|
|
|
+ 2, 9, 16,
|
|
|
+ 3, 10, 17, 24,
|
|
|
+ 4, 11, 18, 25, 32,
|
|
|
+ 5, 12, 19, 26, 33, 40,
|
|
|
+ 6, 13, 20, 27, 34, 41, 48,
|
|
|
+ 7, 14, 21, 28, 35, 42, 49, 56,
|
|
|
+ 15, 22, 29, 36, 43, 50, 57,
|
|
|
+ 23, 30, 37, 44, 51, 58,
|
|
|
+ 31, 38, 45, 52, 59,
|
|
|
+ 39, 46, 53, 60,
|
|
|
+ 47, 54, 61,
|
|
|
+ 55, 62,
|
|
|
+ 63,
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+static int rlc(const s16 *in, __be16 *output, int blocktype)
|
|
|
+{
|
|
|
+ s16 block[8 * 8];
|
|
|
+ s16 *wp = block;
|
|
|
+ int i = 0;
|
|
|
+ int x, y;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ /* read in block from framebuffer */
|
|
|
+ int lastzero_run = 0;
|
|
|
+ int to_encode;
|
|
|
+
|
|
|
+ for (y = 0; y < 8; y++) {
|
|
|
+ for (x = 0; x < 8; x++) {
|
|
|
+ *wp = in[x + y * 8];
|
|
|
+ wp++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* keep track of amount of trailing zeros */
|
|
|
+ for (i = 63; i >= 0 && !block[zigzag[i]]; i--)
|
|
|
+ lastzero_run++;
|
|
|
+
|
|
|
+ *output++ = (blocktype == PBLOCK ? htons(PFRAME_BIT) : 0);
|
|
|
+ ret++;
|
|
|
+
|
|
|
+ to_encode = 8 * 8 - (lastzero_run > 14 ? lastzero_run : 0);
|
|
|
+
|
|
|
+ i = 0;
|
|
|
+ while (i < to_encode) {
|
|
|
+ int cnt = 0;
|
|
|
+ int tmp;
|
|
|
+
|
|
|
+ /* count leading zeros */
|
|
|
+ while ((tmp = block[zigzag[i]]) == 0 && cnt < 14) {
|
|
|
+ cnt++;
|
|
|
+ i++;
|
|
|
+ if (i == to_encode) {
|
|
|
+ cnt--;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* 4 bits for run, 12 for coefficient (quantization by 4) */
|
|
|
+ *output++ = htons((cnt | tmp << 4));
|
|
|
+ i++;
|
|
|
+ ret++;
|
|
|
+ }
|
|
|
+ if (lastzero_run > 14) {
|
|
|
+ *output = htons(ALL_ZEROS | 0);
|
|
|
+ ret++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * This function will worst-case increase rlc_in by 65*2 bytes:
|
|
|
+ * one s16 value for the header and 8 * 8 coefficients of type s16.
|
|
|
+ */
|
|
|
+static s16 derlc(const __be16 **rlc_in, s16 *dwht_out)
|
|
|
+{
|
|
|
+ /* header */
|
|
|
+ const __be16 *input = *rlc_in;
|
|
|
+ s16 ret = ntohs(*input++);
|
|
|
+ int dec_count = 0;
|
|
|
+ s16 block[8 * 8 + 16];
|
|
|
+ s16 *wp = block;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Now de-compress, it expands one byte to up to 15 bytes
|
|
|
+ * (or fills the remainder of the 64 bytes with zeroes if it
|
|
|
+ * is the last byte to expand).
|
|
|
+ *
|
|
|
+ * So block has to be 8 * 8 + 16 bytes, the '+ 16' is to
|
|
|
+ * allow for overflow if the incoming data was malformed.
|
|
|
+ */
|
|
|
+ while (dec_count < 8 * 8) {
|
|
|
+ s16 in = ntohs(*input++);
|
|
|
+ int length = in & 0xf;
|
|
|
+ int coeff = in >> 4;
|
|
|
+
|
|
|
+ /* fill remainder with zeros */
|
|
|
+ if (length == 15) {
|
|
|
+ for (i = 0; i < 64 - dec_count; i++)
|
|
|
+ *wp++ = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < length; i++)
|
|
|
+ *wp++ = 0;
|
|
|
+ *wp++ = coeff;
|
|
|
+ dec_count += length + 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ wp = block;
|
|
|
+
|
|
|
+ for (i = 0; i < 64; i++) {
|
|
|
+ int pos = zigzag[i];
|
|
|
+ int y = pos / 8;
|
|
|
+ int x = pos % 8;
|
|
|
+
|
|
|
+ dwht_out[x + y * 8] = *wp++;
|
|
|
+ }
|
|
|
+ *rlc_in = input;
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static const int quant_table[] = {
|
|
|
+ 2, 2, 2, 2, 2, 2, 2, 2,
|
|
|
+ 2, 2, 2, 2, 2, 2, 2, 2,
|
|
|
+ 2, 2, 2, 2, 2, 2, 2, 3,
|
|
|
+ 2, 2, 2, 2, 2, 2, 3, 6,
|
|
|
+ 2, 2, 2, 2, 2, 3, 6, 6,
|
|
|
+ 2, 2, 2, 2, 3, 6, 6, 6,
|
|
|
+ 2, 2, 2, 3, 6, 6, 6, 6,
|
|
|
+ 2, 2, 3, 6, 6, 6, 6, 8,
|
|
|
+};
|
|
|
+
|
|
|
+static const int quant_table_p[] = {
|
|
|
+ 3, 3, 3, 3, 3, 3, 3, 3,
|
|
|
+ 3, 3, 3, 3, 3, 3, 3, 3,
|
|
|
+ 3, 3, 3, 3, 3, 3, 3, 3,
|
|
|
+ 3, 3, 3, 3, 3, 3, 3, 6,
|
|
|
+ 3, 3, 3, 3, 3, 3, 6, 6,
|
|
|
+ 3, 3, 3, 3, 3, 6, 6, 9,
|
|
|
+ 3, 3, 3, 3, 6, 6, 9, 9,
|
|
|
+ 3, 3, 3, 6, 6, 9, 9, 10,
|
|
|
+};
|
|
|
+
|
|
|
+static void quantize_intra(s16 *coeff, s16 *de_coeff)
|
|
|
+{
|
|
|
+ const int *quant = quant_table;
|
|
|
+ int i, j;
|
|
|
+
|
|
|
+ for (j = 0; j < 8; j++) {
|
|
|
+ for (i = 0; i < 8; i++, quant++, coeff++, de_coeff++) {
|
|
|
+ *coeff >>= *quant;
|
|
|
+ if (*coeff >= -DEADZONE_WIDTH &&
|
|
|
+ *coeff <= DEADZONE_WIDTH)
|
|
|
+ *coeff = *de_coeff = 0;
|
|
|
+ else
|
|
|
+ *de_coeff = *coeff << *quant;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void dequantize_intra(s16 *coeff)
|
|
|
+{
|
|
|
+ const int *quant = quant_table;
|
|
|
+ int i, j;
|
|
|
+
|
|
|
+ for (j = 0; j < 8; j++)
|
|
|
+ for (i = 0; i < 8; i++, quant++, coeff++)
|
|
|
+ *coeff <<= *quant;
|
|
|
+}
|
|
|
+
|
|
|
+static void quantize_inter(s16 *coeff, s16 *de_coeff)
|
|
|
+{
|
|
|
+ const int *quant = quant_table_p;
|
|
|
+ int i, j;
|
|
|
+
|
|
|
+ for (j = 0; j < 8; j++) {
|
|
|
+ for (i = 0; i < 8; i++, quant++, coeff++, de_coeff++) {
|
|
|
+ *coeff >>= *quant;
|
|
|
+ if (*coeff >= -DEADZONE_WIDTH &&
|
|
|
+ *coeff <= DEADZONE_WIDTH)
|
|
|
+ *coeff = *de_coeff = 0;
|
|
|
+ else
|
|
|
+ *de_coeff = *coeff << *quant;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void dequantize_inter(s16 *coeff)
|
|
|
+{
|
|
|
+ const int *quant = quant_table_p;
|
|
|
+ int i, j;
|
|
|
+
|
|
|
+ for (j = 0; j < 8; j++)
|
|
|
+ for (i = 0; i < 8; i++, quant++, coeff++)
|
|
|
+ *coeff <<= *quant;
|
|
|
+}
|
|
|
+
|
|
|
+static void fwht(const u8 *block, s16 *output_block, unsigned int stride,
|
|
|
+ unsigned int input_step, bool intra)
|
|
|
+{
|
|
|
+ /* we'll need more than 8 bits for the transformed coefficients */
|
|
|
+ s32 workspace1[8], workspace2[8];
|
|
|
+ const u8 *tmp = block;
|
|
|
+ s16 *out = output_block;
|
|
|
+ int add = intra ? 256 : 0;
|
|
|
+ unsigned int i;
|
|
|
+
|
|
|
+ /* stage 1 */
|
|
|
+ stride *= input_step;
|
|
|
+
|
|
|
+ for (i = 0; i < 8; i++, tmp += stride, out += 8) {
|
|
|
+ if (input_step == 1) {
|
|
|
+ workspace1[0] = tmp[0] + tmp[1] - add;
|
|
|
+ workspace1[1] = tmp[0] - tmp[1];
|
|
|
+
|
|
|
+ workspace1[2] = tmp[2] + tmp[3] - add;
|
|
|
+ workspace1[3] = tmp[2] - tmp[3];
|
|
|
+
|
|
|
+ workspace1[4] = tmp[4] + tmp[5] - add;
|
|
|
+ workspace1[5] = tmp[4] - tmp[5];
|
|
|
+
|
|
|
+ workspace1[6] = tmp[6] + tmp[7] - add;
|
|
|
+ workspace1[7] = tmp[6] - tmp[7];
|
|
|
+ } else {
|
|
|
+ workspace1[0] = tmp[0] + tmp[2] - add;
|
|
|
+ workspace1[1] = tmp[0] - tmp[2];
|
|
|
+
|
|
|
+ workspace1[2] = tmp[4] + tmp[6] - add;
|
|
|
+ workspace1[3] = tmp[4] - tmp[6];
|
|
|
+
|
|
|
+ workspace1[4] = tmp[8] + tmp[10] - add;
|
|
|
+ workspace1[5] = tmp[8] - tmp[10];
|
|
|
+
|
|
|
+ workspace1[6] = tmp[12] + tmp[14] - add;
|
|
|
+ workspace1[7] = tmp[12] - tmp[14];
|
|
|
+ }
|
|
|
+
|
|
|
+ /* stage 2 */
|
|
|
+ workspace2[0] = workspace1[0] + workspace1[2];
|
|
|
+ workspace2[1] = workspace1[0] - workspace1[2];
|
|
|
+ workspace2[2] = workspace1[1] - workspace1[3];
|
|
|
+ workspace2[3] = workspace1[1] + workspace1[3];
|
|
|
+
|
|
|
+ workspace2[4] = workspace1[4] + workspace1[6];
|
|
|
+ workspace2[5] = workspace1[4] - workspace1[6];
|
|
|
+ workspace2[6] = workspace1[5] - workspace1[7];
|
|
|
+ workspace2[7] = workspace1[5] + workspace1[7];
|
|
|
+
|
|
|
+ /* stage 3 */
|
|
|
+ out[0] = workspace2[0] + workspace2[4];
|
|
|
+ out[1] = workspace2[0] - workspace2[4];
|
|
|
+ out[2] = workspace2[1] - workspace2[5];
|
|
|
+ out[3] = workspace2[1] + workspace2[5];
|
|
|
+ out[4] = workspace2[2] + workspace2[6];
|
|
|
+ out[5] = workspace2[2] - workspace2[6];
|
|
|
+ out[6] = workspace2[3] - workspace2[7];
|
|
|
+ out[7] = workspace2[3] + workspace2[7];
|
|
|
+ }
|
|
|
+
|
|
|
+ out = output_block;
|
|
|
+
|
|
|
+ for (i = 0; i < 8; i++, out++) {
|
|
|
+ /* stage 1 */
|
|
|
+ workspace1[0] = out[0] + out[1 * 8];
|
|
|
+ workspace1[1] = out[0] - out[1 * 8];
|
|
|
+
|
|
|
+ workspace1[2] = out[2 * 8] + out[3 * 8];
|
|
|
+ workspace1[3] = out[2 * 8] - out[3 * 8];
|
|
|
+
|
|
|
+ workspace1[4] = out[4 * 8] + out[5 * 8];
|
|
|
+ workspace1[5] = out[4 * 8] - out[5 * 8];
|
|
|
+
|
|
|
+ workspace1[6] = out[6 * 8] + out[7 * 8];
|
|
|
+ workspace1[7] = out[6 * 8] - out[7 * 8];
|
|
|
+
|
|
|
+ /* stage 2 */
|
|
|
+ workspace2[0] = workspace1[0] + workspace1[2];
|
|
|
+ workspace2[1] = workspace1[0] - workspace1[2];
|
|
|
+ workspace2[2] = workspace1[1] - workspace1[3];
|
|
|
+ workspace2[3] = workspace1[1] + workspace1[3];
|
|
|
+
|
|
|
+ workspace2[4] = workspace1[4] + workspace1[6];
|
|
|
+ workspace2[5] = workspace1[4] - workspace1[6];
|
|
|
+ workspace2[6] = workspace1[5] - workspace1[7];
|
|
|
+ workspace2[7] = workspace1[5] + workspace1[7];
|
|
|
+ /* stage 3 */
|
|
|
+ out[0 * 8] = workspace2[0] + workspace2[4];
|
|
|
+ out[1 * 8] = workspace2[0] - workspace2[4];
|
|
|
+ out[2 * 8] = workspace2[1] - workspace2[5];
|
|
|
+ out[3 * 8] = workspace2[1] + workspace2[5];
|
|
|
+ out[4 * 8] = workspace2[2] + workspace2[6];
|
|
|
+ out[5 * 8] = workspace2[2] - workspace2[6];
|
|
|
+ out[6 * 8] = workspace2[3] - workspace2[7];
|
|
|
+ out[7 * 8] = workspace2[3] + workspace2[7];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Not the nicest way of doing it, but P-blocks get twice the range of
|
|
|
+ * that of the I-blocks. Therefore we need a type bigger than 8 bits.
|
|
|
+ * Furthermore values can be negative... This is just a version that
|
|
|
+ * works with 16 signed data
|
|
|
+ */
|
|
|
+static void fwht16(const s16 *block, s16 *output_block, int stride, int intra)
|
|
|
+{
|
|
|
+ /* we'll need more than 8 bits for the transformed coefficients */
|
|
|
+ s32 workspace1[8], workspace2[8];
|
|
|
+ const s16 *tmp = block;
|
|
|
+ s16 *out = output_block;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < 8; i++, tmp += stride, out += 8) {
|
|
|
+ /* stage 1 */
|
|
|
+ workspace1[0] = tmp[0] + tmp[1];
|
|
|
+ workspace1[1] = tmp[0] - tmp[1];
|
|
|
+
|
|
|
+ workspace1[2] = tmp[2] + tmp[3];
|
|
|
+ workspace1[3] = tmp[2] - tmp[3];
|
|
|
+
|
|
|
+ workspace1[4] = tmp[4] + tmp[5];
|
|
|
+ workspace1[5] = tmp[4] - tmp[5];
|
|
|
+
|
|
|
+ workspace1[6] = tmp[6] + tmp[7];
|
|
|
+ workspace1[7] = tmp[6] - tmp[7];
|
|
|
+
|
|
|
+ /* stage 2 */
|
|
|
+ workspace2[0] = workspace1[0] + workspace1[2];
|
|
|
+ workspace2[1] = workspace1[0] - workspace1[2];
|
|
|
+ workspace2[2] = workspace1[1] - workspace1[3];
|
|
|
+ workspace2[3] = workspace1[1] + workspace1[3];
|
|
|
+
|
|
|
+ workspace2[4] = workspace1[4] + workspace1[6];
|
|
|
+ workspace2[5] = workspace1[4] - workspace1[6];
|
|
|
+ workspace2[6] = workspace1[5] - workspace1[7];
|
|
|
+ workspace2[7] = workspace1[5] + workspace1[7];
|
|
|
+
|
|
|
+ /* stage 3 */
|
|
|
+ out[0] = workspace2[0] + workspace2[4];
|
|
|
+ out[1] = workspace2[0] - workspace2[4];
|
|
|
+ out[2] = workspace2[1] - workspace2[5];
|
|
|
+ out[3] = workspace2[1] + workspace2[5];
|
|
|
+ out[4] = workspace2[2] + workspace2[6];
|
|
|
+ out[5] = workspace2[2] - workspace2[6];
|
|
|
+ out[6] = workspace2[3] - workspace2[7];
|
|
|
+ out[7] = workspace2[3] + workspace2[7];
|
|
|
+ }
|
|
|
+
|
|
|
+ out = output_block;
|
|
|
+
|
|
|
+ for (i = 0; i < 8; i++, out++) {
|
|
|
+ /* stage 1 */
|
|
|
+ workspace1[0] = out[0] + out[1*8];
|
|
|
+ workspace1[1] = out[0] - out[1*8];
|
|
|
+
|
|
|
+ workspace1[2] = out[2*8] + out[3*8];
|
|
|
+ workspace1[3] = out[2*8] - out[3*8];
|
|
|
+
|
|
|
+ workspace1[4] = out[4*8] + out[5*8];
|
|
|
+ workspace1[5] = out[4*8] - out[5*8];
|
|
|
+
|
|
|
+ workspace1[6] = out[6*8] + out[7*8];
|
|
|
+ workspace1[7] = out[6*8] - out[7*8];
|
|
|
+
|
|
|
+ /* stage 2 */
|
|
|
+ workspace2[0] = workspace1[0] + workspace1[2];
|
|
|
+ workspace2[1] = workspace1[0] - workspace1[2];
|
|
|
+ workspace2[2] = workspace1[1] - workspace1[3];
|
|
|
+ workspace2[3] = workspace1[1] + workspace1[3];
|
|
|
+
|
|
|
+ workspace2[4] = workspace1[4] + workspace1[6];
|
|
|
+ workspace2[5] = workspace1[4] - workspace1[6];
|
|
|
+ workspace2[6] = workspace1[5] - workspace1[7];
|
|
|
+ workspace2[7] = workspace1[5] + workspace1[7];
|
|
|
+
|
|
|
+ /* stage 3 */
|
|
|
+ out[0*8] = workspace2[0] + workspace2[4];
|
|
|
+ out[1*8] = workspace2[0] - workspace2[4];
|
|
|
+ out[2*8] = workspace2[1] - workspace2[5];
|
|
|
+ out[3*8] = workspace2[1] + workspace2[5];
|
|
|
+ out[4*8] = workspace2[2] + workspace2[6];
|
|
|
+ out[5*8] = workspace2[2] - workspace2[6];
|
|
|
+ out[6*8] = workspace2[3] - workspace2[7];
|
|
|
+ out[7*8] = workspace2[3] + workspace2[7];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void ifwht(const s16 *block, s16 *output_block, int intra)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * we'll need more than 8 bits for the transformed coefficients
|
|
|
+ * use native unit of cpu
|
|
|
+ */
|
|
|
+ int workspace1[8], workspace2[8];
|
|
|
+ int inter = intra ? 0 : 1;
|
|
|
+ const s16 *tmp = block;
|
|
|
+ s16 *out = output_block;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < 8; i++, tmp += 8, out += 8) {
|
|
|
+ /* stage 1 */
|
|
|
+ workspace1[0] = tmp[0] + tmp[1];
|
|
|
+ workspace1[1] = tmp[0] - tmp[1];
|
|
|
+
|
|
|
+ workspace1[2] = tmp[2] + tmp[3];
|
|
|
+ workspace1[3] = tmp[2] - tmp[3];
|
|
|
+
|
|
|
+ workspace1[4] = tmp[4] + tmp[5];
|
|
|
+ workspace1[5] = tmp[4] - tmp[5];
|
|
|
+
|
|
|
+ workspace1[6] = tmp[6] + tmp[7];
|
|
|
+ workspace1[7] = tmp[6] - tmp[7];
|
|
|
+
|
|
|
+ /* stage 2 */
|
|
|
+ workspace2[0] = workspace1[0] + workspace1[2];
|
|
|
+ workspace2[1] = workspace1[0] - workspace1[2];
|
|
|
+ workspace2[2] = workspace1[1] - workspace1[3];
|
|
|
+ workspace2[3] = workspace1[1] + workspace1[3];
|
|
|
+
|
|
|
+ workspace2[4] = workspace1[4] + workspace1[6];
|
|
|
+ workspace2[5] = workspace1[4] - workspace1[6];
|
|
|
+ workspace2[6] = workspace1[5] - workspace1[7];
|
|
|
+ workspace2[7] = workspace1[5] + workspace1[7];
|
|
|
+
|
|
|
+ /* stage 3 */
|
|
|
+ out[0] = workspace2[0] + workspace2[4];
|
|
|
+ out[1] = workspace2[0] - workspace2[4];
|
|
|
+ out[2] = workspace2[1] - workspace2[5];
|
|
|
+ out[3] = workspace2[1] + workspace2[5];
|
|
|
+ out[4] = workspace2[2] + workspace2[6];
|
|
|
+ out[5] = workspace2[2] - workspace2[6];
|
|
|
+ out[6] = workspace2[3] - workspace2[7];
|
|
|
+ out[7] = workspace2[3] + workspace2[7];
|
|
|
+ }
|
|
|
+
|
|
|
+ out = output_block;
|
|
|
+
|
|
|
+ for (i = 0; i < 8; i++, out++) {
|
|
|
+ /* stage 1 */
|
|
|
+ workspace1[0] = out[0] + out[1 * 8];
|
|
|
+ workspace1[1] = out[0] - out[1 * 8];
|
|
|
+
|
|
|
+ workspace1[2] = out[2 * 8] + out[3 * 8];
|
|
|
+ workspace1[3] = out[2 * 8] - out[3 * 8];
|
|
|
+
|
|
|
+ workspace1[4] = out[4 * 8] + out[5 * 8];
|
|
|
+ workspace1[5] = out[4 * 8] - out[5 * 8];
|
|
|
+
|
|
|
+ workspace1[6] = out[6 * 8] + out[7 * 8];
|
|
|
+ workspace1[7] = out[6 * 8] - out[7 * 8];
|
|
|
+
|
|
|
+ /* stage 2 */
|
|
|
+ workspace2[0] = workspace1[0] + workspace1[2];
|
|
|
+ workspace2[1] = workspace1[0] - workspace1[2];
|
|
|
+ workspace2[2] = workspace1[1] - workspace1[3];
|
|
|
+ workspace2[3] = workspace1[1] + workspace1[3];
|
|
|
+
|
|
|
+ workspace2[4] = workspace1[4] + workspace1[6];
|
|
|
+ workspace2[5] = workspace1[4] - workspace1[6];
|
|
|
+ workspace2[6] = workspace1[5] - workspace1[7];
|
|
|
+ workspace2[7] = workspace1[5] + workspace1[7];
|
|
|
+
|
|
|
+ /* stage 3 */
|
|
|
+ if (inter) {
|
|
|
+ int d;
|
|
|
+
|
|
|
+ out[0 * 8] = workspace2[0] + workspace2[4];
|
|
|
+ out[1 * 8] = workspace2[0] - workspace2[4];
|
|
|
+ out[2 * 8] = workspace2[1] - workspace2[5];
|
|
|
+ out[3 * 8] = workspace2[1] + workspace2[5];
|
|
|
+ out[4 * 8] = workspace2[2] + workspace2[6];
|
|
|
+ out[5 * 8] = workspace2[2] - workspace2[6];
|
|
|
+ out[6 * 8] = workspace2[3] - workspace2[7];
|
|
|
+ out[7 * 8] = workspace2[3] + workspace2[7];
|
|
|
+
|
|
|
+ for (d = 0; d < 8; d++)
|
|
|
+ out[8 * d] >>= 6;
|
|
|
+ } else {
|
|
|
+ int d;
|
|
|
+
|
|
|
+ out[0 * 8] = workspace2[0] + workspace2[4];
|
|
|
+ out[1 * 8] = workspace2[0] - workspace2[4];
|
|
|
+ out[2 * 8] = workspace2[1] - workspace2[5];
|
|
|
+ out[3 * 8] = workspace2[1] + workspace2[5];
|
|
|
+ out[4 * 8] = workspace2[2] + workspace2[6];
|
|
|
+ out[5 * 8] = workspace2[2] - workspace2[6];
|
|
|
+ out[6 * 8] = workspace2[3] - workspace2[7];
|
|
|
+ out[7 * 8] = workspace2[3] + workspace2[7];
|
|
|
+
|
|
|
+ for (d = 0; d < 8; d++) {
|
|
|
+ out[8 * d] >>= 6;
|
|
|
+ out[8 * d] += 128;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void fill_encoder_block(const u8 *input, s16 *dst,
|
|
|
+ unsigned int stride, unsigned int input_step)
|
|
|
+{
|
|
|
+ int i, j;
|
|
|
+
|
|
|
+ for (i = 0; i < 8; i++) {
|
|
|
+ for (j = 0; j < 8; j++, input += input_step)
|
|
|
+ *dst++ = *input;
|
|
|
+ input += (stride - 8) * input_step;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int var_intra(const s16 *input)
|
|
|
+{
|
|
|
+ int32_t mean = 0;
|
|
|
+ int32_t ret = 0;
|
|
|
+ const s16 *tmp = input;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < 8 * 8; i++, tmp++)
|
|
|
+ mean += *tmp;
|
|
|
+ mean /= 64;
|
|
|
+ tmp = input;
|
|
|
+ for (i = 0; i < 8 * 8; i++, tmp++)
|
|
|
+ ret += (*tmp - mean) < 0 ? -(*tmp - mean) : (*tmp - mean);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int var_inter(const s16 *old, const s16 *new)
|
|
|
+{
|
|
|
+ int32_t ret = 0;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < 8 * 8; i++, old++, new++)
|
|
|
+ ret += (*old - *new) < 0 ? -(*old - *new) : (*old - *new);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int decide_blocktype(const u8 *current, const u8 *reference,
|
|
|
+ s16 *deltablock, unsigned int stride,
|
|
|
+ unsigned int input_step)
|
|
|
+{
|
|
|
+ s16 tmp[64];
|
|
|
+ s16 old[64];
|
|
|
+ s16 *work = tmp;
|
|
|
+ unsigned int k, l;
|
|
|
+ int vari;
|
|
|
+ int vard;
|
|
|
+
|
|
|
+ fill_encoder_block(current, tmp, stride, input_step);
|
|
|
+ fill_encoder_block(reference, old, 8, 1);
|
|
|
+ vari = var_intra(tmp);
|
|
|
+
|
|
|
+ for (k = 0; k < 8; k++) {
|
|
|
+ for (l = 0; l < 8; l++) {
|
|
|
+ *deltablock = *work - *reference;
|
|
|
+ deltablock++;
|
|
|
+ work++;
|
|
|
+ reference++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ deltablock -= 64;
|
|
|
+ vard = var_inter(old, tmp);
|
|
|
+ return vari <= vard ? IBLOCK : PBLOCK;
|
|
|
+}
|
|
|
+
|
|
|
+static void fill_decoder_block(u8 *dst, const s16 *input, int stride)
|
|
|
+{
|
|
|
+ int i, j;
|
|
|
+
|
|
|
+ for (i = 0; i < 8; i++) {
|
|
|
+ for (j = 0; j < 8; j++)
|
|
|
+ *dst++ = *input++;
|
|
|
+ dst += stride - 8;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void add_deltas(s16 *deltas, const u8 *ref, int stride)
|
|
|
+{
|
|
|
+ int k, l;
|
|
|
+
|
|
|
+ for (k = 0; k < 8; k++) {
|
|
|
+ for (l = 0; l < 8; l++) {
|
|
|
+ *deltas += *ref++;
|
|
|
+ /*
|
|
|
+ * Due to quantizing, it might possible that the
|
|
|
+ * decoded coefficients are slightly out of range
|
|
|
+ */
|
|
|
+ if (*deltas < 0)
|
|
|
+ *deltas = 0;
|
|
|
+ else if (*deltas > 255)
|
|
|
+ *deltas = 255;
|
|
|
+ deltas++;
|
|
|
+ }
|
|
|
+ ref += stride - 8;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max,
|
|
|
+ struct cframe *cf, u32 height, u32 width,
|
|
|
+ unsigned int input_step,
|
|
|
+ bool is_intra, bool next_is_intra)
|
|
|
+{
|
|
|
+ u8 *input_start = input;
|
|
|
+ __be16 *rlco_start = *rlco;
|
|
|
+ s16 deltablock[64];
|
|
|
+ __be16 pframe_bit = htons(PFRAME_BIT);
|
|
|
+ u32 encoding = 0;
|
|
|
+ unsigned int last_size = 0;
|
|
|
+ unsigned int i, j;
|
|
|
+
|
|
|
+ for (j = 0; j < height / 8; j++) {
|
|
|
+ for (i = 0; i < width / 8; i++) {
|
|
|
+ /* intra code, first frame is always intra coded. */
|
|
|
+ int blocktype = IBLOCK;
|
|
|
+ unsigned int size;
|
|
|
+
|
|
|
+ if (!is_intra)
|
|
|
+ blocktype = decide_blocktype(input, refp,
|
|
|
+ deltablock, width, input_step);
|
|
|
+ if (is_intra || blocktype == IBLOCK) {
|
|
|
+ fwht(input, cf->coeffs, width, input_step, 1);
|
|
|
+ quantize_intra(cf->coeffs, cf->de_coeffs);
|
|
|
+ blocktype = IBLOCK;
|
|
|
+ } else {
|
|
|
+ /* inter code */
|
|
|
+ encoding |= FRAME_PCODED;
|
|
|
+ fwht16(deltablock, cf->coeffs, 8, 0);
|
|
|
+ quantize_inter(cf->coeffs, cf->de_coeffs);
|
|
|
+ }
|
|
|
+ if (!next_is_intra) {
|
|
|
+ ifwht(cf->de_coeffs, cf->de_fwht, blocktype);
|
|
|
+
|
|
|
+ if (blocktype == PBLOCK)
|
|
|
+ add_deltas(cf->de_fwht, refp, 8);
|
|
|
+ fill_decoder_block(refp, cf->de_fwht, 8);
|
|
|
+ }
|
|
|
+
|
|
|
+ input += 8 * input_step;
|
|
|
+ refp += 8 * 8;
|
|
|
+
|
|
|
+ if (encoding & FRAME_UNENCODED)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ size = rlc(cf->coeffs, *rlco, blocktype);
|
|
|
+ if (last_size == size &&
|
|
|
+ !memcmp(*rlco + 1, *rlco - size + 1, 2 * size - 2)) {
|
|
|
+ __be16 *last_rlco = *rlco - size;
|
|
|
+ s16 hdr = ntohs(*last_rlco);
|
|
|
+
|
|
|
+ if (!((*last_rlco ^ **rlco) & pframe_bit) &&
|
|
|
+ (hdr & DUPS_MASK) < DUPS_MASK)
|
|
|
+ *last_rlco = htons(hdr + 2);
|
|
|
+ else
|
|
|
+ *rlco += size;
|
|
|
+ } else {
|
|
|
+ *rlco += size;
|
|
|
+ }
|
|
|
+ if (*rlco >= rlco_max)
|
|
|
+ encoding |= FRAME_UNENCODED;
|
|
|
+ last_size = size;
|
|
|
+ }
|
|
|
+ input += width * 7 * input_step;
|
|
|
+ }
|
|
|
+ if (encoding & FRAME_UNENCODED) {
|
|
|
+ u8 *out = (u8 *)rlco_start;
|
|
|
+
|
|
|
+ input = input_start;
|
|
|
+ /*
|
|
|
+ * The compressed stream should never contain the magic
|
|
|
+ * header, so when we copy the YUV data we replace 0xff
|
|
|
+ * by 0xfe. Since YUV is limited range such values
|
|
|
+ * shouldn't appear anyway.
|
|
|
+ */
|
|
|
+ for (i = 0; i < height * width; i++, input += input_step)
|
|
|
+ *out++ = (*input == 0xff) ? 0xfe : *input;
|
|
|
+ *rlco = (__be16 *)out;
|
|
|
+ }
|
|
|
+ return encoding;
|
|
|
+}
|
|
|
+
|
|
|
+u32 encode_frame(struct raw_frame *frm, struct raw_frame *ref_frm,
|
|
|
+ struct cframe *cf, bool is_intra, bool next_is_intra)
|
|
|
+{
|
|
|
+ unsigned int size = frm->height * frm->width;
|
|
|
+ __be16 *rlco = cf->rlc_data;
|
|
|
+ __be16 *rlco_max;
|
|
|
+ u32 encoding;
|
|
|
+
|
|
|
+ rlco_max = rlco + size / 2 - 256;
|
|
|
+ encoding = encode_plane(frm->luma, ref_frm->luma, &rlco, rlco_max, cf,
|
|
|
+ frm->height, frm->width,
|
|
|
+ 1, is_intra, next_is_intra);
|
|
|
+ if (encoding & FRAME_UNENCODED)
|
|
|
+ encoding |= LUMA_UNENCODED;
|
|
|
+ encoding &= ~FRAME_UNENCODED;
|
|
|
+ rlco_max = rlco + size / 8 - 256;
|
|
|
+ encoding |= encode_plane(frm->cb, ref_frm->cb, &rlco, rlco_max, cf,
|
|
|
+ frm->height / 2, frm->width / 2,
|
|
|
+ frm->chroma_step, is_intra, next_is_intra);
|
|
|
+ if (encoding & FRAME_UNENCODED)
|
|
|
+ encoding |= CB_UNENCODED;
|
|
|
+ encoding &= ~FRAME_UNENCODED;
|
|
|
+ rlco_max = rlco + size / 8 - 256;
|
|
|
+ encoding |= encode_plane(frm->cr, ref_frm->cr, &rlco, rlco_max, cf,
|
|
|
+ frm->height / 2, frm->width / 2,
|
|
|
+ frm->chroma_step, is_intra, next_is_intra);
|
|
|
+ if (encoding & FRAME_UNENCODED)
|
|
|
+ encoding |= CR_UNENCODED;
|
|
|
+ encoding &= ~FRAME_UNENCODED;
|
|
|
+ cf->size = (rlco - cf->rlc_data) * sizeof(*rlco);
|
|
|
+ return encoding;
|
|
|
+}
|
|
|
+
|
|
|
+static void decode_plane(struct cframe *cf, const __be16 **rlco, u8 *ref,
|
|
|
+ u32 height, u32 width, bool uncompressed)
|
|
|
+{
|
|
|
+ unsigned int copies = 0;
|
|
|
+ s16 copy[8 * 8];
|
|
|
+ s16 stat;
|
|
|
+ unsigned int i, j;
|
|
|
+
|
|
|
+ if (uncompressed) {
|
|
|
+ memcpy(ref, *rlco, width * height);
|
|
|
+ *rlco += width * height / 2;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * When decoding each macroblock the rlco pointer will be increased
|
|
|
+ * by 65 * 2 bytes worst-case.
|
|
|
+ * To avoid overflow the buffer has to be 65/64th of the actual raw
|
|
|
+ * image size, just in case someone feeds it malicious data.
|
|
|
+ */
|
|
|
+ for (j = 0; j < height / 8; j++) {
|
|
|
+ for (i = 0; i < width / 8; i++) {
|
|
|
+ u8 *refp = ref + j * 8 * width + i * 8;
|
|
|
+
|
|
|
+ if (copies) {
|
|
|
+ memcpy(cf->de_fwht, copy, sizeof(copy));
|
|
|
+ if (stat & PFRAME_BIT)
|
|
|
+ add_deltas(cf->de_fwht, refp, width);
|
|
|
+ fill_decoder_block(refp, cf->de_fwht, width);
|
|
|
+ copies--;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ stat = derlc(rlco, cf->coeffs);
|
|
|
+
|
|
|
+ if (stat & PFRAME_BIT)
|
|
|
+ dequantize_inter(cf->coeffs);
|
|
|
+ else
|
|
|
+ dequantize_intra(cf->coeffs);
|
|
|
+
|
|
|
+ ifwht(cf->coeffs, cf->de_fwht,
|
|
|
+ (stat & PFRAME_BIT) ? 0 : 1);
|
|
|
+
|
|
|
+ copies = (stat & DUPS_MASK) >> 1;
|
|
|
+ if (copies)
|
|
|
+ memcpy(copy, cf->de_fwht, sizeof(copy));
|
|
|
+ if (stat & PFRAME_BIT)
|
|
|
+ add_deltas(cf->de_fwht, refp, width);
|
|
|
+ fill_decoder_block(refp, cf->de_fwht, width);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void decode_frame(struct cframe *cf, struct raw_frame *ref, u32 hdr_flags)
|
|
|
+{
|
|
|
+ const __be16 *rlco = cf->rlc_data;
|
|
|
+
|
|
|
+ decode_plane(cf, &rlco, ref->luma, cf->height, cf->width,
|
|
|
+ hdr_flags & VICODEC_FL_LUMA_IS_UNCOMPRESSED);
|
|
|
+ decode_plane(cf, &rlco, ref->cb, cf->height / 2, cf->width / 2,
|
|
|
+ hdr_flags & VICODEC_FL_CB_IS_UNCOMPRESSED);
|
|
|
+ decode_plane(cf, &rlco, ref->cr, cf->height / 2, cf->width / 2,
|
|
|
+ hdr_flags & VICODEC_FL_CR_IS_UNCOMPRESSED);
|
|
|
+}
|