/**
{file:
	{name: LmiVideoBuffer.h}
	{description: Buffer for video frames}
	{copyright:
		(c) 2010-2015 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_VIDEOBUFFER_H
#define LMI_VIDEOBUFFER_H

#include <Lmi/Utils/LmiAllocator.h>
#include <Lmi/Utils/LmiDeque.h>
#include <Lmi/Video/Common/LmiVideoCommon.h>
#include <Lmi/Media/Common/LmiMediaFrame.h>
#include <Lmi/Media/Common/LmiMediaMinMaxTracker.h>

LMI_BEGIN_EXTERN_C

/**
{type visibility="private":
	{name: LmiVideoBufferDebugInfo}
	{parent: LmiVideoBuffer}
	{include: Lmi/Video/Common/LmiVideoBuffer.h}
	{description: Video buffer debugging information.}
}
*/

typedef struct LmiVideoBufferDebugInfo_ {
	LmiString label;
	LmiTime totalDuration;
	LmiTime fps;

	LmiTime played;
	LmiUint underrun;
	LmiUint overrun;
} LmiVideoBufferDebugInfo;

/**
{function visibility="private":
	{name: LmiVideoBufferDebugInfoConstruct}
	{parent: LmiVideoBuffer}
	{description: Constructs an LmiVideoBufferDebugInfo object.}
	{prototype: LmiVideoBufferDebugInfo *LmiVideoBufferDebugInfoConstruct(LmiVideoBufferDebugInfo *x, LmiAllocator *a)}
	{parameter: {name: x} {description: The video buffer debug info object.}}
	{parameter: {name: a} {description: An allocator to be used for memory.}}
	{return: A pointer to a constructed object on success, or NULL on failure.}
}
*/
LmiVideoBufferDebugInfo *LmiVideoBufferDebugInfoConstruct(LmiVideoBufferDebugInfo *x, LmiAllocator *a);

/**
{function visibility="private":
	{name: LmiVideoBufferDebugInfoDestruct}
	{parent: LmiVideoBuffer}
	{description: Destructs an LmiVideoBufferDebugInfo object.}
	{prototype: void LmiVideoBufferDebugInfoDestruct(LmiVideoBufferDebugInfo *x)}
	{parameter: {name: x} {description: The video buffer debug info object.}}
}
*/
void LmiVideoBufferDebugInfoDestruct(LmiVideoBufferDebugInfo *x);

/**
{function visibility="private":
	{name: LmiVideoBufferDebugInfoConstructCopy}
	{parent: LmiVideoBuffer}
	{description: Constructs a copy of an LmiVideoBufferDebugInfo object.}
	{prototype: LmiVideoBufferDebugInfo *LmiVideoBufferDebugInfoConstructCopy(LmiVideoBufferDebugInfo *d, const LmiVideoBufferDebugInfo *s)}
	{parameter: {name: d} {description: The video buffer debug info object to construct.}}
	{parameter: {name: s} {description: The video buffer debug info object to construct from.}}
	{return: A pointer to a constructed object on success, or NULL on failure.}
}
*/
LmiVideoBufferDebugInfo *LmiVideoBufferDebugInfoConstructCopy(LmiVideoBufferDebugInfo *d, const LmiVideoBufferDebugInfo *s);

/**
{function visibility="private":
	{name: LmiVideoBufferDebugInfoAssign}
	{parent: LmiVideoBuffer}
	{description: Assigns an LmiVideoBufferDebugInfo object.}
	{prototype: LmiVideoBufferDebugInfo *LmiVideoBufferDebugInfoAssign(LmiVideoBufferDebugInfo *d, const LmiVideoBufferDebugInfo *s)}
	{parameter: {name: d} {description: The video buffer debug info object to assign.}}
	{parameter: {name: s} {description: The video buffer debug info object to assign from.}}
	{return: A pointer to an assigned object on success, or NULL on failure.}
}
*/
LmiVideoBufferDebugInfo *LmiVideoBufferDebugInfoAssign(LmiVideoBufferDebugInfo *d, const LmiVideoBufferDebugInfo *s);

/**
{function visibility="private":
	{name: LmiVideoBufferDebugInfoEqual}
	{parent: LmiVideoBuffer}
	{description: Checks whether LmiVideoBufferDebugInfo objects are equal.}
	{prototype: LmiBool LmiVideoBufferDebugInfoEqual(const LmiVideoBufferDebugInfo *a, const LmiVideoBufferDebugInfo *b)}
	{parameter: {name: a} {description: First video buffer debug info object.}}
	{parameter: {name: b} {description: Second video buffer debug info object.}}
	{return: A boolean indicating whether the video buffer debug objects are equal.}
}
*/
LmiBool LmiVideoBufferDebugInfoEqual(const LmiVideoBufferDebugInfo *a, const LmiVideoBufferDebugInfo *b);

typedef struct
{
	LmiVideoFrame videoFrame;
	LmiUint frameNum;
	LmiBool syncRender;
} LmiVideoBufferImage;

