summaryrefslogtreecommitdiff
path: root/gpr/source/lib/vc5_common/image.c
diff options
context:
space:
mode:
Diffstat (limited to 'gpr/source/lib/vc5_common/image.c')
-rwxr-xr-xgpr/source/lib/vc5_common/image.c321
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;
+}