/**
{file: 
	{name: LmiVideoCommon.h}
	{description: Defines common structures and functions related to video/pciture.}
	{copyright:
		(c) 2007-2016 Vidyo, Inc.,
		433 Hackensack Avenue,
		Hackensack, NJ  07601.

		All rights reserved.

		The information contained herein is proprietary to Vidyo, Inc.
		and shall not be reproduced, copied (in whole or in part), adapted,
		modified, disseminated, transmitted, transcribed, stored in a retrieval
		system, or translated into any language in any form by any means
		without the express written consent of Vidyo, Inc.
										***** CONFIDENTIAL *****
	}
}
*/

#ifndef LMI_VIDEOCOMMON_H_
#define LMI_VIDEOCOMMON_H_


// enable this to test bitstream fuzzing
// #define LMI_DEC_FUZZ_TESTING

#include <Lmi/Utils/LmiTypes.h>
#include <Lmi/Utils/LmiMediaFormat.h>
#include <Lmi/Utils/LmiBitstream.h>
#include <Lmi/Utils/LmiAlignedAllocator.h>
#include <Lmi/Os/LmiDataBuffer.h>

#include <Lmi/Video/Common/LmiVideoCommonDefaultSettings.h>
#include <Lmi/Video/Common/LmiPlanarAllocator.h>
#include <Lmi/Video/Common/LmiVideoFrame.h>


LMI_BEGIN_EXTERN_C


#include "LmiVideoCommonConfig.h"


/**
{package visibility="public":
	{name: VideoCommon}
	{parent: Lmi}
	{include: Lmi/Video/Common/LmiVideoCommon.h}
	{library: LmiVideoCommon}
	{description: Defines common structures and functions related to video/pciture.}
}
*/

#define LMI_VIDEO_COMMON_SupportedDLyrs            3
#define LMI_VIDEO_COMMON_SupportedQLyrs            2
#define LMI_VIDEO_COMMON_SupportedTLyrs            4
#define LMI_VIDEO_COMMON_SupportedSLyrs            (LMI_VIDEO_COMMON_SupportedDLyrs*LMI_VIDEO_COMMON_SupportedQLyrs)
#define LMI_VIDEO_MaxAggregatedBitrateSamples      50

#define LMI_VIDEO_COMMON_MaxDQLyrs                 128
#define LMI_VIDEO_COMMON_MaxTLyrs                  8


/**
{function:
	{name: LmiVideoCommonInitialize}
	{parent: VideoCommon}
	{description: Initialize all VdeoCommon components of the Vidyo SDK.}
	{prototype: LmiBool LmiVideoCommonInitialize(void)}
	{return: LMI_TRUE on success, LMI_FALSE on failure.}
	{note: This function is not reentrant.}
	{note: This function may be called multiple times as long as its corresponding LmiVideoCommonUninitialize function is called the same number of times.}
}
*/
LmiBool LmiVideoCommonInitialize(void);

/**
{function:
	{name: LmiVideoCommonUninitialize}
	{parent: VideoCommon}
	{description: Uninitialize all VideoCommon components of the Vidyo SDK.}
	{prototype: void LmiVideoCommonUninitialize(void)}
	{note: This function is not reentrant.}
	{note: This function may be called multiple times as long as its corresponding LmiVideoCommonInitialize function is called the same number of times.}
}
*/
void LmiVideoCommonUninitialize(void);


#ifdef LMI_DEC_FUZZ_TESTING
void LmiDataBufferAddFuzz_(LmiDataBuffer *db, LmiUint bitsSkipped, LmiUint frequency);
#endif


/**********************/
/* General resampling */
/**********************/

#define LMI_USE_FAST_FIXED_SIZE_FILTER 1

typedef struct LmiPlaneResamplerFilter_
{
	LmiAlignedAllocator* alignedAlloc;
	LmiUint totalFiltNum;
	LmiInt8* filtS;
} LmiPlaneResamplerFilter;

