/**
{file:
	{name: LmiVideoFrameInline.h}
	{description: Inline functions for LmiVideoFrame.}
	{copyright:
		(c) 2010-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 *****
	}
}
*/
/******************************************************************************************************************
 * Video Plane
 ******************************************************************************************************************/
LMI_INLINE LmiVideoPlane* LmiVideoPlaneConstruct(LmiVideoPlane* x, void* buffer, LmiSizeT size, LmiSizeT width, LmiSizeT height, LmiSizeT pitch, LmiSizeT offset)
{
	x->buffer = buffer;
	x->size = size;
	x->width = width;
	x->height = height;
	x->pitch = pitch;
	x->offset = offset;
	x->pixelPitch = 1; /* $! Should be 0 for compressed formats like MJPG, but doesn't matter. */
	return x;
}

LMI_INLINE LmiVideoPlane* LmiVideoPlaneConstructWithPixelPitch(LmiVideoPlane* x, void* buffer, LmiSizeT size, LmiSizeT width, LmiSizeT height, LmiSizeT pitch, LmiSizeT offset, LmiSizeT pixelPitch)
{
	x->buffer = buffer;
	x->size = size;
	x->width = width;
	x->height = height;
	x->pitch = pitch;
	x->offset = offset;
	x->pixelPitch = pixelPitch;
	return x;
}

LMI_INLINE LmiVideoPlane* LmiVideoPlaneConstructCopy(LmiVideoPlane* x, const LmiVideoPlane* y)
{
	x->buffer = y->buffer;
	x->size = y->size;
	x->width = y->width;
	x->height = y->height;
	x->pitch = y->pitch;
	x->offset = y->offset;
	x->pixelPitch = y->pixelPitch;
	return x;
}

LMI_INLINE void LmiVideoPlaneDestruct(LmiVideoPlane* x) {}

LMI_INLINE LmiVideoPlane* LmiVideoPlaneAssign(LmiVideoPlane* x, const LmiVideoPlane* y)
{
	x->buffer = y->buffer;
	x->size = y->size;
	x->width = y->width;
	x->height = y->height;
	x->pitch = y->pitch;
	x->offset = y->offset;
	x->pixelPitch = y->pixelPitch;
	return x;
}

LMI_INLINE LmiBool LmiVideoPlaneEqual(const LmiVideoPlane* x, const LmiVideoPlane* y) {
	LmiAssert(LMI_FALSE);
	return LMI_FALSE;
}

LMI_INLINE const void* LmiVideoPlaneGetBufferConst(const LmiVideoPlane* x) {
	return x->buffer;
}

LMI_INLINE void* LmiVideoPlaneGetBuffer(const LmiVideoPlane* x) {
	return x->buffer;
}

LMI_INLINE void LmiVideoPlaneSetBuffer(LmiVideoPlane* x, void *buffer) {
	LmiAssert(x != NULL);
	x->buffer = buffer;
}

LMI_INLINE LmiSizeT LmiVideoPlaneGetSize(const LmiVideoPlane* x) {
	return x->size;
}

LMI_INLINE const void* LmiVideoPlaneGetImageConst(const LmiVideoPlane* x) {
	return (const void*) ((const LmiUint8*)x->buffer + x->offset);
}

LMI_INLINE void* LmiVideoPlaneGetImage(const LmiVideoPlane* x) {
	return (void*) ((LmiUint8*)x->buffer + x->offset);
}

LMI_INLINE LmiSizeT LmiVideoPlaneGetWidth(const LmiVideoPlane* x) {
	return x->width;
}

LMI_INLINE LmiSizeT LmiVideoPlaneGetHeight(const LmiVideoPlane* x) {
	return x->height;
}

LMI_INLINE LmiSizeT LmiVideoPlaneGetPitch(const LmiVideoPlane* x) {
	return x->pitch;
}

LMI_INLINE LmiSizeT LmiVideoPlaneGetPixelPitch(const LmiVideoPlane* x)
{
	return x->pixelPitch;
}


LMI_INLINE LmiSizeT LmiVideoPlaneGetOffset(const LmiVideoPlane* x) {
	return x->offset;
}

/******************************************************************************************************************
 * Video Frame Transform Parameters
 ******************************************************************************************************************/

LMI_INLINE LmiBool LmiVideoFrameTransformParametersSetInputView(LmiVideoFrameTransformParameters* p, LmiSizeT inputWidth, LmiSizeT inputHeight, LmiSizeT inputOffsetLeft, LmiSizeT inputOffsetTop)
{
	p->inputWidth = inputWidth;
	p->inputHeight = inputHeight;
	p->inputOffsetLeft = inputOffsetLeft;
	p->inputOffsetTop = inputOffsetTop;

	return LMI_TRUE;
}

