/**
 * @file
 *
 * @brief Public APIs for Video.
 */

/*
 * Copyright (c) 2019 Linaro Limited.
 *
 * SPDX-License-Identifier: Apache-2.0
 */
#ifndef ZEPHYR_INCLUDE_VIDEO_H_
#define ZEPHYR_INCLUDE_VIDEO_H_

/**
 * @brief Video Interface
 * @defgroup video_interface Video Interface
 * @since 2.1
 * @version 1.1.0
 * @ingroup io_interfaces
 * @{
 */

#include <zephyr/device.h>
#include <stddef.h>
#include <zephyr/kernel.h>

#include <zephyr/types.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Flag used by @ref video_caps structure to indicate endpoint operates on
 * buffers the size of the video frame
 */
#define LINE_COUNT_HEIGHT (-1)

/**
 * @struct video_format
 * @brief Video format structure
 *
 * Used to configure frame format.
 */
struct video_format {
	/** FourCC pixel format value (\ref video_pixel_formats) */
	uint32_t pixelformat;
	/** frame width in pixels. */
	uint32_t width;
	/** frame height in pixels. */
	uint32_t height;
	/**
	 * @brief line stride.
	 *
	 * This is the number of bytes that needs to be added to the address in the
	 * first pixel of a row in order to go to the address of the first pixel of
	 * the next row (>=width).
	 */
	uint32_t pitch;
};

/**
 * @struct video_format_cap
 * @brief Video format capability
 *
 * Used to describe a video endpoint format capability.
 */
struct video_format_cap {
	/** FourCC pixel format value (\ref video_pixel_formats). */
	uint32_t pixelformat;
	/** minimum supported frame width in pixels. */
	uint32_t width_min;
	/** maximum supported frame width in pixels. */
	uint32_t width_max;
	/** minimum supported frame height in pixels. */
	uint32_t height_min;
	/** maximum supported frame height in pixels. */
	uint32_t height_max;
	/** width step size in pixels. */
	uint16_t width_step;
	/** height step size in pixels. */
	uint16_t height_step;
};

/**
 * @struct video_caps
 * @brief Video format capabilities
 *
 * Used to describe video endpoint capabilities.
 */
struct video_caps {
	/** list of video format capabilities (zero terminated). */
	const struct video_format_cap *format_caps;
	/** minimal count of video buffers to enqueue before being able to start
	 * the stream.
	 */
	uint8_t min_vbuf_count;
	/** Denotes minimum line count of a video buffer that this endpoint
	 * can fill or process. Each line is expected to consume the number
	 * of bytes the selected video format's pitch uses, so the video
	 * buffer must be at least `pitch` * `min_line_count` bytes.
	 * `LINE_COUNT_HEIGHT` is a special value, indicating the endpoint
	 * only supports video buffers with at least enough bytes to store
	 * a full video frame
	 */
	int16_t min_line_count;
	/**
	 * Denotes maximum line count of a video buffer that this endpoint
	 * can fill or process. Similar constraints to `min_line_count`,
	 * but `LINE_COUNT_HEIGHT` indicates that the endpoint will never
	 * fill or process more than a full video frame in one video buffer.
	 */
	int16_t max_line_count;
};

/**
 * @struct video_buffer
 * @brief Video buffer structure
 *
 * Represent a video frame.
 */
struct video_buffer {
	/** pointer to driver specific data. */
	void *driver_data;
	/** pointer to the start of the buffer. */
	uint8_t *buffer;
	/** size of the buffer in bytes. */
	uint32_t size;
	/** number of bytes occupied by the valid data in the buffer. */
	uint32_t bytesused;
	/** time reference in milliseconds at which the last data byte was
	 * actually received for input endpoints or to be consumed for output
	 * endpoints.
	 */
	uint32_t timestamp;
	/** Line offset within frame this buffer represents, from the
	 * beginning of the frame. This offset is given in pixels,
	 * so `line_offset` * `pitch` provides offset from the start of
	 * the frame in bytes.
	 */
	uint16_t line_offset;
};

