298 lines
7.6 KiB
C++
298 lines
7.6 KiB
C++
|
|
||
|
#include <unistd.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <pthread.h>
|
||
|
#include <sys/time.h>
|
||
|
#include <stdint.h>
|
||
|
#include "avtimer.h"
|
||
|
#include "log.h"
|
||
|
|
||
|
//************************************************************//
|
||
|
//**************** define the avtimer context ****************//
|
||
|
//************************************************************//
|
||
|
typedef struct AvTimerContext
|
||
|
{
|
||
|
AvTimer sAvTimer; //* the avtimer interface.
|
||
|
|
||
|
int nSpeed; //* counting at this speed.
|
||
|
|
||
|
int64_t nStartTime; //* start counting from this time.
|
||
|
|
||
|
int eStatus; //* status of this timer.
|
||
|
|
||
|
struct timeval startOsTime; //* the system's time when this timer starts.
|
||
|
|
||
|
struct timeval lastOsTime; //* the system's time at last operation.
|
||
|
|
||
|
pthread_mutex_t mutex; //* mutex to lock the timer.
|
||
|
|
||
|
int64_t nStartPts; //* pts of the first frame
|
||
|
int64_t nStartSystemTime; //* render systemtime of the first frame
|
||
|
}AvTimerContext;
|
||
|
|
||
|
|
||
|
static int64_t __systemTime()
|
||
|
{
|
||
|
struct timespec t;
|
||
|
t.tv_sec = t.tv_nsec = 0;
|
||
|
clock_gettime(CLOCK_MONOTONIC, &t);
|
||
|
return t.tv_sec*1000000000LL + t.tv_nsec;
|
||
|
}
|
||
|
|
||
|
//************************************************************//
|
||
|
//****************** declare static methods ******************//
|
||
|
//************************************************************//
|
||
|
static int AvTimerSetSpeed(AvTimer* t, int nSpeed);
|
||
|
|
||
|
static int AvTimerGetSpeed(AvTimer* t);
|
||
|
|
||
|
static int AvTimerSetTime(AvTimer* t, int64_t nTime);
|
||
|
|
||
|
static int64_t AvTimerGetTime(AvTimer* t);
|
||
|
|
||
|
static int64_t AvTimerPtsToSystemTime(AvTimer* t, int64_t pts);
|
||
|
|
||
|
static int AvTimerStart(AvTimer* t);
|
||
|
|
||
|
static void AvTimerStop(AvTimer* t);
|
||
|
|
||
|
static int AvTimerGetStatus(AvTimer* t);
|
||
|
|
||
|
|
||
|
|
||
|
//************************************************************//
|
||
|
//********************** implementation **********************//
|
||
|
//************************************************************//
|
||
|
|
||
|
AvTimer* AvTimerCreate(void)
|
||
|
{
|
||
|
AvTimerContext* pAvTimerCtx;
|
||
|
AvTimer* pAvTimer;
|
||
|
|
||
|
pAvTimerCtx = (AvTimerContext*) malloc(sizeof(AvTimerContext));
|
||
|
if(pAvTimerCtx == NULL)
|
||
|
{
|
||
|
loge("malloc memory fail.");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
memset(pAvTimerCtx, 0, sizeof(AvTimerContext));
|
||
|
|
||
|
pAvTimer = (AvTimer*)pAvTimerCtx;
|
||
|
|
||
|
pAvTimer->SetSpeed = AvTimerSetSpeed;
|
||
|
pAvTimer->GetSpeed = AvTimerGetSpeed;
|
||
|
pAvTimer->SetTime = AvTimerSetTime;
|
||
|
pAvTimer->GetTime = AvTimerGetTime;
|
||
|
pAvTimer->PtsToSystemTime = AvTimerPtsToSystemTime;
|
||
|
pAvTimer->Start = AvTimerStart;
|
||
|
pAvTimer->Stop = AvTimerStop;
|
||
|
pAvTimer->GetStatus = AvTimerGetStatus;
|
||
|
|
||
|
pAvTimerCtx->nSpeed = 1000;
|
||
|
pAvTimerCtx->nStartTime = 0;
|
||
|
pAvTimerCtx->eStatus = TIMER_STATUS_STOP;
|
||
|
|
||
|
pthread_mutex_init(&pAvTimerCtx->mutex, NULL);
|
||
|
|
||
|
return pAvTimer;
|
||
|
}
|
||
|
|
||
|
|
||
|
void AvTimerDestroy(AvTimer* t)
|
||
|
{
|
||
|
AvTimerContext* pAvTimerCtx;
|
||
|
|
||
|
pAvTimerCtx = (AvTimerContext*)t;
|
||
|
|
||
|
pthread_mutex_destroy(&pAvTimerCtx->mutex);
|
||
|
|
||
|
free(pAvTimerCtx);
|
||
|
}
|
||
|
|
||
|
|
||
|
static int AvTimerStart(AvTimer* t)
|
||
|
{
|
||
|
AvTimerContext* pAvTimerCtx;
|
||
|
|
||
|
pAvTimerCtx = (AvTimerContext*)t;
|
||
|
|
||
|
pthread_mutex_lock(&pAvTimerCtx->mutex);
|
||
|
|
||
|
pAvTimerCtx->eStatus = TIMER_STATUS_START;
|
||
|
|
||
|
//* record the system's time when timer starts.
|
||
|
gettimeofday(&pAvTimerCtx->startOsTime, NULL);
|
||
|
|
||
|
pAvTimerCtx->lastOsTime.tv_sec = pAvTimerCtx->startOsTime.tv_sec;
|
||
|
pAvTimerCtx->lastOsTime.tv_usec = pAvTimerCtx->startOsTime.tv_usec;
|
||
|
|
||
|
pthread_mutex_unlock(&pAvTimerCtx->mutex);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void AvTimerStop(AvTimer* t)
|
||
|
{
|
||
|
AvTimerContext* pAvTimerCtx;
|
||
|
int64_t nPassedTime;
|
||
|
|
||
|
pAvTimerCtx = (AvTimerContext*)t;
|
||
|
|
||
|
pthread_mutex_lock(&pAvTimerCtx->mutex);
|
||
|
|
||
|
//* record the system's time when timer stops.
|
||
|
gettimeofday(&pAvTimerCtx->lastOsTime, NULL);
|
||
|
|
||
|
//* change the start counting point.
|
||
|
nPassedTime = (int64_t)(pAvTimerCtx->lastOsTime.tv_sec - pAvTimerCtx->startOsTime.tv_sec) * 1000000;
|
||
|
nPassedTime += (pAvTimerCtx->lastOsTime.tv_usec - pAvTimerCtx->startOsTime.tv_usec);
|
||
|
|
||
|
pAvTimerCtx->nStartTime += pAvTimerCtx->nSpeed * nPassedTime / 1000;
|
||
|
|
||
|
pAvTimerCtx->startOsTime.tv_sec = pAvTimerCtx->lastOsTime.tv_sec;
|
||
|
pAvTimerCtx->startOsTime.tv_usec = pAvTimerCtx->lastOsTime.tv_usec;
|
||
|
|
||
|
pAvTimerCtx->eStatus = TIMER_STATUS_STOP;
|
||
|
|
||
|
pthread_mutex_unlock(&pAvTimerCtx->mutex);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int AvTimerSetSpeed(AvTimer* t, int nSpeed)
|
||
|
{
|
||
|
AvTimerContext* pAvTimerCtx;
|
||
|
int64_t nPassedTime;
|
||
|
|
||
|
pAvTimerCtx = (AvTimerContext*)t;
|
||
|
|
||
|
pthread_mutex_lock(&pAvTimerCtx->mutex);
|
||
|
|
||
|
//* record the system's time.
|
||
|
gettimeofday(&pAvTimerCtx->lastOsTime, NULL);
|
||
|
|
||
|
//* change the start counting point.
|
||
|
nPassedTime = (int64_t)(pAvTimerCtx->lastOsTime.tv_sec - pAvTimerCtx->startOsTime.tv_sec) * 1000000;
|
||
|
nPassedTime += (pAvTimerCtx->lastOsTime.tv_usec - pAvTimerCtx->startOsTime.tv_usec);
|
||
|
|
||
|
pAvTimerCtx->nStartTime += pAvTimerCtx->nSpeed * nPassedTime / 1000;
|
||
|
|
||
|
pAvTimerCtx->startOsTime.tv_sec = pAvTimerCtx->lastOsTime.tv_sec;
|
||
|
pAvTimerCtx->startOsTime.tv_usec = pAvTimerCtx->lastOsTime.tv_usec;
|
||
|
|
||
|
//* change the counting speed.
|
||
|
pAvTimerCtx->nSpeed = nSpeed;
|
||
|
|
||
|
pthread_mutex_unlock(&pAvTimerCtx->mutex);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int AvTimerGetSpeed(AvTimer* t)
|
||
|
{
|
||
|
AvTimerContext* pAvTimerCtx;
|
||
|
|
||
|
pAvTimerCtx = (AvTimerContext*)t;
|
||
|
|
||
|
return pAvTimerCtx->nSpeed;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int AvTimerGetStatus(AvTimer* t)
|
||
|
{
|
||
|
AvTimerContext* pAvTimerCtx;
|
||
|
|
||
|
pAvTimerCtx = (AvTimerContext*)t;
|
||
|
|
||
|
return pAvTimerCtx->eStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int64_t AvTimerGetTime(AvTimer* t)
|
||
|
{
|
||
|
AvTimerContext* pAvTimerCtx;
|
||
|
int64_t nPassedTime;
|
||
|
int64_t c;
|
||
|
|
||
|
pAvTimerCtx = (AvTimerContext*)t;
|
||
|
|
||
|
pthread_mutex_lock(&pAvTimerCtx->mutex);
|
||
|
|
||
|
if(pAvTimerCtx->eStatus == TIMER_STATUS_START)
|
||
|
{
|
||
|
//* record the system's time.
|
||
|
gettimeofday(&pAvTimerCtx->lastOsTime, NULL);
|
||
|
|
||
|
//* change the start counting point.
|
||
|
nPassedTime = (int64_t)(pAvTimerCtx->lastOsTime.tv_sec - pAvTimerCtx->startOsTime.tv_sec) * 1000000;
|
||
|
nPassedTime += (pAvTimerCtx->lastOsTime.tv_usec - pAvTimerCtx->startOsTime.tv_usec);
|
||
|
|
||
|
nPassedTime = pAvTimerCtx->nStartTime + (pAvTimerCtx->nSpeed * nPassedTime / 1000);
|
||
|
}
|
||
|
else //* in stop status.
|
||
|
{
|
||
|
//* return the last record time.
|
||
|
nPassedTime = pAvTimerCtx->nStartTime;
|
||
|
}
|
||
|
|
||
|
pthread_mutex_unlock(&pAvTimerCtx->mutex);
|
||
|
|
||
|
return nPassedTime;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int64_t AvTimerPtsToSystemTime(AvTimer* t, int64_t pts)
|
||
|
{
|
||
|
AvTimerContext* pAvTimerCtx;
|
||
|
int64_t nPtsAbs;
|
||
|
|
||
|
pAvTimerCtx = (AvTimerContext*)t;
|
||
|
|
||
|
pthread_mutex_lock(&pAvTimerCtx->mutex);
|
||
|
|
||
|
if(pAvTimerCtx->eStatus == TIMER_STATUS_START)
|
||
|
{
|
||
|
//* record the system's time.
|
||
|
nPtsAbs = pAvTimerCtx->nStartSystemTime + (pts - pAvTimerCtx->nStartPts) * 1000LL;
|
||
|
}
|
||
|
else //* in stop status.
|
||
|
{
|
||
|
//* return the last record time.
|
||
|
nPtsAbs = pAvTimerCtx->nStartSystemTime;
|
||
|
}
|
||
|
|
||
|
pthread_mutex_unlock(&pAvTimerCtx->mutex);
|
||
|
|
||
|
return nPtsAbs;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int AvTimerSetTime(AvTimer* t, int64_t nTime)
|
||
|
{
|
||
|
AvTimerContext* pAvTimerCtx;
|
||
|
int64_t c;
|
||
|
|
||
|
pAvTimerCtx = (AvTimerContext*)t;
|
||
|
|
||
|
pthread_mutex_lock(&pAvTimerCtx->mutex);
|
||
|
|
||
|
gettimeofday(&pAvTimerCtx->startOsTime, NULL);
|
||
|
|
||
|
pAvTimerCtx->lastOsTime.tv_sec = pAvTimerCtx->startOsTime.tv_sec;
|
||
|
pAvTimerCtx->lastOsTime.tv_usec = pAvTimerCtx->startOsTime.tv_usec;
|
||
|
|
||
|
pAvTimerCtx->nStartTime = nTime;
|
||
|
|
||
|
pAvTimerCtx->nStartPts = nTime;
|
||
|
pAvTimerCtx->nStartSystemTime = __systemTime() + 30000000LL;
|
||
|
|
||
|
pthread_mutex_unlock(&pAvTimerCtx->mutex);
|
||
|
|
||
|
return 0;
|
||
|
}
|