1/*
2 * soft_image.h - soft image class
3 *
4 *  Copyright (c) 2017 Intel Corporation
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *      http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * Author: Wind Yuan <feng.yuan@intel.com>
19 */
20
21#ifndef XCAM_SOFT_IMAGE_H
22#define XCAM_SOFT_IMAGE_H
23
24#include <xcam_std.h>
25#include <video_buffer.h>
26#include <vec_mat.h>
27#include <file_handle.h>
28
29namespace XCam {
30
31typedef uint8_t Uchar;
32typedef int8_t Char;
33typedef Vector2<uint8_t> Uchar2;
34typedef Vector2<int8_t> Char2;
35typedef Vector2<float> Float2;
36typedef Vector2<int> Int2;
37
38enum BorderType {
39    BorderTypeNearest,
40    BorderTypeConst,
41    BorderTypeRewind,
42};
43
44template <typename T>
45class SoftImage
46{
47public:
48    typedef T Type;
49private:
50    uint8_t    *_buf_ptr;
51    uint32_t    _width;
52    uint32_t    _height;
53    uint32_t    _pitch;
54
55    SmartPtr<VideoBuffer> _bind;
56
57public:
58    explicit SoftImage (const SmartPtr<VideoBuffer> &buf, const uint32_t plane);
59    explicit SoftImage (
60        const uint32_t width, const uint32_t height,
61        uint32_t aligned_width = 0);
62    explicit SoftImage (
63        const SmartPtr<VideoBuffer> &buf,
64        const uint32_t width, const uint32_t height, const uint32_t pictch, const uint32_t offset = 0);
65
66    ~SoftImage () {
67        if (!_bind.ptr ()) {
68            xcam_free (_buf_ptr);
69        }
70    }
71
72    uint32_t pixel_size () const {
73        return sizeof (T);
74    }
75
76    uint32_t get_width () const {
77        return _width;
78    }
79    uint32_t get_height () const {
80        return _height;
81    }
82    uint32_t get_pitch () const {
83        return _pitch;
84    }
85    bool is_valid () const {
86        return (_buf_ptr && _width && _height);
87    }
88
89    const SmartPtr<VideoBuffer> &get_bind_buf () const {
90        return _bind;
91    }
92    T *get_buf_ptr (int32_t x, int32_t y) {
93        return (T *)(_buf_ptr + y * _pitch) + x;
94    }
95    const T *get_buf_ptr (int32_t x, int32_t y) const {
96        return (const T *)(_buf_ptr + y * _pitch) + x;
97    }
98
99    inline T read_data_no_check (int32_t x, int32_t y) const {
100        const T *t_ptr = (const T *)(_buf_ptr + y * _pitch);
101        return t_ptr[x];
102    }
103
104    inline T read_data (int32_t x, int32_t y) const {
105        border_check (x, y);
106        return read_data_no_check (x, y);
107    }
108
109    template<typename O>
110    inline O read_interpolate_data (float x, float y) const;
111
112    template<typename O, uint32_t N>
113    inline void read_interpolate_array (Float2 *pos, O *array) const;
114
115    template<uint32_t N>
116    inline void read_array_no_check (const int32_t x, const int32_t y, T *array) const {
117        XCAM_ASSERT (N <= 8);
118        const T *t_ptr = ((const T *)(_buf_ptr + y * _pitch)) + x;
119        memcpy (array, t_ptr, sizeof (T) * N);
120    }
121
122    template<typename O, uint32_t N>
123    inline void read_array_no_check (const int32_t x, const int32_t y, O *array) const {
124        XCAM_ASSERT (N <= 8);
125        const T *t_ptr = ((const T *)(_buf_ptr + y * _pitch)) + x;
126        for (uint32_t i = 0; i < N; ++i) {
127            array[i] = t_ptr[i];
128        }
129    }
130
131    template<uint32_t N>
132    inline void read_array (int32_t x, int32_t y, T *array) const {
133        XCAM_ASSERT (N <= 8);
134        border_check_y (y);
135        if (x + N < _width) {
136            read_array_no_check<N> (x, y, array);
137        } else {
138            const T *t_ptr = ((const T *)(_buf_ptr + y * _pitch));
139            for (uint32_t i = 0; i < N; ++i, ++x) {
140                border_check_x (x);
141                array[i] = t_ptr[x];
142            }
143        }
144    }
145
146    template<typename O, uint32_t N>
147    inline void read_array (int32_t x, int32_t y, O *array) const {
148        XCAM_ASSERT (N <= 8);
149        border_check_y (y);
150        const T *t_ptr = ((const T *)(_buf_ptr + y * _pitch));
151        for (uint32_t i = 0; i < N; ++i, ++x) {
152            border_check_x (x);
153            array[i] = t_ptr[x];
154        }
155    }
156
157    inline void write_data (int32_t x, int32_t y, const T &v) {
158        if (x < 0 || x >= (int32_t)_width)
159            return;
160        if (y < 0 || y >= (int32_t)_height)
161            return;
162        write_data_no_check (x, y, v);
163    }
164
165    inline void write_data_no_check (int32_t x, int32_t y, const T &v) {
166        T *t_ptr = (T *)(_buf_ptr + y * _pitch);
167        t_ptr[x] = v;
168    }
169
170    template<uint32_t N>
171    inline void write_array_no_check (int32_t x, int32_t y, const T *array) {
172        T *t_ptr = (T *)(_buf_ptr + y * _pitch);
173        memcpy (t_ptr + x, array, sizeof (T) * N);
174    }
175
176    template<uint32_t N>
177    inline void write_array (int32_t x, int32_t y, const T *array) {
178        if (y < 0 || y >= (int32_t)_height)
179            return;
180
181        if (x >= 0 && x + N <= _width) {
182            write_array_no_check<N> (x, y, array);
183        } else {
184            T *t_ptr = ((T *)(_buf_ptr + y * _pitch));
185            for (uint32_t i = 0; i < N; ++i, ++x) {
186                if (x < 0 || x >= (int32_t)_width) continue;
187                t_ptr[x] = array[i];
188            }
189        }
190    }
191
192private:
193    inline void border_check_x (int32_t &x) const {
194        if (x < 0) x = 0;
195        else if (x >= (int32_t)_width) x = (int32_t)(_width - 1);
196    }
197
198    inline void border_check_y (int32_t &y) const {
199        if (y < 0) y = 0;
200        else if (y >= (int32_t)_height) y = (int32_t)(_height - 1);
201    }
202
203    inline void border_check (int32_t &x, int32_t &y) const {
204        border_check_x (x);
205        border_check_y (y);
206    }
207};
208
209
210template <typename T>
211SoftImage<T>::SoftImage (const SmartPtr<VideoBuffer> &buf, const uint32_t plane)
212    : _buf_ptr (NULL)
213    , _width (0) , _height (0) , _pitch (0)
214{
215    XCAM_ASSERT (buf.ptr ());
216    const VideoBufferInfo &info = buf->get_video_info ();
217    VideoBufferPlanarInfo planar;
218    if (!info.get_planar_info(planar, plane)) {
219        XCAM_LOG_ERROR (
220            "videobuf to soft image failed. buf format:%s, plane:%d", xcam_fourcc_to_string (info.format), plane);
221        return;
222    }
223    _buf_ptr = buf->map () + info.offsets[plane];
224    XCAM_ASSERT (_buf_ptr);
225    _pitch = info.strides[plane];
226    _height = planar.height;
227    _width = planar.pixel_bytes * planar.width / sizeof (T);
228    XCAM_ASSERT (_width * sizeof(T) == planar.pixel_bytes * planar.width);
229    _bind = buf;
230}
231
232template <typename T>
233SoftImage<T>::SoftImage (
234    const uint32_t width, const uint32_t height, uint32_t aligned_width)
235    : _buf_ptr (NULL)
236    , _width (0) , _height (0) , _pitch (0)
237{
238    if (!aligned_width)
239        aligned_width = width;
240
241    XCAM_ASSERT (aligned_width >= width);
242    XCAM_ASSERT (width > 0 && height > 0);
243    _pitch = aligned_width * sizeof (T);
244    _buf_ptr = (uint8_t *)xcam_malloc (_pitch * height);
245    XCAM_ASSERT (_buf_ptr);
246    _width = width;
247    _height = height;
248}
249
250template <typename T>
251SoftImage<T>::SoftImage (
252    const SmartPtr<VideoBuffer> &buf,
253    const uint32_t width, const uint32_t height, const uint32_t pictch, const uint32_t offset)
254    : _buf_ptr (NULL)
255    , _width (width) , _height (height)
256    , _pitch (pictch)
257    , _bind (buf)
258{
259    XCAM_ASSERT (buf.ptr ());
260    XCAM_ASSERT (buf->map ());
261    _buf_ptr = buf->map () + offset;
262}
263
264template <typename T>
265inline Uchar convert_to_uchar (const T& v) {
266    if (v < 0.0f) return 0;
267    else if (v > 255.0f) return 255;
268    return (Uchar)(v + 0.5f);
269}
270
271template <typename T, uint32_t N>
272inline void convert_to_uchar_N (const T *in, Uchar *out) {
273    for (uint32_t i = 0; i < N; ++i) {
274        out[i] = convert_to_uchar<T> (in[i]);
275    }
276}
277
278template <typename Vec2>
279inline Uchar2 convert_to_uchar2 (const Vec2& v) {
280    return Uchar2 (convert_to_uchar(v.x), convert_to_uchar(v.y));
281}
282
283template <typename Vec2, uint32_t N>
284inline void convert_to_uchar2_N (const Vec2 *in, Uchar2 *out) {
285    for (uint32_t i = 0; i < N; ++i) {
286        out[i].x = convert_to_uchar (in[i].x);
287        out[i].y = convert_to_uchar (in[i].y);
288    }
289}
290
291typedef SoftImage<Uchar> UcharImage;
292typedef SoftImage<Uchar2> Uchar2Image;
293typedef SoftImage<float> FloatImage;
294typedef SoftImage<Float2> Float2Image;
295
296template <class SoftImageT>
297class SoftImageFile
298    : public FileHandle
299{
300public:
301    SoftImageFile () {}
302    explicit SoftImageFile (const char *name, const char *option)
303        : FileHandle (name, option)
304    {}
305
306    inline XCamReturn read_buf (const SmartPtr<SoftImageT> &buf);
307    inline XCamReturn write_buf (const SmartPtr<SoftImageT> &buf);
308};
309
310template <class SoftImageT>
311inline XCamReturn
312SoftImageFile<SoftImageT>::read_buf (const SmartPtr<SoftImageT> &buf)
313{
314    XCAM_FAIL_RETURN (
315        WARNING, is_valid (), XCAM_RETURN_ERROR_PARAM,
316        "soft image file(%s) read buf failed, file is not open", XCAM_STR (get_file_name ()));
317
318    XCAM_FAIL_RETURN (
319        WARNING, buf->is_valid (), XCAM_RETURN_ERROR_PARAM,
320        "soft image file(%s) read buf failed, buf is not valid", XCAM_STR (get_file_name ()));
321
322    XCAM_ASSERT (is_valid ());
323    uint32_t height = buf->get_height ();
324    uint32_t line_bytes = buf->get_width () * buf->pixel_size ();
325
326    for (uint32_t index = 0; index < height; index++) {
327        uint8_t *line_ptr = buf->get_buf_ptr (0, index);
328        XCAM_FAIL_RETURN (
329            WARNING, fread (line_ptr, 1, line_bytes, _fp) == line_bytes, XCAM_RETURN_ERROR_FILE,
330            "soft image file(%s) read buf failed, image_line:%d", XCAM_STR (get_file_name ()), index);
331    }
332    return XCAM_RETURN_NO_ERROR;
333}
334
335template <class SoftImageT>
336inline XCamReturn
337SoftImageFile<SoftImageT>::write_buf (const SmartPtr<SoftImageT> &buf)
338{
339    XCAM_FAIL_RETURN (
340        WARNING, is_valid (), XCAM_RETURN_ERROR_PARAM,
341        "soft image file(%s) write buf failed, file is not open", XCAM_STR (get_file_name ()));
342
343    XCAM_FAIL_RETURN (
344        WARNING, buf->is_valid (), XCAM_RETURN_ERROR_PARAM,
345        "soft image file(%s) write buf failed, buf is not valid", XCAM_STR (get_file_name ()));
346
347    XCAM_ASSERT (is_valid ());
348    uint32_t height = buf->get_height ();
349    uint32_t line_bytes = buf->get_width () * buf->pixel_size ();
350
351    for (uint32_t index = 0; index < height; index++) {
352        uint8_t *line_ptr = buf->get_buf_ptr (0, index);
353        XCAM_FAIL_RETURN (
354            WARNING, fwrite (line_ptr, 1, line_bytes, _fp) == line_bytes, XCAM_RETURN_ERROR_FILE,
355            "soft image file(%s) write buf failed, image_line:%d", XCAM_STR (get_file_name ()), index);
356    }
357    return XCAM_RETURN_NO_ERROR;
358}
359
360template <typename T> template <typename O>
361O
362SoftImage<T>::read_interpolate_data (float x, float y) const
363{
364    int32_t x0 = (int32_t)(x), y0 = (int32_t)(y);
365    float a = x - x0, b = y - y0;
366    O l0[2], l1[2];
367    read_array<O, 2> (x0, y0, l0);
368    read_array<O, 2> (x0, y0 + 1, l1);
369
370    return l1[1] * (a * b) + l0[0] * ((1 - a) * (1 - b)) +
371           l1[0] * ((1 - a) * b) + l0[1] * (a * (1 - b));
372}
373
374template <typename T> template<typename O, uint32_t N>
375void
376SoftImage<T>::read_interpolate_array (Float2 *pos, O *array) const
377{
378    for (uint32_t i = 0; i < N; ++i) {
379        array[i] = read_interpolate_data<O> (pos[i].x, pos[i].y);
380    }
381}
382
383}
384#endif //XCAM_SOFT_IMAGE_H
385