/**
 * @brief video_frmival_type enum
 *
 * Supported frame interval type of a video device.
 */
enum video_frmival_type {
	/** discrete frame interval type */
	VIDEO_FRMIVAL_TYPE_DISCRETE = 1,
	/** stepwise frame interval type */
	VIDEO_FRMIVAL_TYPE_STEPWISE = 2,
};

/**
 * @struct video_frmival
 * @brief Video frame interval structure
 *
 * Used to describe a video frame interval.
 */
struct video_frmival {
	/** numerator of the frame interval */
	uint32_t numerator;
	/** denominator of the frame interval */
	uint32_t denominator;
};

/**
 * @struct video_frmival_stepwise
 * @brief Video frame interval stepwise structure
 *
 * Used to describe the video frame interval stepwise type.
 */
struct video_frmival_stepwise {
	/** minimum frame interval in seconds */
	struct video_frmival min;
	/** maximum frame interval in seconds */
	struct video_frmival max;
	/** frame interval step size in seconds */
	struct video_frmival step;
};

/**
 * @struct video_frmival_enum
 * @brief Video frame interval enumeration structure
 *
 * Used to describe the supported video frame intervals of a given video format.
 */
struct video_frmival_enum {
	/** frame interval index during enumeration */
	uint32_t index;
	/** video format for which the query is made */
	const struct video_format *format;
	/** frame interval type the device supports */
	enum video_frmival_type type;
	/** the actual frame interval */
	union {
		struct video_frmival discrete;
		struct video_frmival_stepwise stepwise;
	};
};

/**
 * @brief video_endpoint_id enum
 *
 * Identify the video device endpoint.
 */
enum video_endpoint_id {
	/** Targets some part of the video device not bound to an endpoint */
	VIDEO_EP_NONE = -1,
	/** Targets all input or output endpoints of the device */
	VIDEO_EP_ALL = -2,
	/** Targets all input endpoints of the device: those consuming data */
	VIDEO_EP_IN = -3,
	/** Targets all output endpoints of the device: those producing data */
	VIDEO_EP_OUT = -4,
};

/**
 * @brief video_event enum
 *
 * Identify video event.
 */
enum video_signal_result {
	VIDEO_BUF_DONE,
	VIDEO_BUF_ABORTED,
	VIDEO_BUF_ERROR,
};

/**
 * @typedef video_api_set_format_t
 * @brief Set video format
 *
 * See video_set_format() for argument descriptions.
 */
typedef int (*video_api_set_format_t)(const struct device *dev, enum video_endpoint_id ep,
				      struct video_format *fmt);

/**
 * @typedef video_api_get_format_t
 * @brief Get current video format
 *
 * See video_get_format() for argument descriptions.
 */
typedef int (*video_api_get_format_t)(const struct device *dev, enum video_endpoint_id ep,
				      struct video_format *fmt);

/**
 * @typedef video_api_set_frmival_t
 * @brief Set video frame interval
 *
 * See video_set_frmival() for argument descriptions.
 */
typedef int (*video_api_set_frmival_t)(const struct device *dev, enum video_endpoint_id ep,
				       struct video_frmival *frmival);

/**
 * @typedef video_api_get_frmival_t
 * @brief Get current video frame interval
 *
 * See video_get_frmival() for argument descriptions.
 */
typedef int (*video_api_get_frmival_t)(const struct device *dev, enum video_endpoint_id ep,
				       struct video_frmival *frmival);

/**
 * @typedef video_api_enum_frmival_t
 * @brief List all supported frame intervals of a given format
 *
 * See video_enum_frmival() for argument descriptions.
 */
typedef int (*video_api_enum_frmival_t)(const struct device *dev, enum video_endpoint_id ep,
					struct video_frmival_enum *fie);

/**
 * @typedef video_api_enqueue_t
 * @brief Enqueue a buffer in the driver’s incoming queue.
 *
 * See video_enqueue() for argument descriptions.
 */
