/*
* soft_image.h - soft image class
*
* Copyright (c) 2017 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*
* Author: Wind Yuan <feng.yuan@intel.com>
*/
#ifndef XCAM_SOFT_IMAGE_H
#define XCAM_SOFT_IMAGE_H
#include <xcam_std.h>
#include <video_buffer.h>
#include <vec_mat.h>
#include <file_handle.h>
namespace XCam {
typedef uint8_t Uchar;
typedef int8_t Char;
typedef Vector2<uint8_t> Uchar2;
typedef Vector2<int8_t> Char2;
typedef Vector2<float> Float2;
typedef Vector2<int> Int2;
enum BorderType {
BorderTypeNearest,
BorderTypeConst,
BorderTypeRewind,
};
template <typename T>
class SoftImage
{
public:
typedef T Type;
private:
uint8_t *_buf_ptr;
uint32_t _width;
uint32_t _height;
uint32_t _pitch;
SmartPtr<VideoBuffer> _bind;
public:
explicit SoftImage (const SmartPtr<VideoBuffer> &buf, const uint32_t plane);
explicit SoftImage (
const uint32_t width, const uint32_t height,
uint32_t aligned_width = 0);
explicit SoftImage (
const SmartPtr<VideoBuffer> &buf,
const uint32_t width, const uint32_t height, const uint32_t pictch, const uint32_t offset = 0);
~SoftImage () {
if (!_bind.ptr ()) {
xcam_free (_buf_ptr);
}
}
uint32_t pixel_size () const {
return sizeof (T);
}
uint32_t get_width () const {
return _width;
}
uint32_t get_height () const {
return _height;
}
uint32_t get_pitch () const {
return _pitch;
}
bool is_valid () const {
return (_buf_ptr && _width && _height);
}
const SmartPtr<VideoBuffer> &get_bind_buf () const {
return _bind;
}
T *get_buf_ptr (int32_t x, int32_t y) {
return (T *)(_buf_ptr + y * _pitch) + x;
}
const T *get_buf_ptr (int32_t x, int32_t y) const {
return (const T *)(_buf_ptr + y * _pitch) + x;
}
inline T read_data_no_check (int32_t x, int32_t y) const {
const T *t_ptr = (const T *)(_buf_ptr + y * _pitch);
return t_ptr[x];
}
inline T read_data (int32_t x, int32_t y) const {
border_check (x, y);
return read_data_no_check (x, y);
}
template<typename O>
inline O read_interpolate_data (float x, float y) const;
template<typename O, uint32_t N>
inline void read_interpolate_array (Float2 *pos, O *array) const;
template<uint32_t N>
inline void read_array_no_check (const int32_t x, const int32_t y, T *array) const {
XCAM_ASSERT (N <= 8);
const T *t_ptr = ((const T *)(_buf_ptr + y * _pitch)) + x;
memcpy (array, t_ptr, sizeof (T) * N);
}
template<typename O, uint32_t N>
inline void read_array_no_check (const int32_t x, const int32_t y, O *array) const {
XCAM_ASSERT (N <= 8);
const T *t_ptr = ((const T *)(_buf_ptr + y * _pitch)) + x;
for (uint32_t i = 0; i < N; ++i) {
array[i] = t_ptr[i];
}
}
template<uint32_t N>
inline void read_array (int32_t x, int32_t y, T *array) const {
XCAM_ASSERT (N <= 8);
border_check_y (y);
if (x + N < _width) {
read_array_no_check<N> (x, y, array);
} else {
const T *t_ptr = ((const T *)(_buf_ptr + y * _pitch));
for (uint32_t i = 0; i < N; ++i, ++x) {
border_check_x (x);
array[i] = t_ptr[x];
}
}
}
template<typename O, uint32_t N>
inline void read_array (int32_t x, int32_t y, O *array) const {
XCAM_ASSERT (N <= 8);
border_check_y (y);
const T *t_ptr = ((const T *)(_buf_ptr + y * _pitch));
for (uint32_t i = 0; i < N; ++i, ++x) {
border_check_x (x);
array[i] = t_ptr[x];
}
}
inline void write_data (int32_t x, int32_t y, const T &v) {
if (x < 0 || x >= (int32_t)_width)
return;
if (y < 0 || y >= (int32_t)_height)
return;
write_data_no_check (x, y, v);
}
inline void write_data_no_check (int32_t x, int32_t y, const T &v) {
T *t_ptr = (T *)(_buf_ptr + y * _pitch);
t_ptr[x] = v;
}
template<uint32_t N>
inline void write_array_no_check (int32_t x, int32_t y, const T *array) {
T *t_ptr = (T *)(_buf_ptr + y * _pitch);
memcpy (t_ptr + x, array, sizeof (T) * N);
}
template<uint32_t N>
inline void write_array (int32_t x, int32_t y, const T *array) {
if (y < 0 || y >= (int32_t)_height)
return;
if (x >= 0 && x + N <= _width) {
write_array_no_check<N> (x, y, array);
} else {
T *t_ptr = ((T *)(_buf_ptr + y * _pitch));
for (uint32_t i = 0; i < N; ++i, ++x) {
if (x < 0 || x >= (int32_t)_width) continue;
t_ptr[x] = array[i];
}
}
}
private:
inline void border_check_x (int32_t &x) const {
if (x < 0) x = 0;
else if (x >= (int32_t)_width) x = (int32_t)(_width - 1);
}
inline void border_check_y (int32_t &y) const {
if (y < 0) y = 0;
else if (y >= (int32_t)_height) y = (int32_t)(_height - 1);
}
inline void border_check (int32_t &x, int32_t &y) const {
border_check_x (x);
border_check_y (y);
}
};
template <typename T>
SoftImage<T>::SoftImage (const SmartPtr<VideoBuffer> &buf, const uint32_t plane)
: _buf_ptr (NULL)
, _width (0) , _height (0) , _pitch (0)
{
XCAM_ASSERT (buf.ptr ());
const VideoBufferInfo &info = buf->get_video_info ();
VideoBufferPlanarInfo planar;
if (!info.get_planar_info(planar, plane)) {
XCAM_LOG_ERROR (
"videobuf to soft image failed. buf format:%s, plane:%d", xcam_fourcc_to_string (info.format), plane);
return;
}
_buf_ptr = buf->map () + info.offsets[plane];
XCAM_ASSERT (_buf_ptr);
_pitch = info.strides[plane];
_height = planar.height;
_width = planar.pixel_bytes * planar.width / sizeof (T);
XCAM_ASSERT (_width * sizeof(T) == planar.pixel_bytes * planar.width);
_bind = buf;
}
template <typename T>
SoftImage<T>::SoftImage (
const uint32_t width, const uint32_t height, uint32_t aligned_width)
: _buf_ptr (NULL)
, _width (0) , _height (0) , _pitch (0)
{
if (!aligned_width)
aligned_width = width;
XCAM_ASSERT (aligned_width >= width);
XCAM_ASSERT (width > 0 && height > 0);
_pitch = aligned_width * sizeof (T);
_buf_ptr = (uint8_t *)xcam_malloc (_pitch * height);
XCAM_ASSERT (_buf_ptr);
_width = width;
_height = height;
}
template <typename T>
SoftImage<T>::SoftImage (
const SmartPtr<VideoBuffer> &buf,
const uint32_t width, const uint32_t height, const uint32_t pictch, const uint32_t offset)
: _buf_ptr (NULL)
, _width (width) , _height (height)
, _pitch (pictch)
, _bind (buf)
{
XCAM_ASSERT (buf.ptr ());
XCAM_ASSERT (buf->map ());
_buf_ptr = buf->map () + offset;
}
template <typename T>
inline Uchar convert_to_uchar (const T& v) {
if (v < 0.0f) return 0;
else if (v > 255.0f) return 255;
return (Uchar)(v + 0.5f);
}
template <typename T, uint32_t N>
inline void convert_to_uchar_N (const T *in, Uchar *out) {
for (uint32_t i = 0; i < N; ++i) {
out[i] = convert_to_uchar<T> (in[i]);
}
}
template <typename Vec2>
inline Uchar2 convert_to_uchar2 (const Vec2& v) {
return Uchar2 (convert_to_uchar(v.x), convert_to_uchar(v.y));
}
template <typename Vec2, uint32_t N>
inline void convert_to_uchar2_N (const Vec2 *in, Uchar2 *out) {
for (uint32_t i = 0; i < N; ++i) {
out[i].x = convert_to_uchar (in[i].x);
out[i].y = convert_to_uchar (in[i].y);
}
}
typedef SoftImage<Uchar> UcharImage;
typedef SoftImage<Uchar2> Uchar2Image;
typedef SoftImage<float> FloatImage;
typedef SoftImage<Float2> Float2Image;
template <class SoftImageT>
class SoftImageFile
: public FileHandle
{
public:
SoftImageFile () {}
explicit SoftImageFile (const char *name, const char *option)
: FileHandle (name, option)
{}
inline XCamReturn read_buf (const SmartPtr<SoftImageT> &buf);
inline XCamReturn write_buf (const SmartPtr<SoftImageT> &buf);
};
template <class SoftImageT>
inline XCamReturn
SoftImageFile<SoftImageT>::read_buf (const SmartPtr<SoftImageT> &buf)
{
XCAM_FAIL_RETURN (
WARNING, is_valid (), XCAM_RETURN_ERROR_PARAM,
"soft image file(%s) read buf failed, file is not open", XCAM_STR (get_file_name ()));
XCAM_FAIL_RETURN (
WARNING, buf->is_valid (), XCAM_RETURN_ERROR_PARAM,
"soft image file(%s) read buf failed, buf is not valid", XCAM_STR (get_file_name ()));
XCAM_ASSERT (is_valid ());
uint32_t height = buf->get_height ();
uint32_t line_bytes = buf->get_width () * buf->pixel_size ();
for (uint32_t index = 0; index < height; index++) {
uint8_t *line_ptr = buf->get_buf_ptr (0, index);
XCAM_FAIL_RETURN (
WARNING, fread (line_ptr, 1, line_bytes, _fp) == line_bytes, XCAM_RETURN_ERROR_FILE,
"soft image file(%s) read buf failed, image_line:%d", XCAM_STR (get_file_name ()), index);
}
return XCAM_RETURN_NO_ERROR;
}
template <class SoftImageT>
inline XCamReturn
SoftImageFile<SoftImageT>::write_buf (const SmartPtr<SoftImageT> &buf)
{
XCAM_FAIL_RETURN (
WARNING, is_valid (), XCAM_RETURN_ERROR_PARAM,
"soft image file(%s) write buf failed, file is not open", XCAM_STR (get_file_name ()));
XCAM_FAIL_RETURN (
WARNING, buf->is_valid (), XCAM_RETURN_ERROR_PARAM,
"soft image file(%s) write buf failed, buf is not valid", XCAM_STR (get_file_name ()));
XCAM_ASSERT (is_valid ());
uint32_t height = buf->get_height ();
uint32_t line_bytes = buf->get_width () * buf->pixel_size ();
for (uint32_t index = 0; index < height; index++) {
uint8_t *line_ptr = buf->get_buf_ptr (0, index);
XCAM_FAIL_RETURN (
WARNING, fwrite (line_ptr, 1, line_bytes, _fp) == line_bytes, XCAM_RETURN_ERROR_FILE,
"soft image file(%s) write buf failed, image_line:%d", XCAM_STR (get_file_name ()), index);
}
return XCAM_RETURN_NO_ERROR;
}
template <typename T> template <typename O>
O
SoftImage<T>::read_interpolate_data (float x, float y) const
{
int32_t x0 = (int32_t)(x), y0 = (int32_t)(y);
float a = x - x0, b = y - y0;
O l0[2], l1[2];
read_array<O, 2> (x0, y0, l0);
read_array<O, 2> (x0, y0 + 1, l1);
return l1[1] * (a * b) + l0[0] * ((1 - a) * (1 - b)) +
l1[0] * ((1 - a) * b) + l0[1] * (a * (1 - b));
}
template <typename T> template<typename O, uint32_t N>
void
SoftImage<T>::read_interpolate_array (Float2 *pos, O *array) const
{
for (uint32_t i = 0; i < N; ++i) {
array[i] = read_interpolate_data<O> (pos[i].x, pos[i].y);
}
}
}
#endif //XCAM_SOFT_IMAGE_H