// TSRecordingDlg.cpp : implementation file
//

#include "stdafx.h"

#include "SDKDemo.h"
#include "TSRecordingDlg.h"
#include "RecFile.h"

#include "IB2C2MPEG2DataCtrl.h"


#define RECORDING_STATUS_TIMER			1
#define RECORDING_STATUS_TIMER_PIODE	100


CTimeShiftRecFile m_pRecFile;

int CTSRecordingDlg::m_iPacketsProcessed = 0;
int CTSRecordingDlg::m_iContinuityErrors = 0;
BOOL CTSRecordingDlg::bInitializeContinuity = FALSE;
BYTE CTSRecordingDlg::bt[0x1fff];

UINT __stdcall
CTSRecordingDlg::ProcessTransportStreamPacket ( WORD wPID, unsigned char* pucTransportPacket )
{
	m_iPacketsProcessed++;

	m_pRecFile.Write( pucTransportPacket, 188);

	CheckPidContinuityCounter(wPID, pucTransportPacket);

	return (UINT) 1;
}


// CTSRecordingDlg dialog

IMPLEMENT_DYNAMIC(CTSRecordingDlg, CDialog)

CTSRecordingDlg::CTSRecordingDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CTSRecordingDlg::IDD, pParent)
{
	m_iPacketsProcessed = 0;
	m_iContinuityErrors = 0;

	m_iTimerCounts = 0;

	bInitializeContinuity = FALSE;
}

CTSRecordingDlg::~CTSRecordingDlg()
{
}

void CTSRecordingDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}


BEGIN_MESSAGE_MAP(CTSRecordingDlg, CDialog)
	ON_BN_CLICKED(IDCANCEL, &CTSRecordingDlg::OnBnClickedCancel)
	ON_WM_DESTROY()
	ON_WM_TIMER()
END_MESSAGE_MAP()

// CTSRecordingDlg message handlers

BOOL CTSRecordingDlg::OnInitDialog()
{
	HRESULT					hr;

	CDialog::OnInitDialog();

	hr = m_pB2FilterGraph->GetDataControl()->SetCallbackForTransportStream(&CTSRecordingDlg::ProcessTransportStreamPacket);

	// Set special PID to enable receipt of full Transport Stream
	long lDataPid[1] = { 0x2000 } ;
	hr = m_pB2FilterGraph->GetDataControl()->AddTsPIDs( 1 , lDataPid);

//	m_pB2FilterGraph->GetMulticastControl()->Enable();
//	m_pB2FilterGraph->GetMulticastControl()->SetNetworkInterface(m_pMulticastInfo->szNetworkAdapter);
//	m_pB2FilterGraph->GetMulticastControl()->StartMulticast(m_pMulticastInfo->szMulticastAddress,
//		m_pMulticastInfo->wMulticastPort, m_pMulticastInfo->lPIDCount, m_pMulticastInfo->alPIDList);


	// Start Recording Status display update timer
	SetTimer(RECORDING_STATUS_TIMER, RECORDING_STATUS_TIMER_PIODE, NULL);



#define MAX_PATH_NAME	512


	WCHAR wsRecPathName[MAX_PATH_NAME];

	// Generate Timeshift file name
	GenerateTimeStampedFilename(&m_cstrRecordPathName, ".\\", "Capture" );

	LPTSTR lpStr = m_cstrRecordPathName.GetBuffer( m_cstrRecordPathName.GetLength() );
	int nLen = MultiByteToWideChar(CP_ACP, 0,lpStr, -1, NULL, NULL);
	MultiByteToWideChar(CP_ACP, 0, lpStr, -1, wsRecPathName, nLen);

	hr = m_pRecFile.SetFileType( CTimeShiftRecFile::TSRF_RECORD);
	if (FAILED(hr))
	{
		return hr;
	}

	hr = m_pRecFile.SetFileName( wsRecPathName );
	if (FAILED(hr))
	{
		return hr;
	}

	// Open the record file
	hr = m_pRecFile.OpenFile();
	if (FAILED(hr))
	{
		return hr;
	}


	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CTSRecordingDlg::OnBnClickedCancel()
{
	HRESULT					hr;

	// TODO: Add your control notification handler code here
	OnCancel();


	// Close the recording file
	hr = m_pRecFile.CloseFile();
	if (FAILED(hr))
	{
//		return hr;
	}

	// Stop Recording Status display update timer
	KillTimer(RECORDING_STATUS_TIMER);

	// Delete special PID to disable receipt of full Transport Stream
	long lDataPid[1] = { 0x2000 } ;
	hr = m_pB2FilterGraph->GetDataControl()->DeleteTsPIDs( 1 , lDataPid);

	// Remove Callback for Transport Stream
	hr = m_pB2FilterGraph->GetDataControl()->SetCallbackForTransportStream(NULL);



	// Destroy this Dialog box
	DestroyWindow();
}

void CTSRecordingDlg::PostNcDestroy()
{
	CDialog::PostNcDestroy();

	// Delete the the class support this dialog.
	delete this;
}

void CTSRecordingDlg::OnDestroy()
{
	CDialog::OnDestroy();

	// TODO: Add your message handler code here

//	m_pB2FilterGraph->GetMulticastControl()->StopMulticast(m_pMulticastInfo->szMulticastAddress,
//		m_pMulticastInfo->wMulticastPort);

//	ZeroMemory( m_pMulticastInfo, sizeof (tMulticastInfo));
}




void CTSRecordingDlg::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: Add your message handler code here and/or call default

	CDialog::OnTimer(nIDEvent);

	m_iTimerCounts++;

	CString cstrTemp;

	int iFileSizeInKb = ((m_iPacketsProcessed*188) / 1024);
	float fTimeInMinutes = (float) m_iTimerCounts / 10 / 60;

	cstrTemp.Format( _T("File Name:                 %s\n\nPackets Processed:    %d\n\nBytes Processed:       %4.3f MB\n\nElapsed Time:           %5.1f m\n\nContinuity Errors:       %d\n"),
			m_cstrRecordPathName, m_iPacketsProcessed,(float)(m_iPacketsProcessed*188)/1024000,fTimeInMinutes,m_iContinuityErrors);

	GetDlgItem(IDC_STATIC_TS_RECORDING_DESC)->SetWindowText( cstrTemp );

	if (m_pRecordingInfo->lFileSizeLimit && (iFileSizeInKb / 1000) >= m_pRecordingInfo->lFileSizeLimit)
	{
		OnBnClickedCancel();
	}

	if (m_pRecordingInfo->lTimeLimit && fTimeInMinutes >= (float)m_pRecordingInfo->lTimeLimit)
	{
		OnBnClickedCancel();
	}
}



