/* Simple Plugin API */
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
/* SPDX-License-Identifier: MIT */

#ifndef SPA_META_H
#define SPA_META_H

#ifdef __cplusplus
extern "C" {
#endif

#include <spa/utils/defs.h>
#include <spa/pod/pod.h>

#ifndef SPA_API_META
 #ifdef SPA_API_IMPL
  #define SPA_API_META SPA_API_IMPL
 #else
  #define SPA_API_META static inline
 #endif
#endif

/**
 * \addtogroup spa_buffer
 * \{
 */

enum spa_meta_type {
    SPA_META_Invalid,
    SPA_META_Header,        /**< struct spa_meta_header */
    SPA_META_VideoCrop,        /**< struct spa_meta_region with cropping data */
    SPA_META_VideoDamage,        /**< array of struct spa_meta_region with damage, where an invalid entry or end-of-array marks the end. */
    SPA_META_Bitmap,        /**< struct spa_meta_bitmap */
    SPA_META_Cursor,        /**< struct spa_meta_cursor */
    SPA_META_Control,        /**< metadata contains a spa_meta_control
                      *  associated with the data */
    SPA_META_Busy,            /**< don't write to buffer when count > 0 */
    SPA_META_VideoTransform,    /**< struct spa_meta_transform */
    SPA_META_SyncTimeline,        /**< struct spa_meta_sync_timeline */

    _SPA_META_LAST,            /**< not part of ABI/API */
};

/**
 * A metadata element.
 *
 * This structure is available on the buffer structure and contains
 * the type of the metadata and a pointer/size to the actual metadata
 * itself.
 */
struct spa_meta {
    uint32_t type;        /**< metadata type, one of enum spa_meta_type */
    uint32_t size;        /**< size of metadata */
    void *data;        /**< pointer to metadata */
};

SPA_API_META void *spa_meta_first(const struct spa_meta *m) {
    return m->data;
}

SPA_API_META void *spa_meta_end(const struct spa_meta *m) {
    return SPA_PTROFF(m->data,m->size,void);
}
#define spa_meta_check(p,m)    (SPA_PTROFF(p,sizeof(*(p)),void) <= spa_meta_end(m))

/**
 * Describes essential buffer header metadata such as flags and
 * timestamps.
 */
struct spa_meta_header {
#define SPA_META_HEADER_FLAG_DISCONT    (1 << 0)    /**< data is not continuous with previous buffer */
#define SPA_META_HEADER_FLAG_CORRUPTED    (1 << 1)    /**< data might be corrupted */
#define SPA_META_HEADER_FLAG_MARKER    (1 << 2)    /**< media specific marker */
#define SPA_META_HEADER_FLAG_HEADER    (1 << 3)    /**< data contains a codec specific header */
#define SPA_META_HEADER_FLAG_GAP    (1 << 4)    /**< data contains media neutral data */
#define SPA_META_HEADER_FLAG_DELTA_UNIT    (1 << 5)    /**< cannot be decoded independently */
    uint32_t flags;                /**< flags */
    uint32_t offset;            /**< offset in current cycle */
    int64_t pts;                /**< presentation timestamp in nanoseconds */
    int64_t dts_offset;            /**< decoding timestamp as a difference with pts */
    uint64_t seq;                /**< sequence number, increments with a
                          *  media specific frequency */
};

/** metadata structure for Region or an array of these for RegionArray */
struct spa_meta_region {
    struct spa_region region;
};

SPA_API_META bool spa_meta_region_is_valid(const struct spa_meta_region *m) {
    return m->region.size.width != 0 && m->region.size.height != 0;
}

/** iterate all the items in a metadata */
#define spa_meta_for_each(pos,meta)                    \
    for ((pos) = (__typeof(pos))spa_meta_first(meta);        \
        spa_meta_check(pos, meta);                    \
            (pos)++)

/**
 * Bitmap information
 *
 * This metadata contains a bitmap image in the given format and size.
 * It is typically used for cursor images or other small images that are
 * better transferred inline.
 */
struct spa_meta_bitmap {
    uint32_t format;        /**< bitmap video format, one of enum spa_video_format. 0 is
                      *  and invalid format and should be handled as if there is
                      *  no new bitmap information. */
    struct spa_rectangle size;    /**< width and height of bitmap */
    int32_t stride;            /**< stride of bitmap data */
    uint32_t offset;        /**< offset of bitmap data in this structure. An offset of
                      *  0 means no image data (invisible), an offset >=
                      *  sizeof(struct spa_meta_bitmap) contains valid bitmap
                      *  info. */
};

SPA_API_META bool spa_meta_bitmap_is_valid(const struct spa_meta_bitmap *m) {
    return m->format != 0;
}

/**
 * Cursor information
 *
 * Metadata to describe the position and appearance of a pointing device.
 */
struct spa_meta_cursor {
    uint32_t id;            /**< cursor id. an id of 0 is an invalid id and means that
                      *  there is no new cursor data */
    uint32_t flags;            /**< extra flags */
    struct spa_point position;    /**< position on screen */
    struct spa_point hotspot;    /**< offsets for hotspot in bitmap, this field has no meaning
                      *  when there is no valid bitmap (see below) */
    uint32_t bitmap_offset;        /**< offset of bitmap meta in this structure. When the offset
                      *  is 0, there is no new bitmap information. When the offset is
                      *  >= sizeof(struct spa_meta_cursor) there is a
                      *  struct spa_meta_bitmap at the offset. */
};

SPA_API_META bool spa_meta_cursor_is_valid(const struct spa_meta_cursor *m) {
    return m->id != 0;
}

/** a timed set of events associated with the buffer */
struct spa_meta_control {
    struct spa_pod_sequence sequence;
};

/** a busy counter for the buffer */
struct spa_meta_busy {
    uint32_t flags;
    uint32_t count;            /**< number of users busy with the buffer */
};

enum spa_meta_videotransform_value {
    SPA_META_TRANSFORMATION_None = 0,    /**< no transform */
    SPA_META_TRANSFORMATION_90,        /**< 90 degree counter-clockwise */
    SPA_META_TRANSFORMATION_180,        /**< 180 degree counter-clockwise */
    SPA_META_TRANSFORMATION_270,        /**< 270 degree counter-clockwise */
    SPA_META_TRANSFORMATION_Flipped,    /**< 180 degree flipped around the vertical axis. Equivalent
                          * to a reflexion through the vertical line splitting the
                          * buffer in two equal sized parts */
    SPA_META_TRANSFORMATION_Flipped90,    /**< flip then rotate around 90 degree counter-clockwise */
    SPA_META_TRANSFORMATION_Flipped180,    /**< flip then rotate around 180 degree counter-clockwise */
    SPA_META_TRANSFORMATION_Flipped270,    /**< flip then rotate around 270 degree counter-clockwise */
};

/** a transformation of the buffer */
struct spa_meta_videotransform {
    uint32_t transform;            /**< orientation transformation that was applied to the buffer,
                          *  one of enum spa_meta_videotransform_value */
};

/**
 * A timeline point for explicit sync
 *
 * Metadata to describe the time on the timeline when the buffer
 * can be acquired and when it can be reused.
 *
 * This metadata will require negotiation of 2 extra fds for the acquire
 * and release timelines respectively.  One way to achieve this is to place
 * this metadata as SPA_PARAM_BUFFERS_metaType when negotiating a buffer
 * layout with 2 extra fds.
 */
struct spa_meta_sync_timeline {
    uint32_t flags;
    uint32_t padding;
    uint64_t acquire_point;            /**< the timeline acquire point, this is when the data
                          *  can be accessed. */
    uint64_t release_point;            /**< the timeline release point, this timeline point should
                          *  be signaled when the data is no longer accessed. */
};

/**
 * \}
 */

#ifdef __cplusplus
}  /* extern "C" */
#endif

#endif /* SPA_META_H */