/**
{type visibility="private":
	{name: LmiPlaneResampler}
	{parent: VideoCommon}
	{description: A general, two-dimensional byte plane, resampler object.}
}
*/
typedef struct LmiPlaneResampler_
{
	LmiAllocator* alloc;
	LmiAlignedAllocator alignedAlloc;

	LmiSizeT srcWidth;
	LmiSizeT srcHeight;
	LmiSizeT dstWidth;
	LmiSizeT dstHeight;
	LmiSizeT halfTaps;

	LmiUint8* tmpImg; // TODO: use higher precision so that we can avoid one clipping?

	LmiPlaneResamplerFilter widthFilters;
	LmiPlaneResamplerFilter heightFilters;
} LmiPlaneResampler;

/**
{function visibility="private":
	{name: LmiPlaneResamplerConstruct}
	{parent: LmiPlaneResampler}
	{description: Constructs a LmiPlaneResampler object for resampling byte plane.}
	{prototype: LmiPlaneResampler* LmiPlaneResamplerConstruct(LmiPlaneResampler* pr, LmiSizeT srcWidth, LmiSizeT srcHeight, LmiSizeT dstWidth, LmiSizeT dstHeight, LmiAllocator* alloc)}
	{parameter: {name: pr} {description: A pointer to an uninitialized LmiPlaneResampler structure.}}
	{parameter: {name: srcWidth} {description: Width of the source plane.}}
	{parameter: {name: srcHeight} {description: Height of the source plane.}}
	{parameter: {name: dstWidth} {description: Width of the destination plane.}}
	{parameter: {name: dstHeight} {description: Height of the destination plane.}}
	{parameter: {name: alloc} {description: Memory allocator; needed for creating a temporal buffer.}}
	{return: A pointer to the constructed object or NULL on error.}
}
*/
LmiPlaneResampler* LmiPlaneResamplerConstruct(LmiPlaneResampler* pr, LmiSizeT srcWidth, LmiSizeT srcHeight, LmiSizeT dstWidth, LmiSizeT dstHeight, LmiAllocator* alloc);
void LmiPlaneResamplerDestruct(LmiPlaneResampler* pr);
/**
{function visibility="private":
	{name: LmiPlaneResamplerResample}
	{parent: LmiPlaneResampler}
	{description: Resamples the source byte plane of resolution srcWidth x srcHeight to dstWidth x destHeight.  
		This source resolution and the destination resolution does not have to match the corresponding resolutions specified when constructing the LmiPlaneResampler object as long as the 
		source dimension to destination dimention ratio remains the same.  Additionally, the source and destination resolution MUST NOT be greater than the specified resolution during 
		construction.}
	{prototype: LmiBool LmiPlaneResamplerResample(LmiPlaneResampler* pr, const LmiUint8* src, LmiSizeT srcPitch, LmiSizeT srcWidth, LmiSizeT srcHeight, LmiUint8* dst, LmiSizeT dstPitch, LmiSizeT dstWidth, LmiSizeT dstHeight)}
	{parameter: {name: pr} {description: A pointer to constructed LmiPlaneResampler object.}}
	{parameter: {name: src} {description: Pointer to source byte plane.}}
	{parameter: {name: srcPitch} {description: Pitch of the source byte plane.}}
	{parameter: {name: srcWidth} {description: Width of the source plane.}}
	{parameter: {name: srcHeight} {description: Height of the source plane.}}
	{parameter: {name: dst} {description: Pointer to destination byte plane.}}
	{parameter: {name: dstPitch} {description: Pitch of the destination byte plane.}}
	{parameter: {name: dstWidth} {description: Width of the destination plane.}}
	{parameter: {name: dstHeight} {description: Height of the destination plane.}}
	{return: LMI_FALSE on error.}
}
*/
LmiBool LmiPlaneResamplerResample(LmiPlaneResampler* pr, const LmiUint8* src, LmiSizeT srcPitch, LmiSizeT srcWidth, LmiSizeT srcHeight, LmiUint8* dst, LmiSizeT dstPitch, LmiSizeT dstWidth, LmiSizeT dstHeight);


