#ifndef __uvcsam_h__
#define __uvcsam_h__

/* Version: 1.30594.20260120 */
/* Win32:
     (a) x86: XP SP3 or above; CPU supports SSE2 instruction set or above
     (b) x64: Win7 or above
*/

#ifdef __cplusplus
extern "C" {
#endif

/**********************************************************************************/
/*                             C API                                              */
/* Uvcsam_enum (optional)                                                         */
/* ----> Uvcsam_open                                                              */
/* ----> enum resolutions, set resolution, set exposure time, etc                 */
/* ----> Uvcsam_start                                                             */
/* ----> callback for image and events                                            */
/* ----> Uvcsam_close                                                             */
/**********************************************************************************/
#define UVCSAM_MAX              16

/* command: put & get */
#define UVCSAM_FWVERSION        0x00000001    /* firmware version, such as: 1.2.3 */
#define UVCSAM_FWDATE           0x00000002    /* firmware date, such as: 20191018 */
#define UVCSAM_HWVERSION        0x00000003    /* hardware version, such as: 1.2 */
#define UVCSAM_REVISION         0x00000004    /* revision */
#define UVCSAM_GAIN             0x00000005    /* gain, percent, 100 means 100% */
#define UVCSAM_EXPOTIME         0x00000006    /* exposure time, in microseconds */
#define UVCSAM_AE_ONOFF         0x00000007    /* auto exposure: 0 = off, 1 = on */
#define UVCSAM_AE_TARGET        0x00000008    /* auto exposure target, range = [UVCSAM_AE_TARGET_MIN, UVCSAM_AE_TARGET_MAX] */
#define UVCSAM_AE_ROILEFT       0x00000009    /* auto exposure roi: left */
#define UVCSAM_AE_ROITOP        0x0000000a    /* top */
#define UVCSAM_AE_ROIRIGHT      0x0000000b    /* right */
#define UVCSAM_AE_ROIBOTTOM     0x0000000c    /* bottom */
#define UVCSAM_AWB              0x0000000d    /* white balance: 0 = manual, 1 = global auto, 2 = roi, 3 = roi mode 'once' */
#define UVCSAM_AWB_ROILEFT      0x0000000e    /* white balance roi: left */
#define UVCSAM_AWB_ROITOP       0x0000000f    /* top */
#define UVCSAM_AWB_ROIRIGHT     0x00000010    /* right */
#define UVCSAM_AWB_ROIBOTTOM    0x00000011    /* bottom */
#define UVCSAM_WBGAIN_RED       0x00000012    /* white balance gain, range: [UVCSAM_WBGAIN_MIN, UVCSAM_WBGAIN_MAX] */
#define UVCSAM_WBGAIN_GREEN     0x00000013
#define UVCSAM_WBGAIN_BLUE      0x00000014
#define UVCSAM_VFLIP            0x00000015    /* flip vertical */
#define UVCSAM_HFLIP            0x00000016    /* flip horizontal */
#define UVCSAM_FFC              0x00000017    /* flat field correction
                                                    put:
                                                        0: disable
                                                        1: enable
                                                        -1: reset
                                                        (0xff000000 | n): set the average number to n, [1~255]
                                                    get:
                                                        (val & 0xff): 0 -> disable, 1 -> enable, 2 -> inited
                                                        ((val & 0xff00) >> 8): sequence
                                                        ((val & 0xff0000) >> 8): average number
                                              */
#define UVCSAM_FFC_ONCE         0x00000018    /* ffc (flat field correction) 'once' */
#define UVCSAM_LEVELRANGE_AUTO  0x00000019    /* level range auto */
#define UVCSAM_LEVELRANGE_LOW   0x0000001a    /* level range low */
#define UVCSAM_LEVELRANGE_HIGH  0x0000001b    /* level range high */
#define UVCSAM_HISTOGRAM        0x0000001c    /* histogram */
#define UVCSAM_CHROME           0x0000001d    /* monochromatic mode */
#define UVCSAM_NEGATIVE         0x0000001e    /* negative film */
#define UVCSAM_PAUSE            0x0000001f    /* pause */
#define UVCSAM_SHARPNESS        0x00000020
#define UVCSAM_SATURATION       0x00000021
#define UVCSAM_GAMMA            0x00000022
#define UVCSAM_CONTRAST         0x00000023
#define UVCSAM_BRIGHTNESS       0x00000024
#define UVCSAM_HZ               0x00000025    /* 2 -> 60HZ AC;  1 -> 50Hz AC;  0 -> DC */
#define UVCSAM_HUE              0x00000026
#define UVCSAM_LIGHT_SOURCE     0x00000027    /* light source brightness adjustment */
#define UVCSAM_REALTIME         0x00000028    /* realtime: 1 => ON, 0 => OFF */
#define UVCSAM_FORMAT           0x000000fe    /* output format: 0 => BGR888, 1 => BGRA8888, 2 => RGB888, 3 => RGBA8888; default: 0
                                                 Can be changed only when camera is not running.
                                              */
#define UVCSAM_MAGIC            0x000000ff

#define UVCSAM_GPIO             0x08000000    /* GPIO: 0~7 bit corresponds to GPIO */
#define UVCSAM_RES              0x10000000    /* resolution:
                                                    Can be changed only when camera is not running.
                                                    To get the number of the supported resolution, use: Uvcsam_range(h, UVCSAM_RES, nullptr, &num, nullptr)
                                              */
#define UVCSAM_CODEC            0x20000000    /* 0: mjpeg, 1: YUY2; Can be changed only when camera is not running */
#define UVCSAM_WIDTH            0x40000000    /* to get the nth width, use: Uvcsam_get(h, UVCSAM_WIDTH | n, &width) */
#define UVCSAM_HEIGHT           0x80000000

/********************************************************************/
/* How to enum the resolutions:                                     */
/*     Uvcsam_range(h, UVCSAM_RES, nullptr, &num, nullptr);         */
/*     for (int i = 0; i <= num; ++i)                               */
/*     {                                                            */
/*         int width, height;                                       */
/*         Uvcsam_get(h, UVCSAM_WIDTH | i, &width);                 */
/*         Uvcsam_get(h, UVCSAM_HEIGHT | i, &height);               */
/*         printf("%d: %d x %d\n", i, width, height);               */
/*     }                                                            */
/********************************************************************/

/********************************************************************/
/* "Direct Mode" vs "Pull Mode"                                     */
/* (1) Direct Mode:                                                 */
/*     (a) Uvcsam_start(h, pFrameBuffer, ...)                       */
/*     (b) pros: simple, slightly more efficient                    */
/* (2) Pull Mode:                                                   */
/*     (a) Uvcsam_start(h, nullptr, ...)                            */
/*     (b) use Uvcsam_pull(h, pFrameBuffer) to pull image           */
/*     (c) pros: never frame confusion                              */
/********************************************************************/

/* event */
#define UVCSAM_EVENT_AWB        0x0001
#define UVCSAM_EVENT_FFC        0x0002
#define UVCSAM_EVENT_LEVELRANGE 0x0004
#define UVCSAM_EVENT_IMAGE      0x0008
#define UVCSAM_EVENT_TRIGGER    0x0010    /* user push the trigger button */
#define UVCSAM_EVENT_FLIP       0x0020    /* user push the flip button */
#define UVCSAM_EVENT_EXPOTIME   0x0040    /* auto exposure: exposure time changed */
#define UVCSAM_EVENT_GAIN       0x0080    /* auto exposure: gain changed */
#define UVCSAM_EVENT_DISCONNECT 0x0100    /* camera disconnect */
#define UVCSAM_EVENT_ERROR      0x0200    /* error */
#define UVCSAM_EVENT_RECORD     0x0400

#define UVCSAM_ROI_WIDTH_MIN    32
#define UVCSAM_ROI_HEIGHT_MIN   32

#define UVCSAM_AE_TARGET_MIN    16        /* auto exposure target: minimum */
#define UVCSAM_AE_TARGET_DEF    48        /* auto exposure target: default */
#define UVCSAM_AE_TARGET_MAX    208       /* auto exposure target: maximum */

#define UVCSAM_WBGAIN_MIN       1
#define UVCSAM_WBGAIN_MAX       255
#define UVCSAM_WBGAIN_RED_DEF   128
#define UVCSAM_WBGAIN_GREEN_DEF 64
#define UVCSAM_WBGAIN_BLUE_DEF  128

#define UVCSAM_LEVELRANGE_MIN   0
#define UVCSAM_LEVELRANGE_MAX   255

#define UVCSAM_LIGHT_SOURCE_MIN 0
#define UVCSAM_LIGHT_SOURCE_MAX 100
#define UVCSAM_LIGHT_SOURCE_DEF 50

#if defined(_WIN32) && !defined(UVCSAM_DSHOW) && !defined(UVCSAM_TWAIN)
#ifdef UVCSAM_EXPORTS
#define UVCSAM_API(x)    __declspec(dllexport)   x   __stdcall  /* in Windows, we use __stdcall calling convention, see https://docs.microsoft.com/en-us/cpp/cpp/stdcall */
#else
#define UVCSAM_API(x)    __declspec(dllimport)   x   __stdcall
#endif

#ifndef TDIBWIDTHBYTES
#define TDIBWIDTHBYTES(bits)  ((unsigned)(((bits) + 31) & (~31)) / 8)
#endif

/* handle */
typedef struct UvcsamT { int unused; } *HUvcsam;

/* sdk version */
UVCSAM_API(const wchar_t*)   Uvcsam_version();

typedef struct {
    wchar_t   displayname[128];    /* display name */
    wchar_t   id[128];             /* unique and opaque id of a connected camera, for Uvcsam_open */
} UvcsamDevice; /* camera for enumerating */

/*
    enumerate the cameras connected to the computer, return the number of enumerated.
*/
UVCSAM_API(unsigned) Uvcsam_enum(UvcsamDevice arr[UVCSAM_MAX]);

/* camId == nullptr means the first device to open */
UVCSAM_API(HUvcsam) Uvcsam_open(const wchar_t* camId);

typedef void (__stdcall* PUVCSAM_CALLBACK)(unsigned nEvent, void* pCallbackCtx);
/* pFrameBuffer == nullptr: use pull mode,
   otherwise, it's size must be >= TDIBWIDTHBYTES(width * 24) * height
*/
UVCSAM_API(HRESULT) Uvcsam_start(HUvcsam h, void* pFrameBuffer, PUVCSAM_CALLBACK pCallbackFun, void* pCallbackCtx);
UVCSAM_API(HRESULT) Uvcsam_stop(HUvcsam h);
UVCSAM_API(void) Uvcsam_close(HUvcsam h);

/*
    nId: UVCSAM_XXXX
*/
UVCSAM_API(HRESULT) Uvcsam_put(HUvcsam h, unsigned nId, int val);
UVCSAM_API(HRESULT) Uvcsam_get(HUvcsam h, unsigned nId, int* pVal);
UVCSAM_API(HRESULT) Uvcsam_range(HUvcsam h, unsigned nId, int* pMin, int* pMax, int* pDef);

UVCSAM_API(HRESULT) Uvcsam_ffcimport(HUvcsam h, const wchar_t* filepath);
UVCSAM_API(HRESULT) Uvcsam_ffcexport(HUvcsam h, const wchar_t* filepath);

UVCSAM_API(HRESULT) Uvcsam_pull(HUvcsam h, void* pFrameBuffer);

/* filePath == NULL means to stop record.
   support file extension: *.asf, *.mp4, *.mkv
*/
UVCSAM_API(HRESULT) Uvcsam_record(HUvcsam h, const char* filePath /* utf8 */);
UVCSAM_API(HRESULT) Uvcsam_recordW(HUvcsam h, const wchar_t* filePath);
UVCSAM_API(HRESULT) Uvcsam_recordA(HUvcsam h, const char* filePath /* ansi */);

#endif
#ifdef __cplusplus
}
#endif
#endif