typedef int (*video_api_enqueue_t)(const struct device *dev, enum video_endpoint_id ep,
				   struct video_buffer *buf);

/**
 * @typedef video_api_dequeue_t
 * @brief Dequeue a buffer from the driver’s outgoing queue.
 *
 * See video_dequeue() for argument descriptions.
 */
typedef int (*video_api_dequeue_t)(const struct device *dev, enum video_endpoint_id ep,
				   struct video_buffer **buf, k_timeout_t timeout);

/**
 * @typedef video_api_flush_t
 * @brief Flush endpoint buffers, buffer are moved from incoming queue to
 *        outgoing queue.
 *
 * See video_flush() for argument descriptions.
 */
typedef int (*video_api_flush_t)(const struct device *dev, enum video_endpoint_id ep, bool cancel);

/**
 * @typedef video_api_stream_start_t
 * @brief Start the capture or output process.
 *
 * See video_stream_start() for argument descriptions.
 */
typedef int (*video_api_stream_start_t)(const struct device *dev);

/**
 * @typedef video_api_stream_stop_t
 * @brief Stop the capture or output process.
 *
 * See video_stream_stop() for argument descriptions.
 */
typedef int (*video_api_stream_stop_t)(const struct device *dev);

/**
 * @typedef video_api_set_ctrl_t
 * @brief Set a video control value.
 *
 * See video_set_ctrl() for argument descriptions.
 */
typedef int (*video_api_set_ctrl_t)(const struct device *dev, unsigned int cid, void *value);

/**
 * @typedef video_api_get_ctrl_t
 * @brief Get a video control value.
 *
 * See video_get_ctrl() for argument descriptions.
 */
typedef int (*video_api_get_ctrl_t)(const struct device *dev, unsigned int cid, void *value);

/**
 * @typedef video_api_get_caps_t
 * @brief Get capabilities of a video endpoint.
 *
 * See video_get_caps() for argument descriptions.
 */
typedef int (*video_api_get_caps_t)(const struct device *dev, enum video_endpoint_id ep,
				    struct video_caps *caps);

/**
 * @typedef video_api_set_signal_t
 * @brief Register/Unregister poll signal for buffer events.
 *
 * See video_set_signal() for argument descriptions.
 */
typedef int (*video_api_set_signal_t)(const struct device *dev, enum video_endpoint_id ep,
				      struct k_poll_signal *signal);

__subsystem struct video_driver_api {
	/* mandatory callbacks */
	video_api_set_format_t set_format;
	video_api_get_format_t get_format;
	video_api_stream_start_t stream_start;
	video_api_stream_stop_t stream_stop;
	video_api_get_caps_t get_caps;
	/* optional callbacks */
	video_api_enqueue_t enqueue;
	video_api_dequeue_t dequeue;
	video_api_flush_t flush;
	video_api_set_ctrl_t set_ctrl;
	video_api_get_ctrl_t get_ctrl;
	video_api_set_signal_t set_signal;
	video_api_set_frmival_t set_frmival;
	video_api_get_frmival_t get_frmival;
	video_api_enum_frmival_t enum_frmival;
};

/**
 * @brief Set video format.
 *
 * Configure video device with a specific format.
 *
 * @param dev Pointer to the device structure for the driver instance.
 * @param ep Endpoint ID.
 * @param fmt Pointer to a video format struct.
 *
 * @retval 0 Is successful.
 * @retval -EINVAL If parameters are invalid.
 * @retval -ENOTSUP If format is not supported.
 * @retval -EIO General input / output error.
 */
static inline int video_set_format(const struct device *dev, enum video_endpoint_id ep,
				   struct video_format *fmt)
{
	const struct video_driver_api *api = (const struct video_driver_api *)dev->api;

	if (api->set_format == NULL) {
		return -ENOSYS;
	}

	return api->set_format(dev, ep, fmt);
}

/**
 * @brief Get video format.
 *
 * Get video device current video format.
 *
 * @param dev Pointer to the device structure for the driver instance.
 * @param ep Endpoint ID.
 * @param fmt Pointer to video format struct.
 *
 * @retval pointer to video format
 */
