/*
* Video On Demand Samples
*
* Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* You may also obtain this software under a propriety license from Microchip.
* Please contact Microchip for further information.
*
*/
#include
#include "Console.h"
#include "SourceFile.h"
uint32_t CSource::m_nInstCnt = 0;
CSourceFile::CSourceFile(const char *szFile, bool autoDestroy)
{
m_bAutoDestroy = autoDestroy;
m_hFile = fopen64(szFile, "rb"); // try to open file
if (NULL == m_hFile) {
ConsolePrintf( PRIO_ERROR, RED"CSourceFile: unable to open file %s"RESETCOLOR"\n", szFile);
return;
}
strncpy(m_szFileName, szFile, sizeof(m_szFileName));
fseek(m_hFile, 0, SEEK_END); // get file's length
fpos64_t pos;
int result = fgetpos64(m_hFile, &pos);
if (result == 0)
m_nLength = pos.__pos;
else
m_nLength = -1;
fseek(m_hFile, 0, SEEK_SET); // start reading from start of file
uint8_t Ts[READ_LEN]; // get PIDs for video and audio
uint32_t bytesRead = fread(// read a chunk from file and write it into ring buffer
Ts,
1,
READ_LEN,
m_hFile);
if (READ_LEN != bytesRead) { // no complete block available?
Close();
return;
}
for (uint8_t *pTs = Ts; pTs < Ts + READ_LEN; pTs += 188) {
if (PID_INVALID == m_nPPid) {
if (GetIsPat(pTs))
m_nPPid = GetPmtPidFromPat(pTs, 0);
} else if (GetHasPid(pTs, m_nPPid)) {
m_nAPid = GetAudioPidFromPmt(pTs);
m_nVPid = GetVideoPidFromPmt(pTs);
break;
}
}
if (PID_INVALID == m_nPPid) { // PMT found ?
ConsolePrintf( PRIO_ERROR, RED"CSourceFile: no PMT found in file %s"RESETCOLOR"\n", szFile);
Close();
return;
}
uint64_t nBlocks = (m_nLength / READ_LEN) -
1; // number of read blocks in file
for (; (nBlocks) && (PCR_INVALID == m_nLastPcr); nBlocks--) {
fseek(m_hFile, nBlocks * READ_LEN,
SEEK_SET); // read backwards from end of file
if (READ_LEN !=
fread( // read a chunk from file and write it into ring buffer
Ts,
1,
READ_LEN,
m_hFile)) { // no complete block available?
Close();
return;
}
for (uint8_t *pTs = Ts; (pTs < Ts + READ_LEN)
&& (PCR_INVALID == m_nLastPcr); pTs += 188) {
m_nLastPcr = GetPcr(pTs);
}
}
fseek(m_hFile, 0, SEEK_SET); // start reading from start of file
ConsolePrintf( PRIO_MEDIUM, "Stream started file: %s\n", m_szFileName);
}
CSourceFile::~CSourceFile()
{
Close();
}
void CSourceFile::Close()
{
if (NULL != m_hFile) {
fclose(m_hFile);
m_hFile = NULL;
ConsolePrintf( PRIO_MEDIUM, "Stream closed file: %s\n", m_szFileName);
}
}
bool CSourceFile::FillBuffer()
{
if (true == m_bPause || // source paused?
0 == m_Stream.Size() || // no receiving streams?
NULL == m_hFile || // file already closed?
!GetCanWrite() ) // ring buffer full?
{
return false;
}
if ( INVALID_POS != m_fReqPos) { // user requested to play from other position?
int64_t nPos = ((m_nLength * (int64_t)m_fReqPos / (int64_t)1000) /
(int64_t)TS_PACKET_LEN) * (int64_t)TS_PACKET_LEN; // stay TS packet aligned
ConsolePrintf( PRIO_MEDIUM, "Stream seek to %lld (%lld per mil) for file: %s\r\n", nPos,((int64_t)1000 * nPos / m_nLength), m_szFileName);
m_fReqPos = INVALID_POS;
if (PID_INVALID != GetVPid()) { // if there is a video ES, seek to previous I frame
uint8_t Ts[TS_PACKET_LEN];
for (; nPos; nPos -= TS_PACKET_LEN) {
fseeko64(m_hFile, nPos, SEEK_SET);
if ( TS_PACKET_LEN != fread(Ts, 1, TS_PACKET_LEN, m_hFile) )
break;
if (GetIsStartOfIFrame(Ts)) // start of I frame?
break;
}
}
fseeko64(m_hFile, nPos, SEEK_SET); // seek to requested position
}
if ( READ_LEN != fread(GetWritePos(),1,READ_LEN,m_hFile) ) { // no complete chunk available?
ConsolePrintf( PRIO_MEDIUM, "CSourceFile: EOF for file: %s\r\n", m_szFileName);
//TODO: remove quick hack:
if (true || m_bRepetition)
m_fReqPos = 0;
else
Close();
return false;
}
m_nBytesRead += READ_LEN;
WriteDone();
return true;
}