LmiVideoBufferImage *LmiVideoBufferImageConstruct(LmiVideoBufferImage *i, const LmiVideoFrame *videoFrame, LmiUint frameNum, LmiBool syncRender, LmiAllocator* a);
LmiVideoBufferImage *LmiVideoBufferImageConstructCopy(LmiVideoBufferImage *d, const LmiVideoBufferImage *s);
void LmiVideoBufferImageDestruct(LmiVideoBufferImage *i);

Declare_LmiDeque(LmiVideoBufferImage)

/**
{type visibility="private":
	{name: LmiVideoBuffer}
	{parent: VideoCommon}
	{include: Lmi/Video/Common/LmiVideoBuffer.h}
	{description: Video buffer provides de-jittering and delay management for audio/video lipsync and rendering smoothness.}
}
*/
typedef struct
{
	LmiMutex mutex;
	LmiAllocator *alloc;
	LmiTime totalDuration;
	LmiTime minDelay;
	LmiTime maxDelay;

	LmiBool charging;
	LmiBool discharging;
	LmiTime lastElapsedTime;
	LmiTime lastInputTime;
	LmiTime lastOutputTime;
	LmiTime lastOutputPollTime;

	LmiString label;

	LmiUint framesAdded;
	LmiUint framesRemoved;

	LmiVideoBufferDebugInfo debugInfo;
	LmiDeque(LmiVideoBufferImage) imageQueue;

	LmiMediaMinMaxTracker fpsTracker;
	LmiMediaMinMaxTracker delayTracker;
} LmiVideoBuffer;

/**
{function visibility="private":
	{name: LmiVideoBufferConstruct}
	{parent: LmiVideoBuffer}
	{description: Constructs LmiVideoBuffer for Video Frames.}
	{prototype: LmiVideoBuffer* LmiVideoBufferConstruct(LmiVideoBuffer* b, LmiAllocator* alloc)}
	{parameter: {name: b} {description: The LmiVideoBuffer object to construct.}}
	{parameter: {name: alloc} {description: The allocator to use.}}
	{return: A pointer to the constructed object on success, or NULL on failure.}
}
*/
LmiVideoBuffer *LmiVideoBufferConstruct(LmiVideoBuffer *b, LmiAllocator *alloc);

/**
{function visibility="private":
	{name: LmiVideoBufferConstructCopy}
	{parent: LmiVideoBuffer}
	{description: Constructs a copy of LmiVideoBuffer object.}
	{prototype: LmiVideoBuffer* LmiVideoBufferConstructCopy(LmiVideoBuffer* d, const LmiVideoBuffer* s)}
	{parameter: {name: d} {description: The LmiVideoBuffer object to construct.}}
	{parameter: {name: s} {description: The original object to copy.}}
	{return: A pointer to the constructed object on success, or NULL on failure.}
}
*/
LmiVideoBuffer *LmiVideoBufferConstructCopy(LmiVideoBuffer *d, const LmiVideoBuffer *s);

/**
{function visibility="private":
	{name: LmiVideoBufferDestruct}
	{parent: LmiVideoBuffer}
	{description: Destructs LmiVideoBuffer object.}
	{prototype: void LmiVideoBufferDestruct(LmiVideoBuffer* b)}
	{parameter: {name: b} {description: The LmiVideoBuffer object to destruct.}}
}
*/
void LmiVideoBufferDestruct(LmiVideoBuffer *b);

/**
{function visibility="private":
	{name: LmiVideoBufferAssign}
	{parent: LmiVideoBuffer}
	{description: Assigns the value of one LmiVideoBuffer object to another.}
	{prototype: LmiVideoBuffer* LmiVideoBufferAssign(LmiVideoBuffer* d, const LmiVideoBuffer* s)}
	{parameter: {name: d} {description: The LmiVideoBuffer object whose value to set.}}
	{parameter: {name: s} {description: The original object to copy.}}
	{return: A pointer to the constructed object on success, or NULL on failure.}
}
*/
LmiVideoBuffer *LmiVideoBufferAssign(LmiVideoBuffer *d, const LmiVideoBuffer *s);

LmiBool LmiVideoBufferSetLabel(LmiVideoBuffer *b, const char* label);
const char * LmiVideoBufferGetLabel(LmiVideoBuffer *b);
LmiBool LmiVideoBufferSetThresholds(LmiVideoBuffer *b, LmiTime minDelay, LmiTime maxDelay);
LmiTime LmiVideoBufferGetDuration(LmiVideoBuffer *b);
LmiUint LmiVideoBufferGetDurationInMilliseconds(LmiVideoBuffer *b);
LmiBool LmiVideoBufferAddFrame(LmiVideoBuffer *b, const LmiVideoFrame *videoFrame);
LmiBool LmiVideoBufferGetFrame(LmiVideoBuffer *b, LmiVideoFrame *videoFrame);
LmiBool LmiVideoBufferGetFrameBlocking(LmiVideoBuffer *b, LmiVideoFrame *videoFrame);
void LmiVideoBufferClear(LmiVideoBuffer *b);
LmiVideoBufferDebugInfo *LmiVideoBufferGetDebugInfo(LmiVideoBuffer *b);

LMI_END_EXTERN_C

#endif /* LMI_VIDEOBUFFER_H */