/*******************************************/
/* Get version info of the VideoCommon lib */
/*******************************************/

void LmiVideoCommonGetVersionInfo(LmiString* infoString);

void LmiVideoCommonGetLibInfo(LmiString *infoString);


/************/
/* DQ Table */
/************/

/**
{type visibility="public":
	{name: LmiTLyrDqTable}
	{parent: VideoCommon}
	{description: A table of DQ layer IDs for a temporal layer.}
}
*/
typedef struct {
	LmiInt8         numSLyrs;
	/* sorted from the lowest to the highest dq_id; 
			for H.264, dq_id = (dependency_id << 4) + quality_id 
			for H.265, dq_id = layer_id
	*/
	LmiInt8         dqId[LMI_VIDEO_COMMON_DEFAULT_MaxSLyrs]; 
	LmiInt8         numDLyrs;
	LmiInt8         numQLyrs;
} LmiTLyrDqTable;

/**
{function visibility="public":
	{name: LmiTLyrDqTableConstruct}
	{parent: LmiTLyrDqTable}
	{description: Constructs a temporal layer's DQ table.}
	{prototype: LmiTLyrDqTable *LmiTLyrDqTableConstruct(LmiTLyrDqTable *x)}
	{parameter: {name: x} {description: A pointer to an uninitialized LmiTLyrDqTable structure.}}
	{return: A pointer to the constructed object or NULL on error.}
}
*/
LmiTLyrDqTable *LmiTLyrDqTableConstruct(LmiTLyrDqTable *x);

/**
{function visibility="public":
	{name: LmiTLyrDqTableConstructCopy}
	{parent: LmiTLyrDqTable}
	{description: Copy constructs a temporal layer's DQ table.}
	{prototype: LmiTLyrDqTable *LmiTLyrDqTableConstructCopy(LmiTLyrDqTable *x, const LmiTLyrDqTable *y)}
	{parameter: {name: x} {description: A pointer to an uninitialized LmiTLyrDqTable structure.}}
	{parameter: {name: y} {description: A pointer to an initialized LmiTLyrDqTable structure.}}
	{return: A pointer to the constructed object or NULL on error.}
}
*/
LmiTLyrDqTable *LmiTLyrDqTableConstructCopy(LmiTLyrDqTable *x, const LmiTLyrDqTable *y);

/**
{function visibility="public":
	{name: LmiTLyrDqTableAssign}
	{parent: LmiTLyrDqTable}
	{description: Assigns a temporal layer's DQ table from another temporal layer's DQ table.}
	{prototype: LmiTLyrDqTable *LmiTLyrDqTableAssign(LmiTLyrDqTable *x, const LmiTLyrDqTable *y)}
	{parameter: {name: x} {description: A pointer to an initialized LmiTLyrDqTable structure.}}
	{parameter: {name: y} {description: A pointer to an initialized LmiTLyrDqTable structure.}}
	{return: A pointer to the constructed object or NULL on error.}
}
*/
LmiTLyrDqTable *LmiTLyrDqTableAssign(LmiTLyrDqTable *x, const LmiTLyrDqTable *y);

/**
{function visibility="public":
	{name: LmiTLyrDqTableDestruct}
	{parent: LmiTLyrDqTable}
	{description: Destructs a temporal layer's DQ table.}
	{prototype: void LmiTLyrDqTableDestruct(LmiTLyrDqTable *x)}
	{parameter: {name: x} {description: A pointer to an initialized LmiTLyrDqTable structure.}}
}
*/
void LmiTLyrDqTableDestruct(LmiTLyrDqTable *x);