static inline int video_get_format(const struct device *dev, enum video_endpoint_id ep,
				   struct video_format *fmt)
{
	const struct video_driver_api *api = (const struct video_driver_api *)dev->api;

	if (api->get_format == NULL) {
		return -ENOSYS;
	}

	return api->get_format(dev, ep, fmt);
}

/**
 * @brief Set video frame interval.
 *
 * Configure video device with a specific frame interval.
 *
 * Drivers must not return an error solely because the requested interval doesn’t match the device
 * capabilities. They must instead modify the interval to match what the hardware can provide.
 *
 * @param dev Pointer to the device structure for the driver instance.
 * @param ep Endpoint ID.
 * @param frmival Pointer to a video frame interval struct.
 *
 * @retval 0 If successful.
 * @retval -ENOSYS If API is not implemented.
 * @retval -EINVAL If parameters are invalid.
 * @retval -EIO General input / output error.
 */
static inline int video_set_frmival(const struct device *dev, enum video_endpoint_id ep,
				    struct video_frmival *frmival)
{
	const struct video_driver_api *api = (const struct video_driver_api *)dev->api;

	if (api->set_frmival == NULL) {
		return -ENOSYS;
	}

	return api->set_frmival(dev, ep, frmival);
}

/**
 * @brief Get video frame interval.
 *
 * Get current frame interval of the video device.
 *
 * @param dev Pointer to the device structure for the driver instance.
 * @param ep Endpoint ID.
 * @param frmival Pointer to a video frame interval struct.
 *
 * @retval 0 If successful.
 * @retval -ENOSYS If API is not implemented.
 * @retval -EINVAL If parameters are invalid.
 * @retval -EIO General input / output error.
 */
static inline int video_get_frmival(const struct device *dev, enum video_endpoint_id ep,
				    struct video_frmival *frmival)
{
	const struct video_driver_api *api = (const struct video_driver_api *)dev->api;

	if (api->get_frmival == NULL) {
		return -ENOSYS;
	}

	return api->get_frmival(dev, ep, frmival);
}

/**
 * @brief List video frame intervals.
 *
 * List all supported video frame intervals of a given format.
 *
 * Applications should fill the pixelformat, width and height fields of the
 * video_frmival_enum struct first to form a query. Then, the index field is
 * used to iterate through the supported frame intervals list.
 *
 * @param dev Pointer to the device structure for the driver instance.
 * @param ep Endpoint ID.
 * @param fie Pointer to a video frame interval enumeration struct.
 *
 * @retval 0 If successful.
 * @retval -ENOSYS If API is not implemented.
 * @retval -EINVAL If parameters are invalid.
 * @retval -EIO General input / output error.
 */
static inline int video_enum_frmival(const struct device *dev, enum video_endpoint_id ep,
				     struct video_frmival_enum *fie)
{
	const struct video_driver_api *api = (const struct video_driver_api *)dev->api;

	if (api->enum_frmival == NULL) {
		return -ENOSYS;
	}

	return api->enum_frmival(dev, ep, fie);
}

/**
 * @brief Enqueue a video buffer.
 *
 * Enqueue an empty (capturing) or filled (output) video buffer in the driver’s
 * endpoint incoming queue.
 *
 * @param dev Pointer to the device structure for the driver instance.
 * @param ep Endpoint ID.
 * @param buf Pointer to the video buffer.
 *
 * @retval 0 Is successful.
 * @retval -EINVAL If parameters are invalid.
 * @retval -EIO General input / output error.
 */
static inline int video_enqueue(const struct device *dev, enum video_endpoint_id ep,
				struct video_buffer *buf)
{
	const struct video_driver_api *api = (const struct video_driver_api *)dev->api;

	if (api->enqueue == NULL) {
		return -ENOSYS;
	}

	return api->enqueue(dev, ep, buf);
}

