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