/* * 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; }