diff options
Diffstat (limited to 'gpr/source/lib/vc5_decoder/inverse.c')
-rwxr-xr-x | gpr/source/lib/vc5_decoder/inverse.c | 1188 |
1 files changed, 1188 insertions, 0 deletions
diff --git a/gpr/source/lib/vc5_decoder/inverse.c b/gpr/source/lib/vc5_decoder/inverse.c new file mode 100755 index 0000000..cacc7be --- /dev/null +++ b/gpr/source/lib/vc5_decoder/inverse.c @@ -0,0 +1,1188 @@ +/*! @file inverse.c + * + * @brief Implementation of the inverse wavelet transforms. + * + * (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 "headers.h" + +//! Rounding adjustment used by the inverse wavelet transforms +static const int32_t rounding = 4; + +/*! + @brief Apply the inverse horizontal wavelet transform + This routine applies the inverse wavelet transform to a row of + lowpass and highpass coefficients, producing an output row that + is write as wide. + */ +STATIC CODEC_ERROR InvertHorizontal16s(PIXEL *lowpass, //!< Horizontal lowpass coefficients + PIXEL *highpass, //!< Horizontal highpass coefficients + PIXEL *output, //!< Row of reconstructed results + DIMENSION input_width, //!< Number of values in the input row + DIMENSION output_width //!< Number of values in the output row +) +{ + const int last_column = input_width - 1; + + int32_t even; + int32_t odd; + + // Start processing at the beginning of the row + int column = 0; + + // Process the first two output points with special filters for the left border + even = 0; + odd = 0; + + // Apply the even reconstruction filter to the lowpass band + even += 11 * lowpass[column + 0]; + even -= 4 * lowpass[column + 1]; + even += 1 * lowpass[column + 2]; + even += rounding; + even = DivideByShift(even, 3); + + // Add the highpass correction + even += highpass[column]; + even >>= 1; + + // The lowpass result should be a positive number + //assert(0 <= even && even <= INT16_MAX); + + // Apply the odd reconstruction filter to the lowpass band + odd += 5 * lowpass[column + 0]; + odd += 4 * lowpass[column + 1]; + odd -= 1 * lowpass[column + 2]; + odd += rounding; + odd = DivideByShift(odd, 3); + + // Subtract the highpass correction + odd -= highpass[column]; + odd >>= 1; + + // The lowpass result should be a positive number + //assert(0 <= odd && odd <= INT16_MAX); + + // Store the last two output points produced by the loop + output[2 * column + 0] = clamp_uint14(even); + output[2 * column + 1] = clamp_uint14(odd); + + // Advance to the next input column (second pair of output values) + column++; + + // Process the rest of the columns up to the last column in the row + for (; column < last_column; column++) + { + int32_t even = 0; // Result of convolution with even filter + int32_t odd = 0; // Result of convolution with odd filter + + // Apply the even reconstruction filter to the lowpass band + + even += lowpass[column - 1]; + even -= lowpass[column + 1]; + even += 4; + even >>= 3; + even += lowpass[column + 0]; + + // Add the highpass correction + even += highpass[column]; + even >>= 1; + + // The lowpass result should be a positive number + //assert(0 <= even && even <= INT16_MAX); + + // Place the even result in the even column + //output[2 * column + 0] = clamp_uint12(even); + output[2 * column + 0] = clamp_uint14(even); + + // Apply the odd reconstruction filter to the lowpass band + odd -= lowpass[column - 1]; + odd += lowpass[column + 1]; + odd += 4; + odd >>= 3; + odd += lowpass[column + 0]; + + // Subtract the highpass correction + odd -= highpass[column]; + odd >>= 1; + + // The lowpass result should be a positive number + //assert(0 <= odd && odd <= INT16_MAX); + + // Place the odd result in the odd column + //output[2 * column + 1] = clamp_uint14(odd); + output[2 * column + 1] = clamp_uint14(odd); + } + + // Should have exited the loop at the column for right border processing + assert(column == last_column); + + // Process the last two output points with special filters for the right border + even = 0; + odd = 0; + + // Apply the even reconstruction filter to the lowpass band + even += 5 * lowpass[column + 0]; + even += 4 * lowpass[column - 1]; + even -= 1 * lowpass[column - 2]; + even += rounding; + even = DivideByShift(even, 3); + + // Add the highpass correction + even += highpass[column]; + even >>= 1; + + // The lowpass result should be a positive number + //assert(0 <= even && even <= INT16_MAX); + + // Place the even result in the even column + output[2 * column + 0] = clamp_uint14(even); + + if (2 * column + 1 < output_width) + { + // Apply the odd reconstruction filter to the lowpass band + odd += 11 * lowpass[column + 0]; + odd -= 4 * lowpass[column - 1]; + odd += 1 * lowpass[column - 2]; + odd += rounding; + odd = DivideByShift(odd, 3); + + // Subtract the highpass correction + odd -= highpass[column]; + odd >>= 1; + + // The lowpass result should be a positive number + //assert(0 <= odd && odd <= INT16_MAX); + + // Place the odd result in the odd column + output[2 * column + 1] = clamp_uint14(odd); + } + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Apply the inverse horizontal wavelet transform + This routine is similar to @ref InvertHorizontal16s, but a scale factor + that was applied during encoding is removed from the output values. + */ +STATIC CODEC_ERROR InvertHorizontalDescale16s(PIXEL *lowpass, PIXEL *highpass, PIXEL *output, + DIMENSION input_width, DIMENSION output_width, + int descale) +{ + const int last_column = input_width - 1; + + // Start processing at the beginning of the row + int column = 0; + + int descale_shift = 0; + + int32_t even; + int32_t odd; + + /* + The implementation of the inverse filter includes descaling by a factor of two + because the last division by two in the computation of the even and odd results + that is performed using a right arithmetic shift has been omitted from the code. + */ + if (descale == 2) { + descale_shift = 1; + } + + // Check that the descaling value is reasonable + assert(descale_shift >= 0); + + // Process the first two output points with special filters for the left border + even = 0; + odd = 0; + + // Apply the even reconstruction filter to the lowpass band + even += 11 * lowpass[column + 0]; + even -= 4 * lowpass[column + 1]; + even += 1 * lowpass[column + 2]; + even += rounding; + even = DivideByShift(even, 3); + + // Add the highpass correction + even += highpass[column]; + + // Remove any scaling used during encoding + even <<= descale_shift; + + // The lowpass result should be a positive number + //assert(0 <= even && even <= INT16_MAX); + + // Apply the odd reconstruction filter to the lowpass band + odd += 5 * lowpass[column + 0]; + odd += 4 * lowpass[column + 1]; + odd -= 1 * lowpass[column + 2]; + odd += rounding; + odd = DivideByShift(odd, 3); + + // Subtract the highpass correction + odd -= highpass[column]; + + // Remove any scaling used during encoding + odd <<= descale_shift; + + // The lowpass result should be a positive number + //assert(0 <= odd && odd <= INT16_MAX); + + output[2 * column + 0] = ClampPixel(even); + output[2 * column + 1] = ClampPixel(odd); + + // Advance to the next input column (second pair of output values) + column++; + + // Process the rest of the columns up to the last column in the row + for (; column < last_column; column++) + { + int32_t even = 0; // Result of convolution with even filter + int32_t odd = 0; // Result of convolution with odd filter + + // Apply the even reconstruction filter to the lowpass band + even += lowpass[column - 1]; + even -= lowpass[column + 1]; + even += 4; + even >>= 3; + even += lowpass[column + 0]; + + // Add the highpass correction + even += highpass[column]; + + // Remove any scaling used during encoding + even <<= descale_shift; + + // The lowpass result should be a positive number + //assert(0 <= even && even <= INT16_MAX); + + // Place the even result in the even column + output[2 * column + 0] = ClampPixel(even); + + // Apply the odd reconstruction filter to the lowpass band + odd -= lowpass[column - 1]; + odd += lowpass[column + 1]; + odd += 4; + odd >>= 3; + odd += lowpass[column + 0]; + + // Subtract the highpass correction + odd -= highpass[column]; + + // Remove any scaling used during encoding + odd <<= descale_shift; + + // The lowpass result should be a positive number + //assert(0 <= odd && odd <= INT16_MAX); + + // Place the odd result in the odd column + output[2 * column + 1] = ClampPixel(odd); + } + + // Should have exited the loop at the column for right border processing + assert(column == last_column); + + // Process the last two output points with special filters for the right border + even = 0; + odd = 0; + + // Apply the even reconstruction filter to the lowpass band + even += 5 * lowpass[column + 0]; + even += 4 * lowpass[column - 1]; + even -= 1 * lowpass[column - 2]; + even += rounding; + even = DivideByShift(even, 3); + + // Add the highpass correction + even += highpass[column]; + + // Remove any scaling used during encoding + even <<= descale_shift; + + // The lowpass result should be a positive number + //assert(0 <= even && even <= INT16_MAX); + + // Place the even result in the even column + output[2 * column + 0] = ClampPixel(even); + + if (2 * column + 1 < output_width) + { + // Apply the odd reconstruction filter to the lowpass band + odd += 11 * lowpass[column + 0]; + odd -= 4 * lowpass[column - 1]; + odd += 1 * lowpass[column - 2]; + odd += rounding; + odd = DivideByShift(odd, 3); + + // Subtract the highpass correction + odd -= highpass[column]; + + // Remove any scaling used during encoding + odd <<= descale_shift; + + // The lowpass result should be a positive number + //assert(0 <= odd && odd <= INT16_MAX); + + // Place the odd result in the odd column + output[2 * column + 1] = ClampPixel(odd); + } + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Apply the inverse spatial wavelet filter + Dequantize the coefficients in the highpass bands and apply the + inverse spatial wavelet filter to compute a lowpass band that + has twice the width and height of the input bands. + The inverse vertical filter is applied to the upper and lower bands + on the left and the upper and lower bands on the right. The inverse + horizontal filter is applied to the left and right (lowpass and highpass) + results from the vertical inverse. Each application of the inverse + vertical filter produces two output rows and each application of the + inverse horizontal filter produces an output row that is twice as wide. + The inverse wavelet filter is a three tap filter. + + For the even output values, add and subtract the off-center values, + add the rounding correction, and divide by eight, then add the center + value, add the highpass coefficient, and divide by two. + + For the odd output values, the add and subtract operations for the + off-center values are reversed the the highpass coefficient is subtracted. + Divisions are implemented by right arithmetic shifts. + Special formulas for the inverse vertical filter are applied to the top + and bottom rows. + */ +CODEC_ERROR InvertSpatialQuant16s(gpr_allocator *allocator, + PIXEL *lowlow_band, int lowlow_pitch, + PIXEL *lowhigh_band, int lowhigh_pitch, + PIXEL *highlow_band, int highlow_pitch, + PIXEL *highhigh_band, int highhigh_pitch, + PIXEL *output_image, int output_pitch, + DIMENSION input_width, DIMENSION input_height, + DIMENSION output_width, DIMENSION output_height, + QUANT quantization[]) +{ + PIXEL *lowlow = (PIXEL *)lowlow_band; + PIXEL *lowhigh = lowhigh_band; + PIXEL *highlow = highlow_band; + PIXEL *highhigh = highhigh_band; + PIXEL *output = output_image; + PIXEL *even_lowpass; + PIXEL *even_highpass; + PIXEL *odd_lowpass; + PIXEL *odd_highpass; + PIXEL *even_output; + PIXEL *odd_output; + size_t buffer_row_size; + int last_row = input_height - 1; + int row, column; + + PIXEL *lowhigh_row[3]; + + PIXEL *lowhigh_line[3]; + PIXEL *highlow_line; + PIXEL *highhigh_line; + + QUANT highlow_quantization = quantization[HL_BAND]; + QUANT lowhigh_quantization = quantization[LH_BAND]; + QUANT highhigh_quantization = quantization[HH_BAND]; + + // Compute positions within the temporary buffer for each row of horizontal lowpass + // and highpass intermediate coefficients computed by the vertical inverse transform + buffer_row_size = input_width * sizeof(PIXEL); + + // Compute the positions of the even and odd rows of coefficients + even_lowpass = (PIXEL *)allocator->Alloc(buffer_row_size); + even_highpass = (PIXEL *)allocator->Alloc(buffer_row_size); + odd_lowpass = (PIXEL *)allocator->Alloc(buffer_row_size); + odd_highpass = (PIXEL *)allocator->Alloc(buffer_row_size); + + // Compute the positions of the dequantized highpass rows + lowhigh_line[0] = (PIXEL *)allocator->Alloc(buffer_row_size); + lowhigh_line[1] = (PIXEL *)allocator->Alloc(buffer_row_size); + lowhigh_line[2] = (PIXEL *)allocator->Alloc(buffer_row_size); + highlow_line = (PIXEL *)allocator->Alloc(buffer_row_size); + highhigh_line = (PIXEL *)allocator->Alloc(buffer_row_size); + + // Convert pitch from bytes to pixels + lowlow_pitch /= sizeof(PIXEL); + lowhigh_pitch /= sizeof(PIXEL); + highlow_pitch /= sizeof(PIXEL); + highhigh_pitch /= sizeof(PIXEL); + output_pitch /= sizeof(PIXEL); + + // Initialize the pointers to the even and odd output rows + even_output = output; + odd_output = output + output_pitch; + + // Apply the vertical border filter to the first row + row = 0; + + // Set pointers to the first three rows in the first highpass band + lowhigh_row[0] = lowhigh + 0 * lowhigh_pitch; + lowhigh_row[1] = lowhigh + 1 * lowhigh_pitch; + lowhigh_row[2] = lowhigh + 2 * lowhigh_pitch; + + // Dequantize three rows of highpass coefficients in the first highpass band + DequantizeBandRow16s(lowhigh_row[0], input_width, lowhigh_quantization, lowhigh_line[0]); + DequantizeBandRow16s(lowhigh_row[1], input_width, lowhigh_quantization, lowhigh_line[1]); + DequantizeBandRow16s(lowhigh_row[2], input_width, lowhigh_quantization, lowhigh_line[2]); + + // Dequantize one row of coefficients each in the second and third highpass bands + DequantizeBandRow16s(highlow, input_width, highlow_quantization, highlow_line); + DequantizeBandRow16s(highhigh, input_width, highhigh_quantization, highhigh_line); + + for (column = 0; column < input_width; column++) + { + int32_t even = 0; // Result of convolution with even filter + int32_t odd = 0; // Result of convolution with odd filter + + + /***** Compute the vertical inverse for the left two bands *****/ + + // Apply the even reconstruction filter to the lowpass band + even += 11 * lowlow[column + 0 * lowlow_pitch]; + even -= 4 * lowlow[column + 1 * lowlow_pitch]; + even += 1 * lowlow[column + 2 * lowlow_pitch]; + even += rounding; + even = DivideByShift(even, 3); + + // Add the highpass correction + even += highlow_line[column]; + even >>= 1; + + // The inverse of the left two bands should be a positive number + //assert(0 <= even && even <= INT16_MAX); + + // Place the even result in the even row + even_lowpass[column] = ClampPixel(even); + + // Apply the odd reconstruction filter to the lowpass band + odd += 5 * lowlow[column + 0 * lowlow_pitch]; + odd += 4 * lowlow[column + 1 * lowlow_pitch]; + odd -= 1 * lowlow[column + 2 * lowlow_pitch]; + odd += rounding; + odd = DivideByShift(odd, 3); + + // Subtract the highpass correction + odd -= highlow_line[column]; + odd >>= 1; + + // The inverse of the left two bands should be a positive number + //assert(0 <= odd && odd <= INT16_MAX); + + // Place the odd result in the odd row + odd_lowpass[column] = ClampPixel(odd); + + + /***** Compute the vertical inverse for the right two bands *****/ + + even = 0; + odd = 0; + + // Apply the even reconstruction filter to the lowpass band + even += 11 * lowhigh_line[0][column]; + even -= 4 * lowhigh_line[1][column]; + even += 1 * lowhigh_line[2][column]; + even += rounding; + even = DivideByShift(even, 3); + + // Add the highpass correction + even += highhigh_line[column]; + even >>= 1; + + // Place the even result in the even row + even_highpass[column] = ClampPixel(even); + + // Apply the odd reconstruction filter to the lowpass band + odd += 5 * lowhigh_line[0][column]; + odd += 4 * lowhigh_line[1][column]; + odd -= 1 * lowhigh_line[2][column]; + odd += rounding; + odd = DivideByShift(odd, 3); + + // Subtract the highpass correction + odd -= highhigh_line[column]; + odd >>= 1; + + // Place the odd result in the odd row + odd_highpass[column] = ClampPixel(odd); + } + + // Apply the inverse horizontal transform to the even and odd rows + InvertHorizontal16s(even_lowpass, even_highpass, even_output, input_width, output_width); + InvertHorizontal16s(odd_lowpass, odd_highpass, odd_output, input_width, output_width); + + // Advance to the next pair of even and odd output rows + even_output += 2 * output_pitch; + odd_output += 2 * output_pitch; + + // Always advance the highpass row pointers + highlow += highlow_pitch; + highhigh += highhigh_pitch; + + // Advance the row index + row++; + + // Process the middle rows using the interior reconstruction filters + for (; row < last_row; row++) + { + // Dequantize one row from each of the two highpass bands + DequantizeBandRow16s(highlow, input_width, highlow_quantization, highlow_line); + DequantizeBandRow16s(highhigh, input_width, highhigh_quantization, highhigh_line); + + // Process the entire row + for (column = 0; column < input_width; column++) + { + int32_t even = 0; // Result of convolution with even filter + int32_t odd = 0; // Result of convolution with odd filter + + + /***** Compute the vertical inverse for the left two bands *****/ + + // Apply the even reconstruction filter to the lowpass band + even += lowlow[column + 0 * lowlow_pitch]; + even -= lowlow[column + 2 * lowlow_pitch]; + even += 4; + even >>= 3; + even += lowlow[column + 1 * lowlow_pitch]; + + // Add the highpass correction + even += highlow_line[column]; + even >>= 1; + + // The inverse of the left two bands should be a positive number + //assert(0 <= even && even <= INT16_MAX); + + // Place the even result in the even row + even_lowpass[column] = ClampPixel(even); + + // Apply the odd reconstruction filter to the lowpass band + odd -= lowlow[column + 0 * lowlow_pitch]; + odd += lowlow[column + 2 * lowlow_pitch]; + odd += 4; + odd >>= 3; + odd += lowlow[column + 1 * lowlow_pitch]; + + // Subtract the highpass correction + odd -= highlow_line[column]; + odd >>= 1; + + // The inverse of the left two bands should be a positive number + //assert(0 <= odd && odd <= INT16_MAX); + + // Place the odd result in the odd row + odd_lowpass[column] = ClampPixel(odd); + + + /***** Compute the vertical inverse for the right two bands *****/ + + even = 0; + odd = 0; + + // Apply the even reconstruction filter to the lowpass band + even += lowhigh_line[0][column]; + even -= lowhigh_line[2][column]; + even += 4; + even >>= 3; + even += lowhigh_line[1][column]; + + // Add the highpass correction + even += highhigh_line[column]; + even >>= 1; + + // Place the even result in the even row + even_highpass[column] = ClampPixel(even); + + // Apply the odd reconstruction filter to the lowpass band + odd -= lowhigh_line[0][column]; + odd += lowhigh_line[2][column]; + odd += 4; + odd >>= 3; + odd += lowhigh_line[1][column]; + + // Subtract the highpass correction + odd -= highhigh_line[column]; + odd >>= 1; + + // Place the odd result in the odd row + odd_highpass[column] = ClampPixel(odd); + } + + // Apply the inverse horizontal transform to the even and odd rows and descale the results + InvertHorizontal16s(even_lowpass, even_highpass, even_output, input_width, output_width); + InvertHorizontal16s(odd_lowpass, odd_highpass, odd_output, input_width, output_width); + + // Advance to the next input row in each band + lowlow += lowlow_pitch; + lowhigh += lowhigh_pitch; + highlow += highlow_pitch; + highhigh += highhigh_pitch; + + // Advance to the next pair of even and odd output rows + even_output += 2 * output_pitch; + odd_output += 2 * output_pitch; + + if (row < last_row - 1) + { + // Compute the address of the next row in the lowhigh band + PIXEL *lowhigh_row_ptr = (lowhigh + 2 * lowhigh_pitch); + //PIXEL *lowhigh_row_ptr = (lowhigh + lowhigh_pitch); + + // Shift the rows in the buffer of dequantized lowhigh bands + PIXEL *temp = lowhigh_line[0]; + lowhigh_line[0] = lowhigh_line[1]; + lowhigh_line[1] = lowhigh_line[2]; + lowhigh_line[2] = temp; + + // Undo quantization for the next row in the lowhigh band + DequantizeBandRow16s(lowhigh_row_ptr, input_width, lowhigh_quantization, lowhigh_line[2]); + } + } + + // Should have exited the loop at the last row + assert(row == last_row); + + // Advance the lowlow pointer to the last row in the band + lowlow += lowlow_pitch; + + // Check that the band pointers are on the last row in each wavelet band + assert(lowlow == (lowlow_band + last_row * lowlow_pitch)); + + assert(highlow == (highlow_band + last_row * highlow_pitch)); + assert(highhigh == (highhigh_band + last_row * highhigh_pitch)); + + // Undo quantization for the highlow and highhigh bands + DequantizeBandRow16s(highlow, input_width, highlow_quantization, highlow_line); + DequantizeBandRow16s(highhigh, input_width, highhigh_quantization, highhigh_line); + + // Apply the vertical border filter to the last row + for (column = 0; column < input_width; column++) + { + int32_t even = 0; // Result of convolution with even filter + int32_t odd = 0; // Result of convolution with odd filter + + + /***** Compute the vertical inverse for the left two bands *****/ + + // Apply the even reconstruction filter to the lowpass band + even += 5 * lowlow[column + 0 * lowlow_pitch]; + even += 4 * lowlow[column - 1 * lowlow_pitch]; + even -= 1 * lowlow[column - 2 * lowlow_pitch]; + even += 4; + even = DivideByShift(even, 3); + + // Add the highpass correction + even += highlow_line[column]; + even >>= 1; + + // The inverse of the left two bands should be a positive number + //assert(0 <= even && even <= INT16_MAX); + + // Place the even result in the even row + even_lowpass[column] = ClampPixel(even); + + // Apply the odd reconstruction filter to the lowpass band + odd += 11 * lowlow[column + 0 * lowlow_pitch]; + odd -= 4 * lowlow[column - 1 * lowlow_pitch]; + odd += 1 * lowlow[column - 2 * lowlow_pitch]; + odd += 4; + odd = DivideByShift(odd, 3); + + // Subtract the highpass correction + odd -= highlow_line[column]; + odd >>= 1; + + // The inverse of the left two bands should be a positive number + //assert(0 <= odd && odd <= INT16_MAX); + + // Place the odd result in the odd row + odd_lowpass[column] = ClampPixel(odd); + + + // Compute the vertical inverse for the right two bands // + + even = 0; + odd = 0; + + // Apply the even reconstruction filter to the lowpass band + even += 5 * lowhigh_line[2][column]; + even += 4 * lowhigh_line[1][column]; + even -= 1 * lowhigh_line[0][column]; + even += 4; + even = DivideByShift(even, 3); + + // Add the highpass correction + even += highhigh_line[column]; + even >>= 1; + + // Place the even result in the even row + even_highpass[column] = ClampPixel(even); + + // Apply the odd reconstruction filter to the lowpass band + odd += 11 * lowhigh_line[2][column]; + odd -= 4 * lowhigh_line[1][column]; + odd += 1 * lowhigh_line[0][column]; + odd += 4; + odd = DivideByShift(odd, 3); + + // Subtract the highpass correction + odd -= highhigh_line[column]; + odd >>= 1; + + // Place the odd result in the odd row + odd_highpass[column] = ClampPixel(odd); + } + + // Apply the inverse horizontal transform to the even and odd rows and descale the results + InvertHorizontal16s(even_lowpass, even_highpass, even_output, input_width, output_width); + + // Is the output wavelet shorter than twice the height of the input wavelet? + if (2 * row + 1 < output_height) { + InvertHorizontal16s(odd_lowpass, odd_highpass, odd_output, input_width, output_width); + } + + // Free the scratch buffers + allocator->Free(even_lowpass); + allocator->Free(even_highpass); + allocator->Free(odd_lowpass); + allocator->Free(odd_highpass); + + allocator->Free(lowhigh_line[0]); + allocator->Free(lowhigh_line[1]); + allocator->Free(lowhigh_line[2]); + allocator->Free(highlow_line); + allocator->Free(highhigh_line); + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Apply the inverse spatial transform with descaling + This routine is similar to @ref InvertSpatialQuant16s, but a scale factor + that was applied during encoding is removed from the output values. + */ +CODEC_ERROR InvertSpatialQuantDescale16s(gpr_allocator *allocator, + PIXEL *lowlow_band, int lowlow_pitch, + PIXEL *lowhigh_band, int lowhigh_pitch, + PIXEL *highlow_band, int highlow_pitch, + PIXEL *highhigh_band, int highhigh_pitch, + PIXEL *output_image, int output_pitch, + DIMENSION input_width, DIMENSION input_height, + DIMENSION output_width, DIMENSION output_height, + int descale, QUANT quantization[]) +{ + PIXEL *lowlow = lowlow_band; + PIXEL *lowhigh = lowhigh_band; + PIXEL *highlow = highlow_band; + PIXEL *highhigh = highhigh_band; + PIXEL *output = output_image; + PIXEL *even_lowpass; + PIXEL *even_highpass; + PIXEL *odd_lowpass; + PIXEL *odd_highpass; + PIXEL *even_output; + PIXEL *odd_output; + size_t buffer_row_size; + int last_row = input_height - 1; + int row, column; + + PIXEL *lowhigh_row[3]; + + PIXEL *lowhigh_line[3]; + PIXEL *highlow_line; + PIXEL *highhigh_line; + + QUANT highlow_quantization = quantization[HL_BAND]; + QUANT lowhigh_quantization = quantization[LH_BAND]; + QUANT highhigh_quantization = quantization[HH_BAND]; + + // Compute positions within the temporary buffer for each row of horizontal lowpass + // and highpass intermediate coefficients computed by the vertical inverse transform + buffer_row_size = input_width * sizeof(PIXEL); + + // Allocate space for the even and odd rows of results from the inverse vertical filter + even_lowpass = (PIXEL *)allocator->Alloc(buffer_row_size); + even_highpass = (PIXEL *)allocator->Alloc(buffer_row_size); + odd_lowpass = (PIXEL *)allocator->Alloc(buffer_row_size); + odd_highpass = (PIXEL *)allocator->Alloc(buffer_row_size); + + // Allocate scratch space for the dequantized highpass coefficients + lowhigh_line[0] = (PIXEL *)allocator->Alloc(buffer_row_size); + lowhigh_line[1] = (PIXEL *)allocator->Alloc(buffer_row_size); + lowhigh_line[2] = (PIXEL *)allocator->Alloc(buffer_row_size); + highlow_line = (PIXEL *)allocator->Alloc(buffer_row_size); + highhigh_line = (PIXEL *)allocator->Alloc(buffer_row_size); + + // Convert pitch from bytes to pixels + lowlow_pitch /= sizeof(PIXEL); + lowhigh_pitch /= sizeof(PIXEL); + highlow_pitch /= sizeof(PIXEL); + highhigh_pitch /= sizeof(PIXEL); + output_pitch /= sizeof(PIXEL); + + // Initialize the pointers to the even and odd output rows + even_output = output; + odd_output = output + output_pitch; + + // Apply the vertical border filter to the first row + row = 0; + + // Set pointers to the first three rows in the first highpass band + lowhigh_row[0] = lowhigh + 0 * lowhigh_pitch; + lowhigh_row[1] = lowhigh + 1 * lowhigh_pitch; + lowhigh_row[2] = lowhigh + 2 * lowhigh_pitch; + + // Dequantize three rows of highpass coefficients in the first highpass band + DequantizeBandRow16s(lowhigh_row[0], input_width, lowhigh_quantization, lowhigh_line[0]); + DequantizeBandRow16s(lowhigh_row[1], input_width, lowhigh_quantization, lowhigh_line[1]); + DequantizeBandRow16s(lowhigh_row[2], input_width, lowhigh_quantization, lowhigh_line[2]); + + // Dequantize one row of coefficients each in the second and third highpass bands + DequantizeBandRow16s(highlow, input_width, highlow_quantization, highlow_line); + DequantizeBandRow16s(highhigh, input_width, highhigh_quantization, highhigh_line); + + for (column = 0; column < input_width; column++) + { + int32_t even = 0; // Result of convolution with even filter + int32_t odd = 0; // Result of convolution with odd filter + + + /***** Compute the vertical inverse for the left two bands *****/ + + // Apply the even reconstruction filter to the lowpass band + even += 11 * lowlow[column + 0 * lowlow_pitch]; + even -= 4 * lowlow[column + 1 * lowlow_pitch]; + even += 1 * lowlow[column + 2 * lowlow_pitch]; + even += rounding; + even = DivideByShift(even, 3); + + // Add the highpass correction + even += highlow_line[column]; + even = DivideByShift(even, 1); + + // The inverse of the left two bands should be a positive number + //assert(0 <= even && even <= INT16_MAX); + + // Place the even result in the even row + even_lowpass[column] = ClampPixel(even); + + // Apply the odd reconstruction filter to the lowpass band + odd += 5 * lowlow[column + 0 * lowlow_pitch]; + odd += 4 * lowlow[column + 1 * lowlow_pitch]; + odd -= 1 * lowlow[column + 2 * lowlow_pitch]; + odd += rounding; + odd = DivideByShift(odd, 3); + + // Subtract the highpass correction + odd -= highlow_line[column]; + odd = DivideByShift(odd, 1); + + // The inverse of the left two bands should be a positive number + //assert(0 <= odd && odd <= INT16_MAX); + + // Place the odd result in the odd row + odd_lowpass[column] = ClampPixel(odd); + + + /***** Compute the vertical inverse for the right two bands *****/ + + even = 0; + odd = 0; + + // Apply the even reconstruction filter to the lowpass band + even += 11 * lowhigh_line[0][column]; + even -= 4 * lowhigh_line[1][column]; + even += 1 * lowhigh_line[2][column]; + even += rounding; + even = DivideByShift(even, 3); + + // Add the highpass correction + even += highhigh_line[column]; + even = DivideByShift(even, 1); + + // Place the even result in the even row + even_highpass[column] = ClampPixel(even); + + // Apply the odd reconstruction filter to the lowpass band + odd += 5 * lowhigh_line[0][column]; + odd += 4 * lowhigh_line[1][column]; + odd -= 1 * lowhigh_line[2][column]; + odd += rounding; + odd = DivideByShift(odd, 3); + + // Subtract the highpass correction + odd -= highhigh_line[column]; + odd = DivideByShift(odd, 1); + + // Place the odd result in the odd row + odd_highpass[column] = ClampPixel(odd); + } + + // Apply the inverse horizontal transform to the even and odd rows and descale the results + InvertHorizontalDescale16s(even_lowpass, even_highpass, even_output, + input_width, output_width, descale); + + InvertHorizontalDescale16s(odd_lowpass, odd_highpass, odd_output, + input_width, output_width, descale); + + // Advance to the next pair of even and odd output rows + even_output += 2 * output_pitch; + odd_output += 2 * output_pitch; + + // Always advance the highpass row pointers + highlow += highlow_pitch; + highhigh += highhigh_pitch; + + // Advance the row index + row++; + + // Process the middle rows using the interior reconstruction filters + for (; row < last_row; row++) + { + // Dequantize one row from each of the two highpass bands + DequantizeBandRow16s(highlow, input_width, highlow_quantization, highlow_line); + DequantizeBandRow16s(highhigh, input_width, highhigh_quantization, highhigh_line); + + // Process the entire row + for (column = 0; column < input_width; column++) + { + int32_t even = 0; // Result of convolution with even filter + int32_t odd = 0; // Result of convolution with odd filter + + + /***** Compute the vertical inverse for the left two bands *****/ + + // Apply the even reconstruction filter to the lowpass band + even += lowlow[column + 0 * lowlow_pitch]; + even -= lowlow[column + 2 * lowlow_pitch]; + even += 4; + even >>= 3; + even += lowlow[column + 1 * lowlow_pitch]; + + // Add the highpass correction + even += highlow_line[column]; + even = DivideByShift(even, 1); + + // The inverse of the left two bands should be a positive number + //assert(0 <= even && even <= INT16_MAX); + + // Place the even result in the even row + even_lowpass[column] = ClampPixel(even); + + // Apply the odd reconstruction filter to the lowpass band + odd -= lowlow[column + 0 * lowlow_pitch]; + odd += lowlow[column + 2 * lowlow_pitch]; + odd += 4; + odd >>= 3; + odd += lowlow[column + 1 * lowlow_pitch]; + + // Subtract the highpass correction + odd -= highlow_line[column]; + odd = DivideByShift(odd, 1); + + // The inverse of the left two bands should be a positive number + //assert(0 <= odd && odd <= INT16_MAX); + + // Place the odd result in the odd row + odd_lowpass[column] = ClampPixel(odd); + + + /***** Compute the vertical inverse for the right two bands *****/ + + even = 0; + odd = 0; + + // Apply the even reconstruction filter to the lowpass band + even += lowhigh_line[0][column]; + even -= lowhigh_line[2][column]; + even += 4; + even >>= 3; + even += lowhigh_line[1][column]; + + // Add the highpass correction + even += highhigh_line[column]; + even = DivideByShift(even, 1); + + // Place the even result in the even row + even_highpass[column] = ClampPixel(even); + + // Apply the odd reconstruction filter to the lowpass band + odd -= lowhigh_line[0][column]; + odd += lowhigh_line[2][column]; + odd += 4; + odd >>= 3; + odd += lowhigh_line[1][column]; + + // Subtract the highpass correction + odd -= highhigh_line[column]; + odd = DivideByShift(odd, 1); + + // Place the odd result in the odd row + odd_highpass[column] = ClampPixel(odd); + } + + // Apply the inverse horizontal transform to the even and odd rows and descale the results + InvertHorizontalDescale16s(even_lowpass, even_highpass, even_output, + input_width, output_width, descale); + + InvertHorizontalDescale16s(odd_lowpass, odd_highpass, odd_output, + input_width, output_width, descale); + + // Advance to the next input row in each band + lowlow += lowlow_pitch; + lowhigh += lowhigh_pitch; + highlow += highlow_pitch; + highhigh += highhigh_pitch; + + // Advance to the next pair of even and odd output rows + even_output += 2 * output_pitch; + odd_output += 2 * output_pitch; + + if (row < last_row - 1) + { + // Compute the address of the next row in the lowhigh band + PIXEL *lowhigh_row_ptr = (lowhigh + 2 * lowhigh_pitch); + + // Shift the rows in the buffer of dequantized lowhigh bands + PIXEL *temp = lowhigh_line[0]; + lowhigh_line[0] = lowhigh_line[1]; + lowhigh_line[1] = lowhigh_line[2]; + lowhigh_line[2] = temp; + + // Undo quantization for the next row in the lowhigh band + DequantizeBandRow16s(lowhigh_row_ptr, input_width, lowhigh_quantization, lowhigh_line[2]); + } + } + + // Should have exited the loop at the last row + assert(row == last_row); + + // Advance the lowlow pointer to the last row in the band + lowlow += lowlow_pitch; + + // Check that the band pointers are on the last row in each wavelet band + assert(lowlow == (lowlow_band + last_row * lowlow_pitch)); + + assert(highlow == (highlow_band + last_row * highlow_pitch)); + assert(highhigh == (highhigh_band + last_row * highhigh_pitch)); + + // Undo quantization for the highlow and highhigh bands + DequantizeBandRow16s(highlow, input_width, highlow_quantization, highlow_line); + DequantizeBandRow16s(highhigh, input_width, highhigh_quantization, highhigh_line); + + // Apply the vertical border filter to the last row + for (column = 0; column < input_width; column++) + { + int32_t even = 0; // Result of convolution with even filter + int32_t odd = 0; // Result of convolution with odd filter + + + /***** Compute the vertical inverse for the left two bands *****/ + + // Apply the even reconstruction filter to the lowpass band + even += 5 * lowlow[column + 0 * lowlow_pitch]; + even += 4 * lowlow[column - 1 * lowlow_pitch]; + even -= 1 * lowlow[column - 2 * lowlow_pitch]; + even += rounding; + even = DivideByShift(even, 3); + + // Add the highpass correction + even += highlow_line[column]; + even = DivideByShift(even, 1); + + // The inverse of the left two bands should be a positive number + //assert(0 <= even && even <= INT16_MAX); + + // Place the even result in the even row + even_lowpass[column] = ClampPixel(even); + + // Apply the odd reconstruction filter to the lowpass band + odd += 11 * lowlow[column + 0 * lowlow_pitch]; + odd -= 4 * lowlow[column - 1 * lowlow_pitch]; + odd += 1 * lowlow[column - 2 * lowlow_pitch]; + odd += rounding; + odd = DivideByShift(odd, 3); + + // Subtract the highpass correction + odd -= highlow_line[column]; + odd = DivideByShift(odd, 1); + + // The inverse of the left two bands should be a positive number + //assert(0 <= odd && odd <= INT16_MAX); + + // Place the odd result in the odd row + odd_lowpass[column] = ClampPixel(odd); + + + /***** Compute the vertical inverse for the right two bands *****/ + + even = 0; + odd = 0; + + // Apply the even reconstruction filter to the lowpass band + even += 5 * lowhigh_line[2][column]; + even += 4 * lowhigh_line[1][column]; + even -= 1 * lowhigh_line[0][column]; + even += rounding; + even = DivideByShift(even, 3); + + // Add the highpass correction + even += highhigh_line[column]; + even = DivideByShift(even, 1); + + // Place the even result in the even row + even_highpass[column] = ClampPixel(even); + + // Apply the odd reconstruction filter to the lowpass band + odd += 11 * lowhigh_line[2][column]; + odd -= 4 * lowhigh_line[1][column]; + odd += 1 * lowhigh_line[0][column]; + odd += rounding; + odd = DivideByShift(odd, 3); + + // Subtract the highpass correction + odd -= highhigh_line[column]; + odd = DivideByShift(odd, 1); + + // Place the odd result in the odd row + odd_highpass[column] = ClampPixel(odd); + } + + // Apply the inverse horizontal transform to the even and odd rows and descale the results + InvertHorizontalDescale16s(even_lowpass, even_highpass, even_output, + input_width, output_width, descale); + + // Is the output wavelet shorter than twice the height of the input wavelet? + if (2 * row + 1 < output_height) { + InvertHorizontalDescale16s(odd_lowpass, odd_highpass, odd_output, + input_width, output_width, descale); + } + + // Free the scratch buffers + allocator->Free(even_lowpass); + allocator->Free(even_highpass); + allocator->Free(odd_lowpass); + allocator->Free(odd_highpass); + + allocator->Free(lowhigh_line[0]); + allocator->Free(lowhigh_line[1]); + allocator->Free(lowhigh_line[2]); + allocator->Free(highlow_line); + allocator->Free(highhigh_line); + + return CODEC_ERROR_OKAY; +} + |