diff options
Diffstat (limited to 'gpr/source/lib/vc5_common/image.c')
-rwxr-xr-x | gpr/source/lib/vc5_common/image.c | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/gpr/source/lib/vc5_common/image.c b/gpr/source/lib/vc5_common/image.c new file mode 100755 index 0000000..0af14fe --- /dev/null +++ b/gpr/source/lib/vc5_common/image.c @@ -0,0 +1,321 @@ +/*! @file image.c + * + * @brief Implementation of the data structure for the image that is + * input to the image unpacking process. + * + * @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" + +/*! + @brief Initialize the fields in an image data structure + This routine is the constructor for the image data type that + initializes an image instance to default values. + */ +CODEC_ERROR InitImage(IMAGE *image) +{ + if (image != NULL) + { + image->width = 0; + image->height = 0; + image->pitch = 0; + image->offset = 0; + image->format = PIXEL_FORMAT_UNKNOWN; + image->buffer = NULL; + image->size = 0; + return CODEC_ERROR_OKAY; + } + + return CODEC_ERROR_NULLPTR; +} + +CODEC_ERROR InitRGBImage(RGB_IMAGE *image) +{ + if (image != NULL) + { + image->width = 0; + image->height = 0; + image->pitch = 0; + image->buffer = NULL; + image->size = 0; + return CODEC_ERROR_OKAY; + } + + return CODEC_ERROR_NULLPTR; +} +/*! + @brief Allocate the buffer for a image with the sepcified dimensions and format. + This routine calculates the image pitch from the width and format, rounding up + the pitch to satisfy memory alignment requirements in the codec. + This routine will cause a memory leak if it is called with a image that has + already been allocated. + */ +CODEC_ERROR AllocImage(gpr_allocator *allocator, IMAGE *image, DIMENSION width, DIMENSION height, PIXEL_FORMAT format) +{ + size_t size = 0; + DIMENSION pitch = 0; + + assert(image != NULL); + + // Compute the pitch from the width and format + pitch = ImagePitch(width, format); + assert(pitch > 0); + +#if VC5_ENABLED_PART(VC5_PART_COLOR_SAMPLING) + size = height * pitch; +#else + size = height * pitch; +#endif + assert(size > 0); + + // Allocate the image buffer + image->buffer = allocator->Alloc(size); + if (image->buffer != NULL) + { + image->width = width; + image->height = height; + image->pitch = pitch; + image->format = format; + image->offset = 0; + image->size = size; + return CODEC_ERROR_OKAY; + } + + return CODEC_ERROR_OUTOFMEMORY; +} + +/*! + @brief Deallocate the buffer in a image data structure + This routine does not deallocate the image data structure itself. + In the typical use case, the image data structure is allocated on + the stack and teh decoder allocates the buffer for the output image + after determining the size of the image. The image data structure + is deallocated automatically by a calling routine. + */ +CODEC_ERROR ReleaseImage(gpr_allocator *allocator, IMAGE *image) +{ + allocator->Free(image->buffer); + return CODEC_ERROR_OKAY; +} + +/*! + @brief Compute the image pitch for the specified width and pixel format + The pitch of the image (in bytes) is computed for a image with the width + and pixel format that is specified. The pitch is rounted up to satisfy + memory alignment constraints required by the codec. + The return value is zero if the pitch could not be computed for the + specified width and format. + */ +DIMENSION ImagePitch(DIMENSION width, PIXEL_FORMAT format) +{ + DIMENSION pitch = 0; + + switch (format) + { + case PIXEL_FORMAT_RAW_RGGB_14: + case PIXEL_FORMAT_RAW_GBRG_12: + case PIXEL_FORMAT_RAW_GBRG_12P: + case PIXEL_FORMAT_RAW_RGGB_16: + // Half the width of the image times 2 samples times 2 bytes per sample + pitch = width * sizeof(uint16_t); + break; + + default: + assert(0); + } + + return pitch; +} + +/*! + @brief Set the dimensions and pixel format of a image + This routine is used to set the dimensions and format of a image + that was allocated with unknown parameters. + */ +CODEC_ERROR SetImageFormat(IMAGE *image, + DIMENSION width, + DIMENSION height, + DIMENSION pitch, + PIXEL_FORMAT format, + size_t offset) +{ + assert(image != NULL); + + image->width = width; + image->height = height; + image->pitch = pitch; + image->format = format; + image->offset = offset; + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Return the address of the image in the buffer + This routine should be used to obtain the starting address of + a image in a image buffer since the image may be offset from the + beginning of the buffer. + */ +void *ImageData(IMAGE *image) +{ + uint8_t *buffer = image->buffer; + buffer += image->offset; + return buffer; +} + +/*! + @brief Return the address of the specified row in the image + The routine returns NULL if the image argument is null or the + specified row is out of bounds. + */ +void *RowAddress(IMAGE *image, DIMENSION row) +{ + size_t pitch = image->pitch; + + if (image != NULL && image->pitch != 0) + { + //if (0 <= row && row < image->height) + if (row < image->height) + { + void *address = (void *)((uintptr_t)ImageData(image) + row * pitch); + return address; + } + } + + // Could not compute the address of a valid row + return NULL; +} + +CODEC_ERROR ReleaseComponentArrays(gpr_allocator *allocator, + UNPACKED_IMAGE *image, + int channel_count ) +{ + int channel; + + for (channel = 0; channel < channel_count; channel++) + { + allocator->Free( image->component_array_list[channel].data ); + } + + allocator->Free( image->component_array_list ); + + return CODEC_ERROR_OKAY; +} + +CODEC_ERROR AllocateComponentArrays(gpr_allocator *allocator, + UNPACKED_IMAGE *image, + int channel_count, + DIMENSION max_channel_width, + DIMENSION max_channel_height, + PIXEL_FORMAT format, + int bits_per_component) +{ + int channel; + + // Allocate the vector of component arrays + size_t size = channel_count * sizeof(COMPONENT_ARRAY); + image->component_array_list = allocator->Alloc(size); + if (image->component_array_list == NULL) { + return CODEC_ERROR_OUTOFMEMORY; + } + + // Clear the component array information so that the state is consistent + image->component_count = 0; + memset(image->component_array_list, 0, size); + + // Initialize each component array + for (channel = 0; channel < channel_count; channel++) + { + DIMENSION channel_width = max_channel_width; + DIMENSION channel_height = max_channel_height; + + // Allocate space for the data in the component array + CODEC_ERROR error = AllocateComponentArray( allocator, &image->component_array_list[channel], channel_width, channel_height, (uint_least8_t)bits_per_component ); + + if( error != CODEC_ERROR_OKAY ) { + return error; + } + } + + // Set the number of component arrays + image->component_count = channel_count; + + return CODEC_ERROR_OKAY; +} + +CODEC_ERROR AllocateComponentArray(gpr_allocator *allocator, + COMPONENT_ARRAY *component_array, + DIMENSION width, + DIMENSION height, + PRECISION bits_per_component) +{ + //COMPONENT_ARRAY *component_array = Alloc(allocator, sizeof(COMPONENT_ARRAY)); + + // Allocate space for the data in the component array + size_t pitch = width * sizeof(COMPONENT_VALUE); + size_t size = height * pitch; + void *buffer = allocator->Alloc(size); + assert(buffer != NULL); + if (! (buffer != NULL)) { + return CODEC_ERROR_OUTOFMEMORY; + } + + component_array->width = width; + component_array->height = height; + component_array->pitch = pitch; + component_array->data = buffer; + component_array->bits_per_component = bits_per_component; + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Initialize the data structure for the unpacked image + Note that the component arrays will be allocated after the bitstream + has been decoded and the dimensions of the component arrys are known. + */ +CODEC_ERROR InitUnpackedImage(UNPACKED_IMAGE *unpacked_image) +{ + if (unpacked_image == NULL) { + return CODEC_ERROR_UNEXPECTED; + } + + // Clear the fields in the unpacked iamge + memset(unpacked_image, 0, sizeof(UNPACKED_IMAGE)); + + return CODEC_ERROR_OKAY; +} + +/*! + @brief Return the maximum number of bits per component across all channels in the unpacked image + */ +PRECISION MaxBitsPerComponent(const UNPACKED_IMAGE *image) +{ + PRECISION max_bits_per_component = 0; + int channel; + + for (channel = 0; channel < image->component_count; channel++) + { + COMPONENT_ARRAY *component_array = &image->component_array_list[channel]; + + if (max_bits_per_component < component_array->bits_per_component) { + max_bits_per_component = component_array->bits_per_component; + } + } + + return max_bits_per_component; +} |