void CTSRecordingDlg::CheckPidContinuityCounter(WORD wPID, BYTE* pucTransportPacket)
{
	if (bInitializeContinuity == FALSE)
	{
		for (int x = 0; x <= 0x1FFF ; x++)
		{
			bt[x] = 0xff;
		}
		bInitializeContinuity = TRUE; 
	}

	if (wPID != 0x1FFF)
	{
		if(bt[wPID] == 0xff)
		{
			UCHAR ucContinuityCounter = pucTransportPacket[3] & 0x0F;	

			bt[wPID] = ucContinuityCounter;
		}
		else
		{
			UCHAR ucAdaptationFieldControl = (pucTransportPacket[ 3] >> 4) & 0x03;	
			UCHAR ucContinuityCounter = pucTransportPacket[3] & 0x0F;	

			if((bt[wPID] & 0x0f) == ucContinuityCounter)
			{
				// If the Adaptation Field is set to 0x00 or 0x02 the continuity counter will not increment
				if (ucAdaptationFieldControl == 0x01 || ucAdaptationFieldControl == 0x03)
				{
//					char st[100];
//					sprintf(st, "Duplicate packet! PID = %x, old C = %d, new C = %d\n", wPID, bt[wPID], ucContinuityCounter);
//					OutputDebugString(st);
				}
			}
			else if(((bt[wPID] + 1) & 0x0f) != ucContinuityCounter)
			{
				m_iContinuityErrors++;

//				char st[100];
//				sprintf(st, "Missing packet! PID = %x, old C = %d, new C = %d\n", wPID, bt[wPID], ucContinuityCounter);
//				OutputDebugString(st);
			}

			bt[wPID] = ucContinuityCounter;
		}
	}
}



void CTSRecordingDlg::GenerateTimeStampedFilename( CString* pcsRecordPathName, char* szPath, char* szRootName )
{
	COleDateTime Time = COleDateTime::GetCurrentTime();

	char szDate[100];
	sprintf(szDate,"_%d-%02d-%02d_%02d-%02d-%02d", Time.GetYear(),Time.GetMonth(),Time.GetDay(),Time.GetHour(),
			Time.GetMinute(),Time.GetSecond());

	*pcsRecordPathName = "";
	*pcsRecordPathName = *pcsRecordPathName + szPath + szRootName + szDate + ".ts";
}
