summaryrefslogtreecommitdiff
path: root/gpr/source/lib/vc5_common/image.c
blob: 0af14fe1243e41c89af407b9bdfa9e2b26a8ea38 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
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;
}