/**
{function visibility="public":
	{name: LmiTLyrDqTableGetNumSLyrs}
	{parent: LmiTLyrDqTable}
	{description: Returns the number of total DQ (spatial/SNR) layers.}
	{prototype: LmiInt8 LmiTLyrDqTableGetNumSLyrs(const LmiTLyrDqTable *x)}
	{parameter: {name: x} {description: A pointer to an initialized LmiTLyrDqTable structure.}}
	{return: Number of total spatial/SNR layers.}
}
*/
LmiInt8 LmiTLyrDqTableGetNumSLyrs(const LmiTLyrDqTable *x);

/**
{function visibility="public":
	{name: LmiTLyrDqTableGetNumDLyrs}
	{parent: LmiTLyrDqTable}
	{description: Returns the number of D (spatial) layers.}
	{prototype: LmiInt8 LmiTLyrDqTableGetNumDLyrs(const LmiTLyrDqTable *x)}
	{parameter: {name: x} {description: A pointer to an initialized LmiTLyrDqTable structure.}}
	{return: Number of spatial layers.}
}
*/
LmiInt8 LmiTLyrDqTableGetNumDLyrs(const LmiTLyrDqTable *x);

/**
{function visibility="public":
	{name: LmiTLyrDqTableGetNumQLyrs}
	{parent: LmiTLyrDqTable}
	{description: Returns the number of Q (SNR) layers.}
	{prototype: LmiInt8 LmiTLyrDqTableGetNumQLyrs(const LmiTLyrDqTable *x)}
	{parameter: {name: x} {description: A pointer to an initialized LmiTLyrDqTable structure.}}
	{return: Number of SNR layers.}
}
*/
LmiInt8 LmiTLyrDqTableGetNumQLyrs(const LmiTLyrDqTable *x);

/**
{function visibility="public":
	{name: LmiTLyrDqTableGetSLyr}
	{parent: LmiTLyrDqTable}
	{description: Returns the spatial/SNR layer number (increases consecutively from 0 to total DQ layers - 1).}
	{prototype: LmiInt8 LmiTLyrDqTableGetSLyr(const LmiTLyrDqTable *x, LmiInt8 dqId)}
	{parameter: {name: x} {description: A pointer to an initialized LmiTLyrDqTable structure.}}
	{parameter: {name: dqId} {description: DQ ID, e.g., for H.264 SVC, dqId = (dependency_id << 4) + quality_id; for H.265, dqId = layer_id.}}
	{return: Spatial/SNR layer number; -1 if no layer with the DQ ID exists.}
}
*/
LmiInt8 LmiTLyrDqTableGetSLyr(const LmiTLyrDqTable *x, LmiInt8 dqId);

/**
{function visibility="public":
	{name: LmiTLyrDqTableGetDqId}
	{parent: LmiTLyrDqTable}
	{description: Returns the DQ ID, e.g., for H.264 SVC, dqId = (dependency_id << 4) + quality_id; for H.265, dqId = layer_id.} 
	{prototype: LmiInt8 LmiTLyrDqTableGetDqId(const LmiTLyrDqTable *x, LmiInt8 sLyr)}
	{parameter: {name: x} {description: A pointer to an initialized LmiTLyrDqTable structure.}}
	{parameter: {name: sLyr} {description: A spatial/SNR number.}}
	{return: DQ ID; -1 if no layer with the DQ ID exists.}
}
*/
LmiInt8 LmiTLyrDqTableGetDqId(const LmiTLyrDqTable *x, LmiInt8 sLyr);

/**
{type visibility="public":
	{name: LmiDqTable}
	{parent: VideoCommon}
	{description: A table of DQ layer IDs.}
}
*/
typedef struct {
	LmiInt8          numTLyrs;
	/* sorted from the lowest to the highest temporal_id */
	LmiTLyrDqTable   tLyrDqTbl[LMI_VIDEO_COMMON_DEFAULT_MaxTLyrs];
} LmiDqTable;