LMI_INLINE LmiBool LmiVideoFrameTransformParametersSetResize(LmiVideoFrameTransformParameters* p, LmiSizeT resizeWidth, LmiSizeT resizeHeight)
{
	p->resizeWidth = resizeWidth;
	p->resizeHeight = resizeHeight;

	return LMI_TRUE;
}

LMI_INLINE LmiBool LmiVideoFrameTransformParametersSetRotation(LmiVideoFrameTransformParameters* p, LmiImageRotationDegree rotationDegrees)
{
	switch (rotationDegrees) {
	case LMI_IMAGE_ROTATION_0:
	case LMI_IMAGE_ROTATION_90:
	case LMI_IMAGE_ROTATION_180:
	case LMI_IMAGE_ROTATION_270:
		p->rotationDegrees = rotationDegrees;
		break;
	default:
		return LMI_FALSE;
	}

	return LMI_TRUE;
}

LMI_INLINE LmiBool LmiVideoFrameTransformParametersSetMirror(LmiVideoFrameTransformParameters* p, LmiBool mirror)
{
	p->mirror = mirror;

	return LMI_TRUE;
}

LMI_INLINE LmiBool LmiVideoFrameTransformParametersSetMargin(LmiVideoFrameTransformParameters* p, LmiSizeT marginLeft, LmiSizeT marginRight, LmiSizeT marginTop, LmiSizeT marginBottom)
{
	p->margin.left = marginLeft;
	p->margin.right = marginRight;
	p->margin.top = marginTop;
	p->margin.bottom = marginBottom;

	return LMI_TRUE;
}


LMI_INLINE LmiBool LmiVideoFrameTransformParametersSetDitherLevel(LmiVideoFrameTransformParameters* p, LmiVideoFrameDitherLevel ditherLevel)
{
	p->ditherLevel = ditherLevel;

	return LMI_TRUE;
}

LMI_INLINE LmiBool LmiVideoFrameTransformParametersSetSharpenLevel(LmiVideoFrameTransformParameters* p, LmiVideoFrameSharpenLevel sharpenLevel)
{
	p->sharpenLevel = sharpenLevel;

	return LMI_TRUE;
}

LMI_INLINE LmiBool LmiVideoFrameTransformParametersGetInputView(const LmiVideoFrameTransformParameters* p, LmiSizeT* inputWidth, LmiSizeT* inputHeight, LmiSizeT* inputOffsetLeft, LmiSizeT* inputOffsetTop)
{
	*inputWidth = p->inputWidth;
	*inputHeight = p->inputHeight;
	*inputOffsetLeft = p->inputOffsetLeft;
	*inputOffsetTop = p->inputOffsetTop;

	return LMI_TRUE;
}

LMI_INLINE LmiBool LmiVideoFrameTransformParametersGetResize(const LmiVideoFrameTransformParameters* p, LmiSizeT* resizeWidth, LmiSizeT* resizeHeight)
{
	*resizeWidth = p->resizeWidth;
	*resizeHeight = p->resizeHeight;

	return LMI_TRUE;
}

LMI_INLINE LmiImageRotationDegree LmiVideoFrameTransformParametersGetRotation(const LmiVideoFrameTransformParameters* p)
{
	return p->rotationDegrees;
}

LMI_INLINE LmiBool LmiVideoFrameTransformParametersGetMirror(const LmiVideoFrameTransformParameters* p)
{
	return p->mirror;
}

LMI_INLINE LmiBool LmiVideoFrameTransformParametersGetMargin(const LmiVideoFrameTransformParameters* p, LmiSizeT* marginLeft, LmiSizeT* marginRight, LmiSizeT* marginTop, LmiSizeT* marginBottom)
{
	*marginLeft = p->margin.left;
	*marginRight = p->margin.right;
	*marginTop = p->margin.top;
	*marginBottom = p->margin.bottom;

	return LMI_TRUE;
}


LMI_INLINE LmiVideoFrameDitherLevel LmiVideoFrameTransformParametersGetDitherLevel(const LmiVideoFrameTransformParameters* p)
{
	return p->ditherLevel;
}

LMI_INLINE LmiVideoFrameSharpenLevel LmiVideoFrameTransformParametersGetSharpenLevel(const LmiVideoFrameTransformParameters* p)
{
	return p->sharpenLevel;
}


/******************************************************************************************************************
 * Video Frame Implementation
 ******************************************************************************************************************/