/**
 * @brief Dequeue a video buffer.
 *
 * Dequeue a filled (capturing) or displayed (output) buffer from the driver’s
 * endpoint outgoing queue.
 *
 * @param dev Pointer to the device structure for the driver instance.
 * @param ep Endpoint ID.
 * @param buf Pointer a video buffer pointer.
 * @param timeout Timeout
 *
 * @retval 0 Is successful.
 * @retval -EINVAL If parameters are invalid.
 * @retval -EIO General input / output error.
 */
static inline int video_dequeue(const struct device *dev, enum video_endpoint_id ep,
				struct video_buffer **buf, k_timeout_t timeout)
{
	const struct video_driver_api *api = (const struct video_driver_api *)dev->api;

	if (api->dequeue == NULL) {
		return -ENOSYS;
	}

	return api->dequeue(dev, ep, buf, timeout);
}

/**
 * @brief Flush endpoint buffers.
 *
 * A call to flush finishes when all endpoint buffers have been moved from
 * incoming queue to outgoing queue. Either because canceled or fully processed
 * through the video function.
 *
 * @param dev Pointer to the device structure for the driver instance.
 * @param ep Endpoint ID.
 * @param cancel If true, cancel buffer processing instead of waiting for
 *        completion.
 *
 * @retval 0 Is successful, -ERRNO code otherwise.
 */
static inline int video_flush(const struct device *dev, enum video_endpoint_id ep, bool cancel)
{
	const struct video_driver_api *api = (const struct video_driver_api *)dev->api;

	if (api->flush == NULL) {
		return -ENOSYS;
	}

	return api->flush(dev, ep, cancel);
}

/**
 * @brief Start the video device function.
 *
 * video_stream_start is called to enter ‘streaming’ state (capture, output...).
 * The driver may receive buffers with video_enqueue() before video_stream_start
 * is called. If driver/device needs a minimum number of buffers before being
 * able to start streaming, then driver set the min_vbuf_count to the related
 * endpoint capabilities.
 *
 * @retval 0 Is successful.
 * @retval -EIO General input / output error.
 */
static inline int video_stream_start(const struct device *dev)
{
	const struct video_driver_api *api = (const struct video_driver_api *)dev->api;

	if (api->stream_start == NULL) {
		return -ENOSYS;
	}

	return api->stream_start(dev);
}

/**
 * @brief Stop the video device function.
 *
 * On video_stream_stop, driver must stop any transactions or wait until they
 * finish.
 *
 * @retval 0 Is successful.
 * @retval -EIO General input / output error.
 */
static inline int video_stream_stop(const struct device *dev)
{
	const struct video_driver_api *api = (const struct video_driver_api *)dev->api;
	int ret;

	if (api->stream_stop == NULL) {
		return -ENOSYS;
	}

	ret = api->stream_stop(dev);
	video_flush(dev, VIDEO_EP_ALL, true);

	return ret;
}

/**
 * @brief Get the capabilities of a video endpoint.
 *
 * @param dev Pointer to the device structure for the driver instance.
 * @param ep Endpoint ID.
 * @param caps Pointer to the video_caps struct to fill.
 *
 * @retval 0 Is successful, -ERRNO code otherwise.
 */
static inline int video_get_caps(const struct device *dev, enum video_endpoint_id ep,
				 struct video_caps *caps)
{
	const struct video_driver_api *api = (const struct video_driver_api *)dev->api;

	if (api->get_caps == NULL) {
		return -ENOSYS;
	}

	return api->get_caps(dev, ep, caps);
}

/**
 * @brief Set the value of a control.
 *
 * This set the value of a video control, value type depends on control ID, and
 * must be interpreted accordingly.
 *
 * @param dev Pointer to the device structure for the driver instance.
 * @param cid Control ID.
 * @param value Pointer to the control value.
 *
 * @retval 0 Is successful.
 * @retval -EINVAL If parameters are invalid.
 * @retval -ENOTSUP If format is not supported.
 * @retval -EIO General input / output error.
 */