/**
{function visibility="public":
	{name: LmiDqTableConstruct}
	{parent: LmiDqTable}
	{description: Constructs a DQ table.}
	{prototype: LmiDqTable *LmiDqTableConstruct(LmiDqTable *x)}
	{parameter: {name: x} {description: A pointer to an uninitialized LmiDqTable structure.}}
	{return: A pointer to the constructed object or NULL on error.}
}
*/
LmiDqTable *LmiDqTableConstruct(LmiDqTable *x);

/**
{function visibility="public":
	{name: LmiDqTableConstructCopy}
	{parent: LmiDqTable}
	{description: Copy constructs a DQ table.}
	{prototype: LmiDqTable *LmiDqTableConstructCopy(LmiDqTable *x, const LmiDqTable *y)}
	{parameter: {name: x} {description: A pointer to an uninitialized LmiDqTable structure.}}
	{parameter: {name: y} {description: A pointer to an initialized LmiDqTable structure.}}
	{return: A pointer to the constructed object or NULL on error.}
}
*/
LmiDqTable *LmiDqTableConstructCopy(LmiDqTable *x, const LmiDqTable *y);

/**
{function visibility="public":
	{name: LmiDqTableAssign}
	{parent: LmiDqTable}
	{description: Assigns a DQ table from another DQ table.}
	{prototype: LmiDqTable *LmiDqTableAssign(LmiDqTable *x, const LmiDqTable *y)}
	{parameter: {name: x} {description: A pointer to an initialized LmiDqTable structure.}}
	{parameter: {name: y} {description: A pointer to an initialized LmiDqTable structure.}}
	{return: A pointer to the constructed object or NULL on error.}
}
*/
LmiDqTable *LmiDqTableAssign(LmiDqTable *x, const LmiDqTable *y);

/**
{function visibility="public":
	{name: LmiDqTableDestruct}
	{parent: LmiDqTable}
	{description: Destructs a DQ table.} 
	{prototype: void LmiDqTableDestruct(LmiDqTable *x)}
	{parameter: {name: x} {description: A pointer to an initialized LmiDqTable structure.}}
}
*/
void LmiDqTableDestruct(LmiDqTable *x);

/**
{function visibility="public":
	{name: LmiDqTableGetNumTLyrs}
	{parent: LmiDqTable}
	{description: Returns the number of total temporal layers.}
	{prototype: LmiInt8 LmiDqTableGetNumTLyrs(const LmiDqTable *x)} 
	{parameter: {name: x} {description: A pointer to an initialized LmiDqTable structure.}}
	{return: Number of total temporal layers.}
}
*/
LmiInt8 LmiDqTableGetNumTLyrs(const LmiDqTable *x);

/**
{function visibility="public":
	{name: LmiDqTableGetNumSLyrs}
	{parent: LmiDqTable}
	{description: Returns the number of total DQ (spatial/SNR) layers for a given temporal layer.}
	{prototype: LmiInt8 LmiDqTableGetNumSLyrs(const LmiDqTable *x, LmiInt8 tId)}
	{parameter: {name: x} {description: A pointer to an initialized LmiDqTable structure.}}
	{parameter: {name: tId} {description: A temporal layer id.}}
	{return: Number of total spatial/SNR layers.}
}
*/
LmiInt8 LmiDqTableGetNumSLyrs(const LmiDqTable *x, LmiInt8 tId);

