/*******************************************************}
{
}
{ File : MPEGPSBitrateAnalyzer.h }
{ Created by Tsviatko Jongov }
{ http://tsviatko.jongov.com }
{
}
{ Program stream bitrate analyzer. }
{
}
{*******************************************************/
#ifndef
__MPEGPSBITRATEANALYZER_H__
#define
__MPEGPSBITRATEANALYZER_H__
#include <vector>
#include "MPEGPSUtils.h"
#include "Buffer.h"
#include "Thread.h"
struct
MPEGPSClock
{
__int64
FilePosition; //File
position in bytes
__int64
Clock; //Clock
in 27 MHz units (27 000 000 = 1 second)
};
class
CMPEGPSBitrateAnalyzer : public CThread
{
protected:
FILE * m_FileStream;
CBuffer * m_Buffer;
__int64
m_FilePosition;
__int64
m_FileSize;
pack_header m_pack_header;
HANDLE m_ExitEvent;
char
m_FileName[MAX_PATH];
bool
m_FileToLoad;
bool
m_Analyzing;
double
m_Progress;
CRITICAL_SECTION m_ProgressCriticalSection;
CRITICAL_SECTION
m_ClockListCriticalSection;
bool
m_StopAnalyze;
std::vector<MPEGPSClock*>
m_ClockList;
protected:
HRESULT Process()
{
unsigned
char * P;
unsigned
long Len;
__int64
Clck;
__int64
FP;
P = m_Buffer->Head();
Len = m_Buffer->Len();
while
(Len > 50)
{
if
(*((DWORD *)(P)) == PACK_START_CODE_SWP)
{
//parse
clock
if
(ParsePackHeader(P, Len, &m_pack_header))
{
Clck =
GetSCRInt64(&m_pack_header);
FP = m_FilePosition + (P -
m_Buffer->Head() + 6);
AddClock(FP, Clck);
P += 10;
Len -= 10;
}
}
P++;
Len--;
}
m_FilePosition += m_Buffer->Len() -
Len;
m_Buffer->m_First =
m_Buffer->Len() - Len;
m_Buffer->Compact();
return
S_OK;
}
HRESULT ClearClockList()
{
for (unsigned long i = 0;
i < m_ClockList.size(); i++)
{
delete
m_ClockList[i];
}
m_ClockList.clear();
return true;
}
HRESULT AddClock(__int64
FilePosition, __int64 Clock)
{
EnterCriticalSection(&m_ClockListCriticalSection);
MPEGPSClock * Clk = new MPEGPSClock;
Clk->FilePosition = FilePosition;
Clk->Clock = Clock;
m_ClockList.push_back(Clk);
LeaveCriticalSection(&m_ClockListCriticalSection);
return
S_OK;
}
int
ThreadFunc(void)
{
unsigned
long Read;
__int64
ReadSoFar;
for
(;;)
{
if
(WaitForSingleObject(m_ExitEvent, 0) == WAIT_OBJECT_0)
{
break;
}
if
(m_StopAnalyze)
{
m_FileToLoad = false;
if
(m_FileStream)
{
fclose(m_FileStream);
m_FileStream = NULL;
}
m_StopAnalyze = false;
m_Analyzing = false;
m_Buffer->Empty();
}
if
(m_FileToLoad)
{
m_Analyzing = true;
m_FileToLoad = false;
ReadSoFar = 0;
if
(m_FileStream)
{
fclose(m_FileStream);
m_FileStream = NULL;
}
if
(fopen_s(&m_FileStream, m_FileName, "rb")
== 0)
{
_fseeki64(m_FileStream, 0,
SEEK_END);
m_FileSize =
_ftelli64(m_FileStream);
_fseeki64(m_FileStream, 0,
SEEK_SET);
}
m_FilePosition = 0;
ClearClockList();
}
if
(m_FileStream)
{
Read = (unsigned long)fread(m_Buffer->Tail(),
1, 1024 * 1024, m_FileStream);
if
(Read <= 0)
{
if
(m_FileStream)
{
fclose(m_FileStream);
m_FileStream = NULL;
}
m_Analyzing = false;
EnterCriticalSection(&m_ProgressCriticalSection);
m_Progress = 100.0;
LeaveCriticalSection(&m_ProgressCriticalSection);
continue;
}
else
{
m_Buffer->m_Last +=
Read;
}
if
(Process() != S_OK)
{
OutputDebugString(L"tsv: Warning - invalid program stream.");
if
(m_FileStream)
{
fclose(m_FileStream);
m_FileStream = NULL;
}
m_Analyzing = false;
continue;
}
ReadSoFar += Read;
EnterCriticalSection(&m_ProgressCriticalSection);
m_Progress = 100 * ((double)ReadSoFar / m_FileSize);
LeaveCriticalSection(&m_ProgressCriticalSection);
}
Sleep(1);
}
return
0;
}
public:
CMPEGPSBitrateAnalyzer():
m_Progress(0.0),
m_FileStream(NULL)
{
SetThreadPriority(THREAD_PRIORITY_NORMAL);
m_Buffer = new
CBuffer(2 * 1024 * 1024);
m_Buffer->Empty();
m_ExitEvent = CreateEvent(NULL, false, false, NULL);
InitializeCriticalSection(&m_ClockListCriticalSection);
InitializeCriticalSection(&m_ProgressCriticalSection);
ResumeThread();
}
virtual ~CMPEGPSBitrateAnalyzer()
{
SetEvent(m_ExitEvent);
WaitFor();
CloseHandle(m_ExitEvent);
delete
m_Buffer;
ClearClockList();
DeleteCriticalSection(&m_ClockListCriticalSection);
DeleteCriticalSection(&m_ProgressCriticalSection);
}
HRESULT AnalyzeFile(char * FileName)
{
m_StopAnalyze = false;
if
(m_Analyzing)
{
m_StopAnalyze = true;
for
(;;)
{
if
(!m_StopAnalyze)
{
break;
}
Sleep(1);
}
}
if
(!IsPS(FileName))
{
return
false;
}
memset(m_FileName, 0, MAX_PATH);
memcpy(m_FileName, FileName,
strlen(FileName));
m_FileToLoad = true;
return
S_OK;
}
HRESULT GetProgress(double * PercentProgress)
{
EnterCriticalSection(&m_ProgressCriticalSection);
*PercentProgress = m_Progress;
LeaveCriticalSection(&m_ProgressCriticalSection);
return
S_OK;
}
HRESULT StopAnalyze()
{
m_StopAnalyze = true;
for
(;;)
{
if
(!m_StopAnalyze)
{
break;
}
Sleep(1);
}
return
S_OK;
}
unsigned long GetClockListsCount()
{
return
1;
}
unsigned long GetClocksCount(unsigned
long ClockListIndex)
{
if
(ClockListIndex != 0)
{
OutputDebugString(L"tsv: Error in CMPEGPSBitrateAnalyzer.GetClocksCount
- invalid clock list index.");
return
E_FAIL;
}
unsigned
long Cnt = 0;
EnterCriticalSection(&m_ClockListCriticalSection);
Cnt = (unsigned
long)m_ClockList.size();
LeaveCriticalSection(&m_ClockListCriticalSection);
return Cnt;
}
HRESULT GetClockItem(unsigned long
ClockListIndex, unsigned long ClockItemIndex, __int64
* FilePosition, __int64 * Clock)
{
if
(ClockListIndex != 0)
{
OutputDebugString(L"tsv: Error in CMPEGPSBitrateAnalyzer.GetClockItem -
invalid clock list index.");
return
E_FAIL;
}
HRESULT hr = S_OK;
EnterCriticalSection(&m_ClockListCriticalSection);
if
(ClockItemIndex >= m_ClockList.size())
{
OutputDebugString(L"tsv: Error in CMPEGPSBitrateAnalyzer.GetClockItem -
invalid clock item index.");
hr = E_FAIL;
}
if (hr
== S_OK)
{
*FilePosition =
m_ClockList[ClockItemIndex]->FilePosition;
*Clock =
m_ClockList[ClockItemIndex]->Clock;
}
LeaveCriticalSection(&m_ClockListCriticalSection);
return
hr;
}
HRESULT GetNearestNextClockItem(unsigned long
ClockListIndex, __int64 * FilePosition, __int64 * Clock, unsigned
long * ClockItemIndex)
{
if
(ClockListIndex != 0)
{
OutputDebugString(L"tsv: Error in
CMPEGPSBitrateAnalyzer.GetNearestNextClockItem - invalid clock list
index.");
return
E_FAIL;
}
HRESULT hr = E_FAIL;
EnterCriticalSection(&m_ClockListCriticalSection);
for (unsigned long i = 0;
i < m_ClockList.size(); i++)
{
if
(m_ClockList[i]->FilePosition >= *FilePosition)
{
*FilePosition =
m_ClockList[i]->FilePosition;
*Clock =
m_ClockList[i]->Clock;
*ClockItemIndex = i;
hr = S_OK;
break;
}
}
LeaveCriticalSection(&m_ClockListCriticalSection);
return
hr;
}
};
#endif // __MPEGPSBITRATEANALYZER_H__