LMI_INLINE LmiVideoFrame* LmiVideoFrameConstruct(LmiVideoFrame* x, const LmiMediaFormat* format, LmiSizeT width, LmiSizeT height, LmiVideoPlane plane[], LmiSizeT nPlanes, const LmiProperties* properties, LmiAllocator* alloc)
{
	return LmiVideoFrameConstructWithFrameAllocator(x, format, width, height, plane, nPlanes, properties, alloc, alloc);
}

LMI_INLINE LmiVideoFrame* LmiVideoFrameConstructFromKnownFormat(LmiVideoFrame* x, const LmiMediaFormat* format, LmiSizeT width, LmiSizeT height, void* imageBuffer, LmiSizeT imageSize, const LmiProperties* properties, LmiAllocator* alloc)
{
	return LmiVideoFrameConstructFromKnownFormatWithFrameAllocator(x, format, width, height, imageBuffer, imageSize, properties, alloc, alloc);
}

LMI_INLINE LmiBool LmiVideoFrameSwap(LmiVideoFrame* x, LmiVideoFrame* y)
{
	return LmiMediaFrameSwap(&x->base, &y->base);
}

LMI_INLINE const LmiMediaFrame *LmiVideoFrameGetMediaFrame(const LmiVideoFrame* f) {
	return &f->base;
}

LMI_INLINE LmiVideoFrameImpl* LmiVideoFrameGetImpl(const LmiVideoFrame* f)
{
	LmiAssert(LmiMediaFrameGetType(&f->base) == LMI_MEDIATYPE_Video);
	return (LmiVideoFrameImpl*)LmiMediaFrameGetImpl(&f->base);
}

LMI_INLINE const LmiMediaFormat *LmiVideoFrameGetFormat(const LmiVideoFrame* x) {
	return LmiMediaFrameGetFormat(&x->base);
}

LMI_INLINE const void *LmiVideoFrameGetBuffer(const LmiVideoFrame* x) {
	return LmiMediaFrameGetBuffer(&x->base);
}

LMI_INLINE const void *LmiVideoFrameGetPlaneImageConst(const LmiVideoFrame* x, LmiSizeT n)
{
	LmiVideoFrameImpl* impl = LmiVideoFrameGetImpl(x);
	if (n >= impl->nPlanes) return NULL;
	return LmiVideoPlaneGetImageConst(&impl->plane[n]);
}

LMI_INLINE void *LmiVideoFrameGetPlaneImage(const LmiVideoFrame* x, LmiSizeT n)
{
	LmiVideoFrameImpl* impl = LmiVideoFrameGetImpl(x);
	if (n >= impl->nPlanes) return NULL;
	return LmiVideoPlaneGetImage(&impl->plane[n]);
}

LMI_INLINE LmiSizeT LmiVideoFrameGetSize(const LmiVideoFrame* x) {
	return LmiMediaFrameGetSize(&x->base);
}

LMI_INLINE LmiAllocator *LmiVideoFrameGetAllocator(const LmiVideoFrame* x) {
	return LmiMediaFrameGetAllocator(&x->base);
}

LMI_INLINE LmiAllocator *LmiVideoFrameGetBufferAllocator(const LmiVideoFrame* x) {
	return LmiMediaFrameGetBufferAllocator(&x->base);
}

LMI_INLINE const LmiProperties *LmiVideoFrameGetPropertiesConst(const LmiVideoFrame* x) {
	return LmiMediaFrameGetPropertiesConst(&x->base);
}

LMI_INLINE LmiProperties *LmiVideoFrameGetProperties(LmiVideoFrame* x) {
	return LmiMediaFrameGetProperties(&x->base);
}

LMI_INLINE LmiSizeT LmiVideoFrameGetWidth(const LmiVideoFrame* x) {
	LmiVideoFrameImpl* impl = LmiVideoFrameGetImpl(x);
	return impl->width;
}

LMI_INLINE LmiSizeT LmiVideoFrameGetHeight(const LmiVideoFrame* x) {
	LmiVideoFrameImpl* impl = LmiVideoFrameGetImpl(x);
	return impl->height;
}

LMI_INLINE LmiSizeT LmiVideoFrameGetNumPlanes(const LmiVideoFrame* x) {
	LmiVideoFrameImpl* impl = LmiVideoFrameGetImpl(x);
	return impl->nPlanes;
}

