#pragma once
/*
 * NVVideoImageBuffer.h
 *
 *  Created on: May 14, 2020
 *      Author: dengminhao@axzt.net
 */

#ifndef YCKIT_YCKIT_VIDEO_NVVIDEOIMAGEBUFFER_H_
#define YCKIT_YCKIT_VIDEO_NVVIDEOIMAGEBUFFER_H_
#ifdef SDK_SIMPLE_INCLUDE
#include "YCKitExport.h"
#else
#include <YCKit/YCKitExport.h>
#endif
#include "NVVideoSize.h"
#include <cassert>
#include <cstdlib>
#include <cstdint>

enum NativeBufferOwnMode{
	//owned by hardware, you needn't handle its release,
	//but you need use it synchronously (maybe released after this callback)
	MODE_HARDWARE_OWNED = 0,
	//owner by callee (native code), but you need to call retain/release yourself.
	MODE_CALLEE_OWNED_MANUALLY = 1,
	//owner by callee (native code), but you care nothing, just use it.
	MODE_CALLEE_OWNED_AUTO = 2,
	//owner by caller (yourself), you need free it yourself.
	MODE_CALLER_OWNED = 3
};

enum NVPixelFormat{
	NV_FMT_NONE = -1,
	NV_FMT_YUV420P = 0,
	NV_FMT_YUYV422 = 1,
	NV_FMT_RGB24 = 2,
	NV_FMT_YUV422P = 4,
	NV_FMT_YUV444P = 5,   ///< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
	NV_FMT_YUV410P = 6,   ///< planar YUV 4:1:0,  9bpp, (1 Cr & Cb sample per 4x4 Y samples)
	NV_FMT_YUV411P = 7,   ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
	NV_FMT_GRAY8 =8,     ///<        Y        ,  8bpp
	NV_FMT_YUVJ420P =12,  ///< planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting color_range
	NV_FMT_YUVJ422P =13,  ///< planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV422P and setting color_range
	NV_FMT_YUVJ444P =14,  ///< planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting color_range
	NV_FMT_UYVY422 =15,   ///< packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
	NV_FMT_UYYVYY411 =16,

	NV_FMT_NV12 = 23,
	NV_FMT_NV21 = 24,
	NV_FMT_ARGB = 25, // AV_PIX_FMT_ARGB
    NV_FMT_RGBA = 26, // AV_PIX_FMT_RGBA
    NV_FMT_ABGR = 27, // AV_PIX_FMT_ABGR
    NV_FMT_BGRA = 28, // AV_PIX_FMT_BGRA

	//Hardware surfaces/frames
	NV_FMT_CVPIXEL_BUFFER = 160, //AV_PIX_FMT_VIDEOTOOLBOX

    NV_FMT_DXVA2_VLD = 53,    // AV_PIX_FMT_DXVA2_VLD
    NV_FMT_D3D11VA_VLD = 118, // AV_PIX_FMT_D3D11VA_VLD
    NV_FMT_D3D11 = 174,       // AV_PIX_FMT_D3D11

	NV_FMT_NB,  ///number of NVPixelFormat, not real pixel format
};

class DLL_DECL NVVideoImageBuffer {
public:
    enum {
        kMaxPlanes = 4,

        kYPlane = 0,
        kARGBPlane = kYPlane,
        kUPlane = 1,
        kUVPlane = kUPlane,
        kVPlane = 2,
        kAPlane = 3,
    };

    [[deprecated("Using NVPixelFormatEx::planeCount instead")]]
    static int NumPlanes(NVPixelFormat format);

    static bool Copy(NVPixelFormat fmt, int width, int height,
        uint8_t* src_data[kMaxPlanes], int src_strides[kMaxPlanes],
        uint8_t* dst_data[kMaxPlanes], int dst_strides[kMaxPlanes]);

	virtual const void * getNativeBufferObj() = 0;
	virtual const NVVideoSize getImageSize() const = 0;

	//CPU may not access real raw buffer, only GPU does.
	virtual bool isDMA() const = 0;

	virtual inline bool isHardwareOwnedBuffer(){
		return getOwnMode() == MODE_HARDWARE_OWNED;
	}

	//only available when isDMA() == false
	virtual const unsigned char* getRawBuffer() const = 0;

	//only available when isDMA() == false
	virtual size_t getRawBufferSize() const = 0;

	virtual NVPixelFormat getPixelFormat() const = 0;

    virtual void setTs(uint64_t ts) = 0;
	virtual uint64_t getTs() const = 0;

    virtual NVPixelFormat getHWPixelFormat() const;

    virtual int stride(int plane) const;

    virtual const uint8_t* data(int plane) const;

    virtual bool CopyTo(uint8_t* data[kMaxPlanes], int strides[kMaxPlanes]);
    virtual bool CopyTo(void* textures[kMaxPlanes]);

	virtual ~NVVideoImageBuffer(){
		//we cannot call virtual function in destructor in C++.
		//make sure bufReleased == true here.
		assert(bufReleased);
		if (!bufReleased){
			//bad. you need call releaseOrFreeBuf in derived class destructor.
			exit(42);
		}
	}

	virtual inline NVPixelFormat getPixelFormatForEncoder() const{
		return getPixelFormat();
	}

	DISALLOW_COPY_AND_ASSIGN(NVVideoImageBuffer);
protected:
	//always using std::shared_ptr<NVVideoImageBuffer>, so don't make ctor public.
    NVVideoImageBuffer();

	//only use it in mode MODE_CALLEE_OWNED_MANUALLY
	virtual void retain()=0;
	//only use it in mode MODE_CALLEE_OWNED_MANUALLY
	virtual void release()=0;
	//only use it in mode MODE_CALLER_OWNED
	virtual void free()=0;

	virtual NativeBufferOwnMode getOwnMode() const =0;

	bool bufReleased = false;

	inline void releaseOrFreeBuf(){
		if (bufReleased) return;
		//handle OwnMode internally. make std::shared_ptr<NVVideoImageBuffer> act as MODE_CALLEE_OWNED_AUTO.
		switch(getOwnMode()){
		case MODE_CALLEE_OWNED_MANUALLY:
			release();
			break;
		case MODE_CALLER_OWNED:
			free();
			break;
		default:
			break;
		}
		bufReleased = true;
	}

protected:
    NVPixelFormat hw_pixel_format_ = NV_FMT_NONE;
    int strides_[kMaxPlanes];
    uint8_t* data_[kMaxPlanes];
};




#endif /* YCKIT_YCKIT_VIDEO_NVVIDEOIMAGEBUFFER_H_ */