static inline int video_set_ctrl(const struct device *dev, unsigned int cid, void *value)
{
	const struct video_driver_api *api = (const struct video_driver_api *)dev->api;

	if (api->set_ctrl == NULL) {
		return -ENOSYS;
	}

	return api->set_ctrl(dev, cid, value);
}

/**
 * @brief Get the current value of a control.
 *
 * This retrieve the value of a video control, value type depends on control ID,
 * and must be interpreted accordingly.
 *
 * @param dev Pointer to the device structure for the driver instance.
 * @param cid Control ID.
 * @param value Pointer to the control value.
 *
 * @retval 0 Is successful.
 * @retval -EINVAL If parameters are invalid.
 * @retval -ENOTSUP If format is not supported.
 * @retval -EIO General input / output error.
 */
static inline int video_get_ctrl(const struct device *dev, unsigned int cid, void *value)
{
	const struct video_driver_api *api = (const struct video_driver_api *)dev->api;

	if (api->get_ctrl == NULL) {
		return -ENOSYS;
	}

	return api->get_ctrl(dev, cid, value);
}

/**
 * @brief Register/Unregister k_poll signal for a video endpoint.
 *
 * Register a poll signal to the endpoint, which will be signaled on frame
 * completion (done, aborted, error). Registering a NULL poll signal
 * unregisters any previously registered signal.
 *
 * @param dev Pointer to the device structure for the driver instance.
 * @param ep Endpoint ID.
 * @param signal Pointer to k_poll_signal
 *
 * @retval 0 Is successful, -ERRNO code otherwise.
 */
static inline int video_set_signal(const struct device *dev, enum video_endpoint_id ep,
				   struct k_poll_signal *signal)
{
	const struct video_driver_api *api = (const struct video_driver_api *)dev->api;

	if (api->set_signal == NULL) {
		return -ENOSYS;
	}

	return api->set_signal(dev, ep, signal);
}

/**
 * @brief Allocate aligned video buffer.
 *
 * @param size Size of the video buffer (in bytes).
 * @param align Alignment of the requested memory, must be a power of two.
 * @param timeout Timeout duration or K_NO_WAIT
 *
 * @retval pointer to allocated video buffer
 */
struct video_buffer *video_buffer_aligned_alloc(size_t size, size_t align, k_timeout_t timeout);

/**
 * @brief Allocate video buffer.
 *
 * @param size Size of the video buffer (in bytes).
 * @param timeout Timeout duration or K_NO_WAIT
 *
 * @retval pointer to allocated video buffer
 */
struct video_buffer *video_buffer_alloc(size_t size, k_timeout_t timeout);

/**
 * @brief Release a video buffer.
 *
 * @param buf Pointer to the video buffer to release.
 */
void video_buffer_release(struct video_buffer *buf);

/**
 * @brief Search for a format that matches in a list of capabilities
 *
 * @param fmts The format capability list to search.
 * @param fmt The format to find in the list.
 * @param idx The pointer to a number of the first format that matches.
 *
 * @return 0 when a format is found.
 * @return -ENOENT when no matching format is found.
 */
int video_format_caps_index(const struct video_format_cap *fmts, const struct video_format *fmt,
			    size_t *idx);

/**
 * @brief Compute the difference between two frame intervals
 *
 * @param frmival Frame interval to turn into microseconds.
 *
 * @return The frame interval value in microseconds.
 */
static inline uint64_t video_frmival_nsec(const struct video_frmival *frmival)
{
	return (uint64_t)NSEC_PER_SEC * frmival->numerator / frmival->denominator;
}

/**
 * @brief Find the closest match to a frame interval value within a stepwise frame interval.
 *
 * @param stepwise The stepwise frame interval range to search
 * @param desired The frame interval for which find the closest match
 * @param match The resulting frame interval closest to @p desired
 */
void video_closest_frmival_stepwise(const struct video_frmival_stepwise *stepwise,
				    const struct video_frmival *desired,
				    struct video_frmival *match);

