#include "LiveSourceWithx264.hh"
#include <GroupsockHelper.hh>
#include "InputFile.hh"

#include "H264VideoRTPSink.hh"
#include "H264VideoStreamFramer.hh"
#include "H264or5VideoRTPSink.hh"
#include "H264or5VideoStreamFramer.hh"

//#ifndef H264_LIVE_SERVER_MEDIASESSION_HH_
#include "H264LiveServerMediaSession.hh"
//#endif

uint64_t LiveSourceWithx264::getSystemDateTimeInMS(void) {
	uint64_t timeInMS = 0;
	struct timeval currentTime = { 0 }; /*< Current time */
	gettimeofday(&currentTime, NULL);
	timeInMS = ((uint64_t) (currentTime.tv_sec * (uint64_t) 1000)
			+ (uint64_t) (currentTime.tv_usec / (uint64_t) 1000));
	return timeInMS;
}

void LiveSourceWithx264::LiveStream_cameraFrameData(unsigned char* mFrameByte,
		unsigned mFrameSize, struct timeval mPresentationTime,
		uint64_t packetArrivalTime) {

	isContinue = true;
	
	QUEUE camFrame;
	camFrame.Framedata = (unsigned char *) calloc(1, mFrameSize);
	camFrame.framesize = mFrameSize;
	camFrame.PresentationTime = mPresentationTime;
	camFrame.frameArrivalTime = packetArrivalTime;

	memcpy(camFrame.Framedata, mFrameByte, mFrameSize);
	camQueue.push(camFrame);
	//envir().taskScheduler().triggerEvent(((H264LiveServerMediaSession *)videoLiveSession)->eventTriggerId,this);
	if (isContinue) {
		sem_post(waitForFrame);	//wait for frame delivered
	}

}

void LiveSourceWithx264::stopLiveFrameSources() {
	isContinue = false;
}

LiveSourceWithx264* LiveSourceWithx264::createNew(UsageEnvironment& env,
		void *livesession) {
	return new LiveSourceWithx264(env, livesession);
}

LiveSourceWithx264::LiveSourceWithx264(UsageEnvironment& env, void *livesession) :
		FramedSource(env) {
	isContinue = true;
	head = NULL;
	eventTriggerId = 0;
	videoLiveSession = livesession;
	frameTimeDiffDuration = 0;
	if (videoLiveSession != NULL) {
		((H264LiveServerMediaSession *) videoLiveSession)->liveSourceAvailable =
				false;
	}

	waitForFrame = sem_open("Aframe", O_CREAT, 0644, 0);
}

LiveSourceWithx264::~LiveSourceWithx264(void) {
	((H264LiveServerMediaSession *) videoLiveSession)->mtx.lock();
	((H264LiveServerMediaSession *) videoLiveSession)->liveSourceAvailable = 0;
	((H264LiveServerMediaSession *) videoLiveSession)->liveVideosource = NULL;
	isContinue = false;
	frameTimeDiffDuration = 0;
	sem_destroy(waitForFrame);
	while (!camQueue.empty()) {
		QUEUE camFrame;
		camFrame = camQueue.front();
		free(camFrame.Framedata);
		camFrame.Framedata = NULL;
		camQueue.pop();
	}

	((H264LiveServerMediaSession *) videoLiveSession)->mtx.unlock();
}

void LiveSourceWithx264::deliverFrame0(void* clientData) {
	((LiveSourceWithx264*) clientData)->deliverFrame();
}

void LiveSourceWithx264::doGetNextFrame() {
	deliverFrame();
}

void LiveSourceWithx264::deliverFrame() {
	int fifoStat = 0;
	unsigned FrameSize = 0;
	unsigned char *FrameData = NULL;
	int trancate = 0;
	if (!isCurrentlyAwaitingData()) {
		printf("we're not ready for the data yet StreamName %s size %d\n",
				streamName.c_str(), camQueue.size());
		return; // we're not ready for the data yet
	}
	if (isContinue) {
		QUEUE camFrame;
		if ((!camQueue.empty()))
		{
			camFrame = camQueue.front();
			FrameSize = camFrame.framesize;
			FrameData = camFrame.Framedata;

			gettimeofday(&fPresentationTime, NULL);

			currSystemTime = getSystemDateTimeInMS();
			printf("Queuesize %d delta %d %s\n", camQueue.size(),
					(currSystemTime - prevSystemTime), streamName.c_str());

			prevSystemTime = currSystemTime;

			fFrameSize = FrameSize;
			memmove(fTo, FrameData + trancate, fFrameSize);
			free(camFrame.Framedata);
			camFrame.Framedata = NULL;
			camQueue.pop();
		}
		else
		{
			int ret = sem_wait(waitForFrame);
			if (ret < 0) {
				printf("AACFramsource sem_wait failed\n");
			}
			return deliverFrame0(this);

		}

		isContinue = true;
		FramedSource::afterGetting(this);
	} 
}
