/*
* Video On Demand Samples
*
* Copyright (C) 2016 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
#include
#include
#include
#include
#include
#include
#include "Console.h"
#include "SourceFileConverted.h"
CSourceFileConverted::CSourceFileConverted(const char *szFile, bool autoDestroy)
: m_hFile(-1)
, m_nLength(0)
, m_nChildPid(0)
{
m_bAutoDestroy = autoDestroy;
strncpy(m_szFileName, szFile, sizeof(m_szFileName));
m_nLength = 6*60; // TODO: determine actual stream length, assume 6 minutes for now...
Start(0);
m_nPPid = 0x1000; // avconv default / -mpegts_pmt_start_pid X
m_nAPid = 0x101; // avconv default / -streamid 1:X
m_nVPid = 0x100; // avconv default / -streamid 0:X
m_nLastPcr = PCR_INVALID;
}
CSourceFileConverted::~CSourceFileConverted()
{
Close();
}
void CSourceFileConverted::Start(int64_t nPos)
{
// fork() and start avconv in child:
int fd[2];
if (pipe(fd)) {
ConsolePrintf(PRIO_ERROR, RED"CSourceFileConverted: failed to open pipe for %s"RESETCOLOR"\n", m_szFileName);
return;
}
pid_t forkret = fork();
char *ext;
char chstr[20] = "";
switch (forkret) {
case 0:
/* the child process: */
close(fd[0]);
dup2(fd[1], 1); // close stdout, duplicate input side of the pipe to stdout
// execl("/bin/cat", "/bin/cat", m_szFileName, NULL);
sprintf(chstr, "%lli", nPos);
ext = rindex(m_szFileName, '.');
if (ext && !strcasecmp(ext, ".mp3"))
execl("/usr/bin/avconv", "/usr/bin/avconv",
"-ss", chstr, "-i", m_szFileName,
"-f", "mpegts", "-codec", "copy",
"-map", "0:a:0",
"-streamid", "0:0x101", "-mpegts_pmt_start_pid", "0x1000",
"pipe:1", NULL);
else
execl("/usr/bin/avconv", "/usr/bin/avconv",
"-ss", chstr, "-i", m_szFileName,
"-f", "mpegts", "-codec", "copy", "-bsf:v", "h264_mp4toannexb",
"-map", "0:v:0", "-map", "0:a:0",
"-streamid", "0:0x100", "-streamid", "1:0x101", "-mpegts_pmt_start_pid", "0x1000",
"pipe:1", NULL);
ConsolePrintf(PRIO_ERROR, RED"CSourceFileConverted: execl() call failed for %s"RESETCOLOR"\n", m_szFileName);
exit(0);
case -1:
/* fork() failed */
close(fd[0]);
close(fd[1]);
ConsolePrintf(PRIO_ERROR, RED"CSourceFileConverted: failed to fork for %s"RESETCOLOR"\n", m_szFileName);
return;
default:
/* parent process after fork: */
m_nChildPid = forkret;
close(fd[1]);
m_hFile = fd[0]; /* read from child via pipe */
}
m_nLastPcr = PCR_INVALID;
ConsolePrintf( PRIO_MEDIUM, "Stream started file: %s\n", m_szFileName);
}
void CSourceFileConverted::Close()
{
if (m_nChildPid > 0) {
ConsolePrintf(PRIO_LOW, "sending SIGKILL to pid %u\n", m_nChildPid);
kill(m_nChildPid, SIGKILL);
ConsolePrintf(PRIO_LOW, "waiting for child to exit...\n");
int childStatus = 0;
waitpid(m_nChildPid, &childStatus, 0);
m_nChildPid = 0;
if (WIFEXITED(childStatus))
ConsolePrintf(PRIO_LOW, "child terminated normally (exit status %u)\n", WEXITSTATUS(childStatus));
else if (WIFSIGNALED(childStatus))
ConsolePrintf(PRIO_LOW, "child terminated by signal number %u\n", WTERMSIG(childStatus));
}
if (m_hFile > 0) {
close(m_hFile);
m_hFile = -1;
ConsolePrintf( PRIO_MEDIUM, "Stream closed file: %s\n", m_szFileName);
}
}
bool CSourceFileConverted::FillBuffer()
{
if (true == m_bPause || // source paused?
0 == m_Stream.Size() || // no receiving streams?
m_hFile < 0 || // 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 / 1000);
ConsolePrintf( PRIO_MEDIUM, "Stream seek to %lld (%lld per mil) for file: %s\r\n", nPos,(1000 * nPos / m_nLength), m_szFileName);
m_fReqPos = INVALID_POS;
Close();
Start(nPos);
}
unsigned int readcnt = 0;
while (readcnt < READ_LEN) {
int readres = read(m_hFile, GetWritePos()+readcnt, READ_LEN-readcnt);
if (readres <= 0) { // remote pipe end closed, or other error?
ConsolePrintf( PRIO_MEDIUM, "CSourceFileConverted: EOF for file: %s (result=%i, errno=%i)\r\n", m_szFileName, readres, errno);
//TODO: remove quick hack:
if (true || m_bRepetition)
m_fReqPos = 0;
else
Close();
return false;
}
readcnt += readres;
}
m_nBytesRead += READ_LEN;
WriteDone();
return true;
}