/**
 * @brief Find the closest match to a frame interval value within a video device.
 *
 * To compute the closest match, fill @p match with the following fields:
 *
 * - @c match->format to the @ref video_format of interest.
 * - @c match->type to @ref VIDEO_FRMIVAL_TYPE_DISCRETE.
 * - @c match->discrete to the desired frame interval.
 *
 * The result will be loaded into @p match, with the following fields set:
 *
 * - @c match->discrete to the value of the closest frame interval.
 * - @c match->index to the index of the closest frame interval.
 *
 * @param dev Video device to query.
 * @param ep Video endpoint ID to query.
 * @param match Frame interval enumerator with the query, and loaded with the result.
 */
void video_closest_frmival(const struct device *dev, enum video_endpoint_id ep,
			   struct video_frmival_enum *match);

/* fourcc - four-character-code */
#define video_fourcc(a, b, c, d)                                                                   \
	((uint32_t)(a) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))

/**
 * @defgroup video_pixel_formats Video pixel formats
 * @{
 */

/**
 * @name Bayer formats
 * @{
 */

/** BGGR8 pixel format */
#define VIDEO_PIX_FMT_BGGR8 video_fourcc('B', 'G', 'G', 'R') /*  8  BGBG.. GRGR.. */
/** GBRG8 pixel format */
#define VIDEO_PIX_FMT_GBRG8 video_fourcc('G', 'B', 'R', 'G') /*  8  GBGB.. RGRG.. */
/** GRBG8 pixel format */
#define VIDEO_PIX_FMT_GRBG8 video_fourcc('G', 'R', 'B', 'G') /*  8  GRGR.. BGBG.. */
/** RGGB8 pixel format */
#define VIDEO_PIX_FMT_RGGB8 video_fourcc('R', 'G', 'G', 'B') /*  8  RGRG.. GBGB.. */

/**
 * @}
 */

/**
 * @name RGB formats
 * @{
 */

/** RGB565 pixel format */
#define VIDEO_PIX_FMT_RGB565 video_fourcc('R', 'G', 'B', 'P') /* 16  RGB-5-6-5 */

/** XRGB32 pixel format */
#define VIDEO_PIX_FMT_XRGB32 video_fourcc('B', 'X', '2', '4') /* 32  XRGB-8-8-8-8 */

/**
 * @}
 */

/**
 * @name YUV formats
 * @{
 */

/** YUYV pixel format */
#define VIDEO_PIX_FMT_YUYV video_fourcc('Y', 'U', 'Y', 'V') /* 16  Y0-Cb0 Y1-Cr0 */

/** XYUV32 pixel format */
#define VIDEO_PIX_FMT_XYUV32 video_fourcc('X', 'Y', 'U', 'V') /* 32  XYUV-8-8-8-8 */

/**
 *
 * @}
 */

/**
 * @name JPEG formats
 * @{
 */

/** JPEG pixel format */
#define VIDEO_PIX_FMT_JPEG video_fourcc('J', 'P', 'E', 'G') /*  8  JPEG */

/**
 * @}
 */

/**
 * @}
 */

/**
 * @brief Get number of bytes per pixel of a pixel format
 *
 * @param pixfmt FourCC pixel format value (\ref video_pixel_formats).
 */
static inline unsigned int video_pix_fmt_bpp(uint32_t pixfmt)
{
	switch (pixfmt) {
	case VIDEO_PIX_FMT_BGGR8:
	case VIDEO_PIX_FMT_GBRG8:
	case VIDEO_PIX_FMT_GRBG8:
	case VIDEO_PIX_FMT_RGGB8:
		return 1;
	case VIDEO_PIX_FMT_RGB565:
	case VIDEO_PIX_FMT_YUYV:
		return 2;
	case VIDEO_PIX_FMT_XRGB32:
	case VIDEO_PIX_FMT_XYUV32:
		return 4;
	default:
		return 0;
	}
}

#ifdef __cplusplus
}
#endif

/**
 * @}
 */

#endif /* ZEPHYR_INCLUDE_VIDEO_H_ */