/* Video frame plane convenience accessors */
LMI_INLINE const void *LmiVideoFrameGetPlaneBufferConst(const LmiVideoFrame* x, LmiSizeT n) {
	LmiVideoFrameImpl* impl = LmiVideoFrameGetImpl(x);
	if (n >= impl->nPlanes) return NULL;
	return LmiVideoPlaneGetBufferConst(&impl->plane[n]);
}

LMI_INLINE void *LmiVideoFrameGetPlaneBuffer(const LmiVideoFrame* x, LmiSizeT n) {
	LmiVideoFrameImpl* impl = LmiVideoFrameGetImpl(x);
	if (n >= impl->nPlanes) return NULL;
	return LmiVideoPlaneGetBuffer(&impl->plane[n]);
}

LMI_INLINE LmiSizeT LmiVideoFrameGetPlaneSize(const LmiVideoFrame* x, LmiSizeT n) {
	LmiVideoFrameImpl* impl = LmiVideoFrameGetImpl(x);
	if (n >= impl->nPlanes) return 0;
	return LmiVideoPlaneGetSize(&impl->plane[n]);
}

LMI_INLINE LmiSizeT LmiVideoFrameGetPlaneWidth(const LmiVideoFrame* x, LmiSizeT n) {
	LmiVideoFrameImpl* impl = LmiVideoFrameGetImpl(x);
	if (n >= impl->nPlanes) return 0;
	return LmiVideoPlaneGetWidth(&impl->plane[n]);
}

LMI_INLINE LmiSizeT LmiVideoFrameGetPlaneHeight(const LmiVideoFrame* x, LmiSizeT n) {
	LmiVideoFrameImpl* impl = LmiVideoFrameGetImpl(x);
	if (n >= impl->nPlanes) return 0;
	return LmiVideoPlaneGetHeight(&impl->plane[n]);
}

LMI_INLINE LmiSizeT LmiVideoFrameGetPlanePitch(const LmiVideoFrame* x, LmiSizeT n) {
	LmiVideoFrameImpl* impl = LmiVideoFrameGetImpl(x);
	if (n >= impl->nPlanes) return 0;
	return LmiVideoPlaneGetPitch(&impl->plane[n]);
}

LMI_INLINE LmiSizeT LmiVideoFrameGetPlaneOffset(const LmiVideoFrame* x, LmiSizeT n) {
	LmiVideoFrameImpl* impl = LmiVideoFrameGetImpl(x);
	if (n >= impl->nPlanes) return 0;
	return LmiVideoPlaneGetOffset(&impl->plane[n]);
}

LMI_INLINE LmiSizeT LmiVideoFrameGetPlanePixelPitch(const LmiVideoFrame* x, LmiSizeT n) {
	LmiVideoFrameImpl* impl = LmiVideoFrameGetImpl(x);
	if (n >= impl->nPlanes) return 0;
	return LmiVideoPlaneGetPixelPitch(&impl->plane[n]);
}

LMI_INLINE LmiBool LmiVideoFrameIsExclusive(LmiVideoFrame *x)
{
	return LmiMediaFrameIsExclusive(&x->base);
}

LMI_INLINE LmiBool LmiVideoFrameSetTimeProperties(LmiVideoFrame* x, LmiTime elapsedTime, LmiTime timestamp)
{
	return LmiMediaFrameSetTimeProperties(&x->base, elapsedTime, timestamp);
}

LMI_INLINE LmiBool LmiVideoFrameSetLocationProperties(LmiVideoFrame* x, const LmiLocation* location)
{
	return LmiMediaFrameSetLocationProperties(&x->base, location);
}

LMI_INLINE LmiBool LmiVideoFrameSetCodecMimeTypeProperty(LmiVideoFrame* x, const LmiString* codecMimeType)
{
	return LmiMediaFrameSetCodecMimeTypeProperty(&x->base, codecMimeType);
}

LMI_INLINE LmiBool LmiVideoFrameSetCodecMimeTypePropertyCStr(LmiVideoFrame* x, const char* codecMimeType)
{
	return LmiMediaFrameSetCodecMimeTypePropertyCStr(&x->base, codecMimeType);
}

LMI_INLINE LmiTime LmiVideoFrameGetElapsedTime(const LmiVideoFrame* x)
{
	return LmiMediaFrameGetElapsedTime(&x->base);
}

LMI_INLINE LmiTime LmiVideoFrameGetTimestamp(const LmiVideoFrame* x)
{
	return LmiMediaFrameGetTimestamp(&x->base);
}

LMI_INLINE LmiBool LmiVideoFrameGetCodecMimeType(const LmiVideoFrame* x, LmiString* codecMimeType)
{
	return LmiMediaFrameGetCodecMimeType(&x->base, codecMimeType);
}