/**
{function visibility="public":
	{name: LmiDqTableGetSLyr}
	{parent: LmiDqTable}
	{description: Returns the spatial/quality layer number (increases consecutively from 0 to numDqLyrs-1) for a given temporal layer.}
	{prototype: LmiInt8 LmiDqTableGetSLyr(const LmiDqTable *x, LmiInt8 tId, LmiInt8 dqId)}
	{parameter: {name: x} {description: A pointer to an initialized LmiDqTable structure.}}
	{parameter: {name: tId} {description: A temporal layer id.}}
	{parameter: {name: dqId} {description: DQ ID, e.g., for H.264 SVC, dqId = (dependency_id << 4) + quality_id; for H.265, dqId = layer_id.}}
	{return: Spatial/quality layer number; -1 if no layer with the DQ ID exists.}
}
*/
LmiInt8 LmiDqTableGetSLyr(const LmiDqTable *x, LmiInt8 tId, LmiInt8 dqId);

/**
{function visibility="public":
	{name: LmiDqTableGetDqId}
	{parent: LmiDqTable}
	{description: Returns the DQ ID, e.g., for H.264 SVC, dqId = (dependency_id << 4) + quality_id; for H.265, dqId = layer_id.}
	{prototype: LmiInt8 LmiDqTableGetDqId(const LmiDqTable *x, LmiInt8 tId, LmiInt8 sLyr)}
	{parameter: {name: x} {description: A pointer to an initialized LmiDqTable structure.}}
	{parameter: {name: tId} {description: A temporal layer id.}}
	{parameter: {name: sLyr} {description: A spatial/SNR number.}}
	{return: DQ ID; -1 if no layer with the DQ ID exists.}
}
*/
LmiInt8 LmiDqTableGetDqId(const LmiDqTable *x, LmiInt8 tId, LmiInt8 sLyr);

/**
{function visibility="public":
	{name: LmiCopyArea}
	{parent: VideoCommon}
	{description: Copies a block of width and height.}
	{prototype: void LmiCopyArea(const LmiUint8 *src, LmiDistanceT srcPitch, LmiUint8 *dst, LmiSizeT dstPitch, LmiSizeT width, LmiSizeT height)}
	{parameter: {name: src} {description: A pointer to a source area.}}
	{parameter: {name: srcPitch} {description: A source area pitch.}}
	{parameter: {name: dst} {description: A pointer to destination area.}}
	{parameter: {name: dstPitch} {description: A destination area pitch.}}
	{parameter: {name: width} {description: A width to copy.}}
	{parameter: {name: height} {description: A height to copy.}}
}
*/
void LmiCopyArea(const LmiUint8 *src, LmiDistanceT srcPitch, LmiUint8 *dst, LmiSizeT dstPitch, LmiSizeT width, LmiSizeT height);

/**
{function visibility="public":
	{name: LmiResize4To1}
	{parent: VideoCommon}
	{description: Downsizes a source block with a 4-to-1 ratio.}
	{prototype: void LmiResize4To1(const LmiUint8 *src, LmiSizeT srcPitch, LmiUint8 *dst, LmiSizeT dstPitch, LmiSizeT dstWidth, LmiSizeT dstHeight)}
	{parameter: {name: src} {description: A pointer to a source area.}}
	{parameter: {name: srcPitch} {description: A source area pitch.}}
	{parameter: {name: dst} {description: A pointer to destination area.}}
	{parameter: {name: dstPitch} {description: A destination area pitch.}}
	{parameter: {name: dstWidth} {description: A width of a final block.}}
	{parameter: {name: dstHeight} {description: A height of a final block.}}
}
*/
void LmiResize4To1(const LmiUint8 *src, LmiSizeT srcPitch, LmiUint8 *dst, LmiSizeT dstPitch, LmiSizeT dstWidth, LmiSizeT dstHeight);

LmiVideoQuality LmiVideoQualityGetH264VideoQuality(LmiUint qp);
LmiVideoQuality LmiVideoQualityGetVp8VideoQuality(LmiUint qp);
LmiVideoQuality LmiVideoQualityGetVp9VideoQuality(LmiUint qp);
LmiVideoQuality LmiVideoQualityGetAv1VideoQuality(LmiUint qp);

LMI_END_EXTERN_C


#endif // LMI_VIDEOCOMMON_H_
