mirror of
https://github.com/tuxbox-fork-migrations/recycled-ni-neutrino.git
synced 2025-09-01 01:41:12 +02:00
Merge branch 'dvbsi++' of ssh://coolstreamtech.de/cst-public-gui-neutrino into dvbsi++
Origin commit data
------------------
Commit: de5004bd86
Author: Jacek Jendrzej <overx300@gmail.com>
Date: 2012-11-08 (Thu, 08 Nov 2012)
This commit is contained in:
@@ -26,7 +26,7 @@ libneutrino_driver_a_SOURCES = \
|
||||
file.cpp \
|
||||
fontrenderer.cpp \
|
||||
framebuffer.cpp \
|
||||
genpsi.c \
|
||||
genpsi.cpp \
|
||||
radiotext.cpp \
|
||||
radiotools.cpp \
|
||||
rcinput.cpp \
|
||||
|
@@ -37,7 +37,7 @@
|
||||
in __USE_FILE_OFFSET64 mode */
|
||||
|
||||
#ifndef __USE_FILE_OFFSET64
|
||||
#error not using 64 bit file offsets
|
||||
#define __USE_FILE_OFFSET64
|
||||
#endif /* __USE_FILE__OFFSET64 */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
@@ -1,10 +1,6 @@
|
||||
/*
|
||||
$Id: genpsi.c,v 1.2 2006/01/16 12:45:54 sat_man Exp $
|
||||
|
||||
Copyright (c) 2004 gmo18t, Germany. All rights reserved.
|
||||
|
||||
aktuelle Versionen gibt es hier:
|
||||
$Source: /cvs/tuxbox/apps/tuxbox/neutrino/src/driver/genpsi.c,v $
|
||||
Copyright (C) 2012 CoolStream International Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
@@ -20,9 +16,9 @@ $Id: genpsi.c,v 1.2 2006/01/16 12:45:54 sat_man Exp $
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 675 Mass Ave, Cambridge MA 02139, USA.
|
||||
|
||||
Mit diesem Programm koennen Neutrino TS Streams für das Abspielen unter Enigma gepatched werden
|
||||
Mit diesem Programm koennen Neutrino TS Streams für das Abspielen unter Enigma gepatched werden
|
||||
*/
|
||||
//#include <mpegtools/transform.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <driver/genpsi.h>
|
||||
@@ -31,26 +27,15 @@ $Id: genpsi.c,v 1.2 2006/01/16 12:45:54 sat_man Exp $
|
||||
#define OFS_HDR_2 5
|
||||
#define OFS_PMT_DATA 13
|
||||
#define OFS_STREAM_TAB 17
|
||||
#define SIZE_STREAM_TAB_ROW 5
|
||||
#define SIZE_STREAM_TAB_ROW 5
|
||||
#define OFS_ENIGMA_TAB 31
|
||||
#define SIZE_ENIGMA_TAB_ROW 4
|
||||
#define SIZE_ENIGMA_TAB_ROW 4
|
||||
|
||||
#define ES_TYPE_MPEG12 0x02
|
||||
#define ES_TYPE_AVC 0x1b
|
||||
#define ES_TYPE_MPA 0x03
|
||||
#define ES_TYPE_AC3 0x81
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short nba;
|
||||
uint16_t vpid;
|
||||
uint8_t vtype;
|
||||
uint16_t apid[10];
|
||||
short isAC3[10];
|
||||
} T_AV_PIDS;
|
||||
|
||||
T_AV_PIDS avPids;
|
||||
|
||||
static const uint32_t crc_table[256] = {
|
||||
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
|
||||
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
|
||||
@@ -97,49 +82,6 @@ static const uint32_t crc_table[256] = {
|
||||
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
|
||||
};
|
||||
|
||||
uint32_t calc_crc32psi(uint8_t *dst, const uint8_t *src, uint32_t len)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t crc = 0xffffffff;
|
||||
|
||||
for (i=0; i<len; i++)
|
||||
crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *src++) & 0xff];
|
||||
|
||||
if (dst)
|
||||
{
|
||||
dst[0] = (crc >> 24) & 0xff;
|
||||
dst[1] = (crc >> 16) & 0xff;
|
||||
dst[2] = (crc >> 8) & 0xff;
|
||||
dst[3] = (crc) & 0xff;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
void transfer_pids(uint16_t pid,uint16_t pidart,short isAC3)
|
||||
{
|
||||
switch(pidart)
|
||||
{
|
||||
case EN_TYPE_VIDEO:
|
||||
avPids.vpid=pid;
|
||||
avPids.vtype = ES_TYPE_MPEG12;
|
||||
break;
|
||||
case EN_TYPE_AVC:
|
||||
avPids.vpid=pid;
|
||||
avPids.vtype = ES_TYPE_AVC;
|
||||
break;
|
||||
case EN_TYPE_AUDIO:
|
||||
avPids.apid[avPids.nba]=pid;
|
||||
avPids.isAC3[avPids.nba]=isAC3;
|
||||
avPids.nba++;
|
||||
break;
|
||||
case EN_TYPE_TELTEX:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
//-- special enigma stream description packet for --
|
||||
//-- at least 1 video, 1 audo and 1 PCR-Pid stream --
|
||||
//------------------------------------------------------------------------------------
|
||||
@@ -148,13 +90,13 @@ static uint8_t pkt_enigma[] =
|
||||
0x47, 0x40, 0x1F, 0x10, 0x00,
|
||||
0x7F, 0x80, 0x24,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0x6D, 0x66, 0x30, 0x19,
|
||||
0x00, 0x00, 0x6D, 0x66, 0x30, 0x19,
|
||||
0x80, 0x13, 'N','E','U','T','R','I','N','O','N','G', // tag(8), len(8), text(10) -> NG hihi ;)
|
||||
0x00, 0x02, 0x00, 0x6e, // cVPID(8), len(8), PID(16)
|
||||
0x01, 0x03, 0x00, 0x78, 0x00, // cAPID(8), len(8), PID(16), ac3flag(8)
|
||||
// 0x02, 0x02, 0x00, 0x82,// cTPID(8), len(8), ...
|
||||
0x03, 0x02, 0x00, 0x6e // cPCRPID(8), ...
|
||||
};
|
||||
};
|
||||
//-- PAT packet for at least 1 PMT --
|
||||
//----------------------------------------------------------
|
||||
static uint8_t pkt_pat[] =
|
||||
@@ -165,25 +107,77 @@ static uint8_t pkt_pat[] =
|
||||
0x6D, 0x66, 0xEF, 0xFF, // PAT-DATA - PMT (PID=0xFFF) entry
|
||||
};
|
||||
|
||||
//-- PMT packet for at least 1 video and 1 audio stream --
|
||||
//-- PMT packet for at least 1 video and 1 audio stream --
|
||||
//--------------------------------------------------------
|
||||
static uint8_t pkt_pmt[] =
|
||||
{
|
||||
0x47, 0x4F, 0xFF, 0x10, 0x00, // HEADER-1
|
||||
0x02, 0xB0, 0x17, // HEADER-2
|
||||
0x6D, 0x66, 0xE9, 0x00, 0x00, // HEADER-3
|
||||
0xE0, 0x00, 0xF0, 0x00, // PMT-DATA
|
||||
0xE0, 0x00, 0xF0, 0x00, // PMT-DATA
|
||||
0x02, 0xE0, 0x00, 0xF0, 0x00, // (video stream 1)
|
||||
0x03, 0xE0, 0x00, 0xF0, 0x00 // (audio stream 1)
|
||||
};
|
||||
};
|
||||
|
||||
CGenPsi::CGenPsi()
|
||||
{
|
||||
nba = 0;
|
||||
vpid = 0;
|
||||
vtype = 0;
|
||||
memset(apid, 0, sizeof(apid));
|
||||
memset(atypes, 0, sizeof(atypes));
|
||||
}
|
||||
|
||||
uint32_t CGenPsi::calc_crc32psi(uint8_t *dst, const uint8_t *src, uint32_t len)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t crc = 0xffffffff;
|
||||
|
||||
for (i=0; i<len; i++)
|
||||
crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *src++) & 0xff];
|
||||
|
||||
if (dst)
|
||||
{
|
||||
dst[0] = (crc >> 24) & 0xff;
|
||||
dst[1] = (crc >> 16) & 0xff;
|
||||
dst[2] = (crc >> 8) & 0xff;
|
||||
dst[3] = (crc) & 0xff;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
void CGenPsi::addPid(uint16_t pid, uint16_t pidtype, short isAC3)
|
||||
{
|
||||
switch(pidtype)
|
||||
{
|
||||
case EN_TYPE_VIDEO:
|
||||
vpid=pid;
|
||||
vtype = ES_TYPE_MPEG12;
|
||||
break;
|
||||
case EN_TYPE_AVC:
|
||||
vpid=pid;
|
||||
vtype = ES_TYPE_AVC;
|
||||
break;
|
||||
case EN_TYPE_AUDIO:
|
||||
apid[nba]=pid;
|
||||
atypes[nba]=isAC3;
|
||||
nba++;
|
||||
break;
|
||||
case EN_TYPE_TELTEX:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//== setup a new TS packet with format ==
|
||||
//== predefined with a template ==
|
||||
//=======================================
|
||||
#define COPY_TEMPLATE(dst, src) copy_template(dst, src, sizeof(src))
|
||||
|
||||
static int copy_template(uint8_t *dst, uint8_t *src, int len)
|
||||
int CGenPsi::copy_template(uint8_t *dst, uint8_t *src, int len)
|
||||
{
|
||||
//-- reset buffer --
|
||||
memset(dst, 0xFF, SIZE_TS_PKT);
|
||||
@@ -192,92 +186,93 @@ static int copy_template(uint8_t *dst, uint8_t *src, int len)
|
||||
|
||||
return len;
|
||||
}
|
||||
int genpsi(int fd2)
|
||||
|
||||
int CGenPsi::genpsi(int fd)
|
||||
{
|
||||
// int bytes = 0;
|
||||
uint8_t pkt[SIZE_TS_PKT];
|
||||
int i, data_len, patch_len, ofs;
|
||||
|
||||
//-- copy "Enigma"-template --
|
||||
//-- copy "Enigma"-template --
|
||||
data_len = COPY_TEMPLATE(pkt, pkt_enigma);
|
||||
|
||||
//-- adjust len dependent to number of audio streams --
|
||||
data_len += ((SIZE_ENIGMA_TAB_ROW+1) * (avPids.nba-1));
|
||||
//-- adjust len dependent to number of audio streams --
|
||||
data_len += ((SIZE_ENIGMA_TAB_ROW+1) * (nba-1));
|
||||
|
||||
patch_len = data_len - OFS_HDR_2 + 1;
|
||||
pkt[OFS_HDR_2+1] |= (patch_len>>8);
|
||||
pkt[OFS_HDR_2+2] = (patch_len & 0xFF);
|
||||
//-- write row with desc. for video stream --
|
||||
pkt[OFS_HDR_2+2] = (patch_len & 0xFF);
|
||||
//-- write row with desc. for video stream --
|
||||
ofs = OFS_ENIGMA_TAB;
|
||||
pkt[ofs] = EN_TYPE_VIDEO;
|
||||
pkt[ofs+1] = 0x02;
|
||||
pkt[ofs+2] = (avPids.vpid>>8);
|
||||
pkt[ofs+3] = (avPids.vpid & 0xFF);
|
||||
//-- for each audio stream, write row with desc. --
|
||||
ofs += SIZE_ENIGMA_TAB_ROW;
|
||||
for (i=0; i<avPids.nba; i++)
|
||||
pkt[ofs+2] = (vpid>>8);
|
||||
pkt[ofs+3] = (vpid & 0xFF);
|
||||
//-- for each audio stream, write row with desc. --
|
||||
ofs += SIZE_ENIGMA_TAB_ROW;
|
||||
for (i=0; i<nba; i++)
|
||||
{
|
||||
pkt[ofs] = EN_TYPE_AUDIO;
|
||||
pkt[ofs+1] = 0x03;
|
||||
pkt[ofs+2] = (avPids.apid[i]>>8);
|
||||
pkt[ofs+3] = (avPids.apid[i] & 0xFF);
|
||||
pkt[ofs+4] = (avPids.isAC3[i]==1)? 0x01 : 0x00;
|
||||
pkt[ofs+2] = (apid[i]>>8);
|
||||
pkt[ofs+3] = (apid[i] & 0xFF);
|
||||
pkt[ofs+4] = (atypes[i]==1)? 0x01 : 0x00;
|
||||
|
||||
ofs += (SIZE_ENIGMA_TAB_ROW + 1);
|
||||
}
|
||||
//-- write row with desc. for pcr stream (eq. video) --
|
||||
//-- write row with desc. for pcr stream (eq. video) --
|
||||
pkt[ofs] = EN_TYPE_PCR;
|
||||
pkt[ofs+1] = 0x02;
|
||||
pkt[ofs+2] = (avPids.vpid>>8);
|
||||
pkt[ofs+3] = (avPids.vpid & 0xFF);
|
||||
|
||||
//-- calculate CRC --
|
||||
calc_crc32psi(&pkt[data_len], &pkt[OFS_HDR_2], data_len-OFS_HDR_2 );
|
||||
//-- write TS packet --
|
||||
/*bytes +=*/ write(fd2, pkt, SIZE_TS_PKT);
|
||||
//-- (II) build PAT --
|
||||
data_len = COPY_TEMPLATE(pkt, pkt_pat);
|
||||
//-- calculate CRC --
|
||||
calc_crc32psi(&pkt[data_len], &pkt[OFS_HDR_2], data_len-OFS_HDR_2 );
|
||||
//-- write TS packet --
|
||||
/*bytes +=*/ write(fd2, pkt, SIZE_TS_PKT);
|
||||
pkt[ofs+2] = (vpid>>8);
|
||||
pkt[ofs+3] = (vpid & 0xFF);
|
||||
|
||||
//-- (III) build PMT --
|
||||
//-- calculate CRC --
|
||||
calc_crc32psi(&pkt[data_len], &pkt[OFS_HDR_2], data_len-OFS_HDR_2 );
|
||||
//-- write TS packet --
|
||||
write(fd, pkt, SIZE_TS_PKT);
|
||||
|
||||
//-- (II) build PAT --
|
||||
data_len = COPY_TEMPLATE(pkt, pkt_pat);
|
||||
//-- calculate CRC --
|
||||
calc_crc32psi(&pkt[data_len], &pkt[OFS_HDR_2], data_len-OFS_HDR_2 );
|
||||
//-- write TS packet --
|
||||
write(fd, pkt, SIZE_TS_PKT);
|
||||
|
||||
//-- (III) build PMT --
|
||||
data_len = COPY_TEMPLATE(pkt, pkt_pmt);
|
||||
//-- adjust len dependent to count of audio streams --
|
||||
data_len += (SIZE_STREAM_TAB_ROW * (avPids.nba-1));
|
||||
//-- adjust len dependent to count of audio streams --
|
||||
data_len += (SIZE_STREAM_TAB_ROW * (nba-1));
|
||||
patch_len = data_len - OFS_HDR_2 + 1;
|
||||
pkt[OFS_HDR_2+1] |= (patch_len>>8);
|
||||
pkt[OFS_HDR_2+2] = (patch_len & 0xFF);
|
||||
//-- patch pcr PID --
|
||||
pkt[OFS_HDR_2+2] = (patch_len & 0xFF);
|
||||
//-- patch pcr PID --
|
||||
ofs = OFS_PMT_DATA;
|
||||
pkt[ofs] |= (avPids.vpid>>8);
|
||||
pkt[ofs+1] = (avPids.vpid & 0xFF);
|
||||
//-- write row with desc. for ES video stream --
|
||||
pkt[ofs] |= (vpid>>8);
|
||||
pkt[ofs+1] = (vpid & 0xFF);
|
||||
//-- write row with desc. for ES video stream --
|
||||
ofs = OFS_STREAM_TAB;
|
||||
pkt[ofs] = avPids.vtype;
|
||||
pkt[ofs+1] = 0xE0 | (avPids.vpid>>8);
|
||||
pkt[ofs+2] = (avPids.vpid & 0xFF);
|
||||
pkt[ofs] = vtype;
|
||||
pkt[ofs+1] = 0xE0 | (vpid>>8);
|
||||
pkt[ofs+2] = (vpid & 0xFF);
|
||||
pkt[ofs+3] = 0xF0;
|
||||
pkt[ofs+4] = 0x00;
|
||||
|
||||
//-- for each ES audio stream, write row with desc. --
|
||||
for (i=0; i<avPids.nba; i++)
|
||||
//-- for each ES audio stream, write row with desc. --
|
||||
for (i=0; i<nba; i++)
|
||||
{
|
||||
ofs += SIZE_STREAM_TAB_ROW;
|
||||
pkt[ofs] = (avPids.isAC3[i]==1)? ES_TYPE_AC3 : ES_TYPE_MPA;
|
||||
pkt[ofs+1] = 0xE0 | (avPids.apid[i]>>8);
|
||||
pkt[ofs+2] = (avPids.apid[i] & 0xFF);
|
||||
pkt[ofs] = (atypes[i]==1)? ES_TYPE_AC3 : ES_TYPE_MPA;
|
||||
pkt[ofs+1] = 0xE0 | (apid[i]>>8);
|
||||
pkt[ofs+2] = (apid[i] & 0xFF);
|
||||
pkt[ofs+3] = 0xF0;
|
||||
pkt[ofs+4] = 0x00;
|
||||
}
|
||||
//-- calculate CRC --
|
||||
//-- calculate CRC --
|
||||
calc_crc32psi(&pkt[data_len], &pkt[OFS_HDR_2], data_len-OFS_HDR_2 );
|
||||
//-- write TS packet --
|
||||
/*bytes +=*/ write(fd2, pkt, SIZE_TS_PKT);
|
||||
//-- finish --
|
||||
avPids.vpid=0;
|
||||
avPids.nba=0;
|
||||
fdatasync(fd2);
|
||||
//-- write TS packet --
|
||||
write(fd, pkt, SIZE_TS_PKT);
|
||||
//-- finish --
|
||||
vpid=0;
|
||||
nba=0;
|
||||
fdatasync(fd);
|
||||
return 1;
|
||||
}
|
@@ -1,10 +1,7 @@
|
||||
/*
|
||||
$Id: genpsi.h,v 1.1 2005/08/15 14:47:52 metallica Exp $
|
||||
|
||||
Copyright (c) 2004 gmo18t, Germany. All rights reserved.
|
||||
|
||||
aktuelle Versionen gibt es hier:
|
||||
$Source: /cvs/tuxbox/apps/tuxbox/neutrino/src/driver/genpsi.h,v $
|
||||
Copyright (C) 2012 CoolStream International Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published
|
||||
@@ -26,13 +23,26 @@ $Id: genpsi.h,v 1.1 2005/08/15 14:47:52 metallica Exp $
|
||||
#define __genpsi_h__
|
||||
#include <inttypes.h>
|
||||
|
||||
int genpsi(int fd2);
|
||||
void transfer_pids(uint16_t pid,uint16_t pidart,short isAC3);
|
||||
|
||||
#define EN_TYPE_VIDEO 0x00
|
||||
#define EN_TYPE_AUDIO 0x01
|
||||
#define EN_TYPE_TELTEX 0x02
|
||||
#define EN_TYPE_PCR 0x03
|
||||
#define EN_TYPE_AVC 0x04
|
||||
|
||||
class CGenPsi
|
||||
{
|
||||
private:
|
||||
short nba;
|
||||
uint16_t vpid;
|
||||
uint8_t vtype;
|
||||
uint16_t apid[10];
|
||||
short atypes[10];
|
||||
static int copy_template(uint8_t *dst, uint8_t *src, int len);
|
||||
uint32_t calc_crc32psi(uint8_t *dst, const uint8_t *src, uint32_t len);
|
||||
|
||||
public:
|
||||
CGenPsi();
|
||||
void addPid(uint16_t pid,uint16_t pidtype, short isAC3);
|
||||
int genpsi(int fd);
|
||||
};
|
||||
#endif
|
||||
|
@@ -51,6 +51,7 @@
|
||||
|
||||
|
||||
#include <driver/record.h>
|
||||
#include <driver/streamts.h>
|
||||
#include <zapit/capmt.h>
|
||||
#include <zapit/channel.h>
|
||||
#include <zapit/getservices.h>
|
||||
@@ -156,15 +157,16 @@ record_error_msg_t CRecordInstance::Start(CZapitChannel * channel)
|
||||
return RECORD_INVALID_DIRECTORY;
|
||||
}
|
||||
|
||||
CGenPsi psi;
|
||||
if (allpids.PIDs.vpid != 0)
|
||||
transfer_pids(allpids.PIDs.vpid, recMovieInfo->VideoType ? EN_TYPE_AVC : EN_TYPE_VIDEO, 0);
|
||||
psi.addPid(allpids.PIDs.vpid, recMovieInfo->VideoType ? EN_TYPE_AVC : EN_TYPE_VIDEO, 0);
|
||||
|
||||
numpids = 0;
|
||||
for (unsigned int i = 0; i < recMovieInfo->audioPids.size(); i++) {
|
||||
apids[numpids++] = recMovieInfo->audioPids[i].epgAudioPid;
|
||||
transfer_pids(recMovieInfo->audioPids[i].epgAudioPid, EN_TYPE_AUDIO, recMovieInfo->audioPids[i].atype);
|
||||
psi.addPid(recMovieInfo->audioPids[i].epgAudioPid, EN_TYPE_AUDIO, recMovieInfo->audioPids[i].atype);
|
||||
}
|
||||
genpsi(fd);
|
||||
psi.genpsi(fd);
|
||||
|
||||
if ((StreamVTxtPid) && (allpids.PIDs.vtxtpid != 0))
|
||||
apids[numpids++] = allpids.PIDs.vtxtpid;
|
||||
@@ -1590,12 +1592,16 @@ bool CRecordManager::CutBackNeutrino(const t_channel_id channel_id, CFrontend *
|
||||
* needed, if record frontend same as live, and its on different TP */
|
||||
bool found = (live_fe != frontend) || SAME_TRANSPONDER(live_channel_id, channel_id);
|
||||
if(found) {
|
||||
/* stop stream for this channel */
|
||||
CStreamManager::getInstance()->StopStream(channel_id);
|
||||
ret = g_Zapit->zapTo_record(channel_id) > 0;
|
||||
printf("%s found same tp, zapTo_record channel_id %llx result %d\n", __FUNCTION__, channel_id, ret);
|
||||
}
|
||||
else {
|
||||
printf("%s mode %d last_mode %d getLastMode %d\n", __FUNCTION__, mode, last_mode, CNeutrinoApp::getInstance()->getLastMode());
|
||||
StopAutoRecord(false);
|
||||
/* stop all streams */
|
||||
CStreamManager::getInstance()->StopStream();
|
||||
if (mode != last_mode && (last_mode != NeutrinoMessages::mode_standby || mode != CNeutrinoApp::getInstance()->getLastMode())) {
|
||||
CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::CHANGEMODE , mode | NeutrinoMessages::norezap );
|
||||
mode_changed = true;
|
||||
@@ -1619,6 +1625,8 @@ bool CRecordManager::CutBackNeutrino(const t_channel_id channel_id, CFrontend *
|
||||
g_Zapit->stopPlayBack();
|
||||
if ((live_channel_id == channel_id) && g_Radiotext)
|
||||
g_Radiotext->radiotext_stop();
|
||||
/* in case channel_id == live_channel_id */
|
||||
CStreamManager::getInstance()->StopStream(channel_id);
|
||||
}
|
||||
if(last_mode == NeutrinoMessages::mode_standby) {
|
||||
//CNeutrinoApp::getInstance()->handleMsg( NeutrinoMessages::CHANGEMODE , NeutrinoMessages::mode_standby);
|
||||
|
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
Neutrino-GUI - DBoxII-Project
|
||||
|
||||
Copyright (C) 2011-2012 CoolStream International Ltd
|
||||
|
||||
based on code which is
|
||||
Copyright (C) 2002 Andreas Oberritter <obi@tuxbox.org>
|
||||
Copyright (C) 2001 TripleDES
|
||||
Copyright (C) 2000, 2001 Marcus Metzler <marcus@convergence.de>
|
||||
|
||||
License: GPLv2
|
||||
|
||||
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;
|
||||
|
||||
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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -13,10 +39,8 @@
|
||||
#include <poll.h>
|
||||
#include <syscall.h>
|
||||
|
||||
/* work around for building with old kernel headers */
|
||||
#ifndef POLLRDHUP
|
||||
#define POLLRDHUP 0
|
||||
#endif
|
||||
#include <global.h>
|
||||
#include <neutrino.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
@@ -28,248 +52,231 @@
|
||||
#include <dmx.h>
|
||||
#include <zapit/capmt.h>
|
||||
#include <zapit/zapit.h>
|
||||
#include <zapit/pat.h>
|
||||
#include <driver/streamts.h>
|
||||
#include <driver/record.h>
|
||||
#include <driver/genpsi.h>
|
||||
|
||||
/* experimental mode:
|
||||
* stream not possible, if record running
|
||||
* pids in url ignored, and added from channel, with fake PAT/PMT
|
||||
* different channels supported, only from the same transponder - no zap is done,
|
||||
* with url like http://coolstream:31339/id=c32400030070283e (channel id)
|
||||
* TODO: multi-tuner support
|
||||
*/
|
||||
#define ENABLE_MULTI_CHANNEL
|
||||
|
||||
#define TS_SIZE 188
|
||||
#define IN_SIZE (2048 * TS_SIZE)
|
||||
//#define IN_SIZE (TS_SIZE * 362)
|
||||
#define DMX_BUFFER_SIZE (2048*TS_SIZE)
|
||||
#define IN_SIZE (250*TS_SIZE)
|
||||
|
||||
#define DMX_BUFFER_SIZE (2 * 3008 * 62)
|
||||
|
||||
/* maximum number of pes pids */
|
||||
#define MAXPIDS 64
|
||||
|
||||
/* tcp packet data size */
|
||||
//#define PACKET_SIZE 1448
|
||||
#define PACKET_SIZE 7*TS_SIZE
|
||||
|
||||
//unsigned char * buf;
|
||||
|
||||
extern CCam *cam0;
|
||||
|
||||
//int demuxfd[MAXPIDS];
|
||||
|
||||
static unsigned char exit_flag = 0;
|
||||
static unsigned int writebuf_size = 0;
|
||||
static unsigned char writebuf[PACKET_SIZE];
|
||||
|
||||
void packet_stdout (int fd, unsigned char * buf, int count, void * /*p*/)
|
||||
CStreamInstance::CStreamInstance(int clientfd, t_channel_id chid, stream_pids_t &_pids)
|
||||
{
|
||||
|
||||
unsigned int size;
|
||||
unsigned char * bp;
|
||||
ssize_t written;
|
||||
|
||||
//printf("packet_stdout count %d\n", count);
|
||||
/* ensure, that there is always at least one complete
|
||||
* packet inside of the send buffer */
|
||||
while (writebuf_size + count >= PACKET_SIZE) {
|
||||
|
||||
/* how many bytes are to be sent from the input buffer? */
|
||||
size = PACKET_SIZE - writebuf_size;
|
||||
|
||||
/* send buffer is not empty, so copy from
|
||||
input buffer to get a complete packet */
|
||||
if (writebuf_size) {
|
||||
memmove(writebuf + writebuf_size, buf, size);
|
||||
bp = writebuf;
|
||||
}
|
||||
|
||||
/* if send buffer is empty, then do not memcopy,
|
||||
but send directly from input buffer */
|
||||
else {
|
||||
bp = buf;
|
||||
}
|
||||
|
||||
/* write the packet, count the amount of really written bytes */
|
||||
written = write(fd, bp, PACKET_SIZE);
|
||||
|
||||
/* exit on error */
|
||||
if (written == -1) {
|
||||
perror("write");
|
||||
exit_flag = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* if the packet could not be written completely, then
|
||||
* how many bytes must be stored in the send buffer
|
||||
* until the next packet is to be sent? */
|
||||
writebuf_size = PACKET_SIZE - written;
|
||||
|
||||
/* move all bytes of the packet which were not sent
|
||||
* to the beginning of the send buffer */
|
||||
if (writebuf_size)
|
||||
memmove(writebuf, bp + written, writebuf_size);
|
||||
|
||||
/* * advance in the input buffer */
|
||||
buf += size;
|
||||
|
||||
/* * decrease the todo size */
|
||||
count -= size;
|
||||
}
|
||||
|
||||
/* if there are still some bytes left in the input buffer,
|
||||
* then store them in the send buffer and increase send
|
||||
* buffer size */
|
||||
if (count) {
|
||||
memmove(writebuf + writebuf_size, buf, count);
|
||||
writebuf_size += count;
|
||||
}
|
||||
printf("CStreamInstance:: new channel %llx fd %d\n", chid, clientfd);
|
||||
fds.insert(clientfd);
|
||||
pids = _pids;
|
||||
channel_id = chid;
|
||||
running = false;
|
||||
dmx = NULL;
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
int open_incoming_port (int port)
|
||||
CStreamInstance::~CStreamInstance()
|
||||
{
|
||||
struct sockaddr_in socketAddr;
|
||||
int socketOptActive = 1;
|
||||
int handle;
|
||||
|
||||
if (!port)
|
||||
return -1;
|
||||
|
||||
if ((handle = socket (AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
{
|
||||
fprintf (stderr, "network port %u open: ", port);
|
||||
perror ("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setsockopt (handle, SOL_SOCKET, SO_REUSEADDR, (const void *)&socketOptActive, sizeof (int)) < 0)
|
||||
{
|
||||
fprintf (stderr, "network port %u open: error setsockopt\n", port);
|
||||
close (handle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
socketAddr.sin_family = AF_INET;
|
||||
socketAddr.sin_port = htons (port);
|
||||
socketAddr.sin_addr.s_addr = htonl (INADDR_ANY);
|
||||
|
||||
if (bind (handle, (struct sockaddr *) &socketAddr, sizeof (socketAddr)) < 0)
|
||||
{
|
||||
fprintf (stderr, "network port %u open: ", port);
|
||||
perror ("bind");
|
||||
close (handle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen (handle, 5) < 0)
|
||||
{
|
||||
fprintf (stderr, "network port %u open: ", port);
|
||||
perror ("listen");
|
||||
close (handle);
|
||||
return -1;
|
||||
}
|
||||
return handle;
|
||||
Stop();
|
||||
Close();
|
||||
}
|
||||
|
||||
void * streamts_live_thread(void *data);
|
||||
int streamts_stop;
|
||||
|
||||
void streamts_main_thread(void * /*data*/)
|
||||
bool CStreamInstance::Start()
|
||||
{
|
||||
struct sockaddr_in servaddr;
|
||||
int clilen;
|
||||
if (running)
|
||||
return false;
|
||||
|
||||
struct pollfd pfd[128];
|
||||
int poll_cnt, tcnt;
|
||||
int listenfd;
|
||||
int connfd = -1;
|
||||
int pollres;
|
||||
int i;
|
||||
pthread_t st = 0;
|
||||
|
||||
printf("Starting STREAM thread keeper, tid %ld\n", syscall(__NR_gettid));
|
||||
|
||||
listenfd = open_incoming_port(31339);
|
||||
if(listenfd < 0) {
|
||||
printf("Open incoming port failed\n");
|
||||
return;
|
||||
buf = new unsigned char [IN_SIZE];
|
||||
if (buf == NULL) {
|
||||
perror("CStreamInstance::Start: buf");
|
||||
return false;
|
||||
}
|
||||
printf("listenfd %d\n", listenfd);
|
||||
|
||||
clilen = sizeof (servaddr);
|
||||
pfd[0].fd = listenfd;
|
||||
pfd[0].events = (POLLIN | POLLPRI);
|
||||
pfd[0].revents = 0;
|
||||
tcnt = 1;
|
||||
streamts_stop = 0;
|
||||
|
||||
while (!streamts_stop) {
|
||||
poll_cnt = tcnt;
|
||||
//printf("polling, count= %d\n", poll_cnt);
|
||||
pollres = poll (pfd, poll_cnt, 1000);
|
||||
if (pollres < 0) {
|
||||
perror("streamts_main_thread poll");
|
||||
continue;
|
||||
}
|
||||
if(pollres == 0)
|
||||
continue;
|
||||
for (i = poll_cnt - 1; i >= 0; i--) {
|
||||
if (pfd[i].revents & (POLLIN | POLLPRI | POLLHUP | POLLRDHUP)) {
|
||||
printf("fd %d has events %x\n", pfd[i].fd, pfd[i].revents);
|
||||
if (pfd[i].fd == listenfd) {
|
||||
connfd = accept (listenfd, (struct sockaddr *) &servaddr, (socklen_t *) & clilen);
|
||||
printf("new connection, fd %d\n", connfd);
|
||||
if(connfd < 0) {
|
||||
perror("accept");
|
||||
continue;
|
||||
}
|
||||
if(st != 0) {
|
||||
printf("New connection, stopping stream thread\n");
|
||||
exit_flag = 1;
|
||||
pthread_join(st, NULL);
|
||||
tcnt --;
|
||||
}
|
||||
pfd[tcnt].fd = connfd;
|
||||
pfd[tcnt].events = POLLRDHUP | POLLHUP;
|
||||
pfd[tcnt].revents = 0;
|
||||
tcnt++;
|
||||
exit_flag = 0;
|
||||
pthread_create (&st, NULL, streamts_live_thread, (void *) connfd);
|
||||
} else {
|
||||
if (pfd[i].revents & (POLLHUP | POLLRDHUP)) {
|
||||
connfd = -1;
|
||||
printf("Client disconnected, stopping stream thread\n");
|
||||
exit_flag = 1;
|
||||
if(st)
|
||||
pthread_join(st, NULL);
|
||||
st = 0;
|
||||
tcnt --;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("Stopping STREAM thread keeper\n");
|
||||
close(listenfd);
|
||||
if(st != 0) {
|
||||
printf("Stopping stream thread\n");
|
||||
exit_flag = 1;
|
||||
pthread_join(st, NULL);
|
||||
close(connfd);
|
||||
}
|
||||
return;
|
||||
running = true;
|
||||
printf("CStreamInstance::Start: %llx\n", channel_id);
|
||||
return (OpenThreads::Thread::start() == 0);
|
||||
}
|
||||
|
||||
void * streamts_live_thread(void *data)
|
||||
bool CStreamInstance::Stop()
|
||||
{
|
||||
if (!running)
|
||||
return false;
|
||||
|
||||
printf("CStreamInstance::Stop: %llx\n", channel_id);
|
||||
running = false;
|
||||
return (OpenThreads::Thread::join() == 0);
|
||||
}
|
||||
|
||||
bool CStreamInstance::Send(ssize_t r)
|
||||
{
|
||||
mutex.lock();
|
||||
for (stream_fds_t::iterator it = fds.begin(); it != fds.end(); ++it) {
|
||||
int ret, i = 10;
|
||||
do {
|
||||
ret = send(*it, buf, r, MSG_DONTWAIT);
|
||||
#if 0
|
||||
if (ret != r)
|
||||
usleep(100);
|
||||
#endif
|
||||
} while ((ret != r) && (i-- > 0));
|
||||
if (ret != r) {
|
||||
if (r < 0)
|
||||
perror("send");
|
||||
printf("send err, fd %d: %d\n", *it, r);
|
||||
}
|
||||
}
|
||||
mutex.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CStreamInstance::Close()
|
||||
{
|
||||
for (stream_fds_t::iterator fit = fds.begin(); fit != fds.end(); ++fit)
|
||||
close(*fit);
|
||||
fds.clear();
|
||||
}
|
||||
|
||||
void CStreamInstance::AddClient(int clientfd)
|
||||
{
|
||||
mutex.lock();
|
||||
fds.insert(clientfd);
|
||||
printf("CStreamInstance::AddClient: %d (count %d)\n", clientfd, fds.size());
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void CStreamInstance::RemoveClient(int clientfd)
|
||||
{
|
||||
mutex.lock();
|
||||
fds.erase(clientfd);
|
||||
close(clientfd);
|
||||
printf("CStreamInstance::RemoveClient: %d (count %d)\n", clientfd, fds.size());
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void CStreamInstance::run()
|
||||
{
|
||||
printf("CStreamInstance::run: %llx\n", channel_id);
|
||||
|
||||
dmx = new cDemux(STREAM_DEMUX);//FIXME
|
||||
|
||||
dmx->Open(DMX_TP_CHANNEL, NULL, DMX_BUFFER_SIZE);
|
||||
|
||||
/* pids here cannot be empty */
|
||||
stream_pids_t::iterator it = pids.begin();
|
||||
printf("CStreamInstance::run: add pid %x\n", *it);
|
||||
dmx->pesFilter(*it);
|
||||
++it;
|
||||
for (; it != pids.end(); ++it) {
|
||||
printf("CStreamInstance::run: add pid %x\n", *it);
|
||||
dmx->addPid(*it);
|
||||
}
|
||||
#ifdef ENABLE_MULTI_CHANNEL
|
||||
dmx->Start();//FIXME
|
||||
#else
|
||||
dmx->Start(true);//FIXME
|
||||
#endif
|
||||
|
||||
CCamManager::getInstance()->Start(channel_id, CCamManager::STREAM);
|
||||
|
||||
while (running) {
|
||||
ssize_t r = dmx->Read(buf, IN_SIZE, 100);
|
||||
if(r > 0)
|
||||
Send(r);
|
||||
}
|
||||
|
||||
CCamManager::getInstance()->Stop(channel_id, CCamManager::STREAM);
|
||||
|
||||
printf("CStreamInstance::run: exiting %llx (%d fds)\n", channel_id, fds.size());
|
||||
|
||||
Close();
|
||||
delete dmx;
|
||||
delete []buf;
|
||||
}
|
||||
|
||||
bool CStreamInstance::HasFd(int fd)
|
||||
{
|
||||
if (fds.find(fd) != fds.end())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
CStreamManager *CStreamManager::sm = NULL;
|
||||
CStreamManager::CStreamManager()
|
||||
{
|
||||
enabled = true;
|
||||
running = false;
|
||||
listenfd = -1;
|
||||
port = 31339;
|
||||
}
|
||||
|
||||
CStreamManager::~CStreamManager()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
CStreamManager * CStreamManager::getInstance()
|
||||
{
|
||||
if (sm == NULL)
|
||||
sm = new CStreamManager();
|
||||
return sm;
|
||||
}
|
||||
|
||||
bool CStreamManager::Start(int _port)
|
||||
{
|
||||
if (running)
|
||||
return false;
|
||||
|
||||
if (_port)
|
||||
port = _port;
|
||||
if (!Listen())
|
||||
return false;
|
||||
|
||||
running = true;
|
||||
return (OpenThreads::Thread::start() == 0);
|
||||
}
|
||||
|
||||
bool CStreamManager::Stop()
|
||||
{
|
||||
if (!running)
|
||||
return false;
|
||||
running = false;
|
||||
return (OpenThreads::Thread::join() == 0);
|
||||
}
|
||||
|
||||
bool CStreamManager::SetPort(int newport)
|
||||
{
|
||||
bool ret = false;
|
||||
if (port != newport) {
|
||||
port = newport;
|
||||
#if 0
|
||||
Stop();
|
||||
ret = Start(newport);
|
||||
#endif
|
||||
mutex.lock();
|
||||
if (listenfd >= 0)
|
||||
close(listenfd);
|
||||
ret = Listen();
|
||||
mutex.unlock();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CStreamManager::Parse(int fd, stream_pids_t &pids, t_channel_id &chid)
|
||||
{
|
||||
unsigned char * buf;
|
||||
int pid;
|
||||
int pids[MAXPIDS];
|
||||
char cbuf[512];
|
||||
char *bp;
|
||||
int fd = (int) data;
|
||||
unsigned char demuxfd_count = 0;
|
||||
|
||||
printf("Starting LIVE STREAM thread, fd %d\n", fd);
|
||||
FILE * fp = fdopen(fd, "r+");
|
||||
if(fp == NULL) {
|
||||
perror("fdopen");
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
writebuf_size = 0;
|
||||
|
||||
cbuf[0] = 0;
|
||||
bp = &cbuf[0];
|
||||
|
||||
@@ -279,7 +286,7 @@ void * streamts_live_thread(void *data)
|
||||
int res = read(fd, &c, 1);
|
||||
if(res < 0) {
|
||||
perror("read");
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
if ((*bp++ = c) == '\n')
|
||||
break;
|
||||
@@ -288,7 +295,7 @@ void * streamts_live_thread(void *data)
|
||||
*bp++ = 0;
|
||||
bp = &cbuf[0];
|
||||
|
||||
printf("stream: got %s\n", cbuf);
|
||||
printf("CStreamManager::Parse: got %s\n", cbuf);
|
||||
|
||||
/* send response to http client */
|
||||
if (!strncmp(cbuf, "GET /", 5)) {
|
||||
@@ -297,165 +304,256 @@ void * streamts_live_thread(void *data)
|
||||
bp += 5;
|
||||
} else {
|
||||
printf("Received garbage\n");
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef ENABLE_MULTI_CHANNEL
|
||||
/* parse stdin / url path, start dmx filters */
|
||||
do {
|
||||
int pid;
|
||||
int res = sscanf(bp, "%x", &pid);
|
||||
if(res == 1) {
|
||||
printf("New pid: 0x%x\n", pid);
|
||||
pids[demuxfd_count++] = pid;
|
||||
pids.insert(pid);
|
||||
}
|
||||
}
|
||||
while ((bp = strchr(bp, ',')) && (bp++) && (demuxfd_count < MAXPIDS));
|
||||
while ((bp = strchr(bp, ',')) && (bp++));
|
||||
#endif
|
||||
|
||||
if(demuxfd_count == 0) {
|
||||
printf("No pids!\n");
|
||||
CZapitChannel * channel = CZapit::getInstance()->GetCurrentChannel();
|
||||
chid = CZapit::getInstance()->GetCurrentChannelID();
|
||||
CZapitChannel * channel = CZapit::getInstance()->GetCurrentChannel();
|
||||
|
||||
int mode = CNeutrinoApp::getInstance()->getMode();
|
||||
if (mode == NeutrinoMessages::mode_standby && streams.empty()) {
|
||||
printf("CStreamManager::Parse: wakeup zapit..\n");
|
||||
g_Zapit->setStandby(false);
|
||||
g_Zapit->getMode();
|
||||
}
|
||||
if(pids.empty()) {
|
||||
#ifdef ENABLE_MULTI_CHANNEL
|
||||
t_channel_id tmpid;
|
||||
bp = &cbuf[5];
|
||||
if (sscanf(bp, "id=%llx", &tmpid) == 1) {
|
||||
printf("############################# channel_id %llx\n", tmpid);
|
||||
|
||||
CZapitChannel * tmpchan = CServiceManager::getInstance()->FindChannel(tmpid);
|
||||
if (tmpchan && (tmpid != chid) && SAME_TRANSPONDER(tmpid, chid)) {
|
||||
printf("############################# channel_id %llx -> zap\n", tmpid);
|
||||
bool ret = g_Zapit->zapTo_record(tmpid) > 0;
|
||||
if (ret) {
|
||||
channel = tmpchan;
|
||||
chid = tmpid;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(CRecordManager::getInstance()->RecordingStatus(tmpid)) {
|
||||
printf("CStreamManager::Parse: channel %llx recorded, aborting..\n", tmpid);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("CStreamManager::Parse: no pids in url, using channel %llx pids\n", chid);
|
||||
if(!channel)
|
||||
return 0;
|
||||
pids[demuxfd_count++] = 0;
|
||||
pids[demuxfd_count++] = channel->getPmtPid();
|
||||
pids[demuxfd_count++] = channel->getVideoPid();
|
||||
return false;
|
||||
//pids.insert(0);
|
||||
//pids.insert(channel->getPmtPid());
|
||||
pids.insert(channel->getVideoPid());
|
||||
for (int i = 0; i < channel->getAudioChannelCount(); i++)
|
||||
pids[demuxfd_count++] = channel->getAudioChannel(i)->pid;
|
||||
pids.insert(channel->getAudioChannel(i)->pid);
|
||||
}
|
||||
|
||||
buf = new unsigned char [IN_SIZE];
|
||||
if (buf == NULL) {
|
||||
perror("NEW");
|
||||
return 0;
|
||||
CGenPsi psi;
|
||||
for (stream_pids_t::iterator it = pids.begin(); it != pids.end(); ++it) {
|
||||
if (*it == channel->getVideoPid()) {
|
||||
printf("CStreamManager::Parse: genpsi vpid %x (%d)\n", *it, channel->type);
|
||||
psi.addPid(*it, channel->type ? EN_TYPE_AVC : EN_TYPE_VIDEO, 0);
|
||||
} else {
|
||||
for (int i = 0; i < channel->getAudioChannelCount(); i++) {
|
||||
if (*it == channel->getAudioChannel(i)->pid) {
|
||||
CZapitAudioChannel::ZapitAudioChannelType atype = channel->getAudioChannel(i)->audioChannelType;
|
||||
printf("CStreamManager::Parse: genpsi apid %x (%d)\n", *it, atype);
|
||||
psi.addPid(*it, EN_TYPE_AUDIO, atype);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
psi.genpsi(fd);
|
||||
|
||||
cDemux * dmx = new cDemux(STREAM_DEMUX);//FIXME
|
||||
|
||||
dmx->Open(DMX_TP_CHANNEL, NULL, DMX_BUFFER_SIZE);
|
||||
|
||||
dmx->pesFilter(pids[0]);
|
||||
for(int i = 1; i < demuxfd_count; i++)
|
||||
dmx->addPid(pids[i]);
|
||||
|
||||
dmx->Start(true);//FIXME
|
||||
|
||||
CCamManager::getInstance()->Start(CZapit::getInstance()->GetCurrentChannelID(), CCamManager::STREAM);
|
||||
ssize_t r;
|
||||
|
||||
while (!exit_flag) {
|
||||
r = dmx->Read(buf, IN_SIZE, 100);
|
||||
if(r > 0)
|
||||
packet_stdout(fd, buf, r, NULL);
|
||||
}
|
||||
|
||||
printf("Exiting LIVE STREAM thread, fd %d\n", fd);
|
||||
|
||||
CCamManager::getInstance()->Stop(CZapit::getInstance()->GetCurrentChannelID(), CCamManager::STREAM);
|
||||
|
||||
delete dmx;
|
||||
delete []buf;
|
||||
close(fd);
|
||||
return 0;
|
||||
return !pids.empty();
|
||||
}
|
||||
#if 0
|
||||
//never used
|
||||
void streamts_file_thread(void *data)
|
||||
|
||||
void CStreamManager::run()
|
||||
{
|
||||
int dvrfd;
|
||||
unsigned char * buf;
|
||||
char cbuf[512];
|
||||
char *bp;
|
||||
unsigned char mode = 0;
|
||||
char tsfile[IN_SIZE];
|
||||
int tsfilelen = 0;
|
||||
int fileslice = 0;
|
||||
int i = 0;
|
||||
int fd = (int) data;
|
||||
struct sockaddr_in servaddr;
|
||||
int clilen = sizeof(servaddr);;
|
||||
|
||||
buf = (unsigned char *) malloc(IN_SIZE);
|
||||
struct pollfd pfd[128];
|
||||
int poll_cnt;
|
||||
|
||||
if (buf == NULL) {
|
||||
perror("malloc");
|
||||
return;
|
||||
}
|
||||
printf("Starting STREAM thread keeper, tid %ld\n", syscall(__NR_gettid));
|
||||
|
||||
bp = &cbuf[0];
|
||||
|
||||
/* read one line */
|
||||
while (bp - &cbuf[0] < IN_SIZE) {
|
||||
unsigned char c;
|
||||
read(fd, &c, 1);
|
||||
if ((*bp++ = c) == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
*bp++ = 0;
|
||||
bp = &cbuf[0];
|
||||
|
||||
/* send response to http client */
|
||||
if (!strncmp(cbuf, "GET /", 5)) {
|
||||
printf("HTTP/1.1 200 OK\r\nServer: streamts (%s)\r\n\r\n", "ts" /*&argv[1][1]*/);
|
||||
fflush(stdout);
|
||||
bp += 5;
|
||||
}
|
||||
|
||||
/* ts filename */
|
||||
int j = 0;
|
||||
i = 0;
|
||||
while (i < (int) strlen(bp) - 3)
|
||||
{
|
||||
if ((bp[i] == '.') && (bp[i + 1] == 't') && (bp[i + 2] == 's'))
|
||||
{
|
||||
tsfile[j] = bp[i];
|
||||
tsfile[j + 1] = bp[i + 1];
|
||||
tsfile[j + 2] = bp[i + 2];
|
||||
tsfile[j + 3] = '\0';
|
||||
break;
|
||||
}
|
||||
else
|
||||
if ((bp[i] == '%') && (bp[i + 1] == '2') && (bp[i + 2] == '0'))
|
||||
{
|
||||
tsfile[j++] = ' ';
|
||||
i += 3;
|
||||
while (running) {
|
||||
mutex.lock();
|
||||
pfd[0].fd = listenfd;
|
||||
pfd[0].events = (POLLIN | POLLPRI);
|
||||
pfd[0].revents = 0;
|
||||
poll_cnt = 1;
|
||||
for (streammap_iterator_t it = streams.begin(); it != streams.end(); ++it) {
|
||||
stream_fds_t fds = it->second->GetFds();
|
||||
for (stream_fds_t::iterator fit = fds.begin(); fit != fds.end(); ++fit) {
|
||||
pfd[poll_cnt].fd = *fit;
|
||||
pfd[poll_cnt].events = POLLRDHUP | POLLHUP;
|
||||
pfd[poll_cnt].revents = 0;
|
||||
poll_cnt++;
|
||||
}
|
||||
else
|
||||
tsfile[j++] = bp[i++];
|
||||
}
|
||||
tsfilelen = strlen(tsfile);
|
||||
/* open ts file */
|
||||
if ((dvrfd = open(tsfile, O_RDONLY)) < 0) {
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t pos;
|
||||
ssize_t r;
|
||||
|
||||
while (!exit_flag) {
|
||||
/* always read IN_SIZE bytes */
|
||||
for (pos = 0; pos < IN_SIZE; pos += r) {
|
||||
r = read(dvrfd, buf + pos, IN_SIZE - pos);
|
||||
if (r == -1) {
|
||||
/* Error */
|
||||
exit_flag = 1;
|
||||
break;
|
||||
} else if (r == 0) {
|
||||
/* End of file */
|
||||
if (mode == 3) {
|
||||
close(dvrfd);
|
||||
sprintf(&tsfile[tsfilelen], ".%03d", ++fileslice);
|
||||
dvrfd = open(tsfile, O_RDONLY);
|
||||
}
|
||||
if ((dvrfd == -1) || (mode != 3)) {
|
||||
exit_flag = 1;
|
||||
break;
|
||||
}
|
||||
mutex.unlock();
|
||||
//printf("polling, count= %d\n", poll_cnt);
|
||||
int pollres = poll (pfd, poll_cnt, 1000);
|
||||
if (pollres < 0) {
|
||||
perror("CStreamManager::run(): poll");
|
||||
continue;
|
||||
}
|
||||
if(pollres == 0)
|
||||
continue;
|
||||
for (int i = poll_cnt - 1; i >= 0; i--) {
|
||||
if (pfd[i].revents & (POLLIN | POLLPRI | POLLHUP | POLLRDHUP)) {
|
||||
printf("fd %d has events %x\n", pfd[i].fd, pfd[i].revents);
|
||||
if (pfd[i].fd == listenfd) {
|
||||
int connfd = accept (listenfd, (struct sockaddr *) &servaddr, (socklen_t *) & clilen);
|
||||
printf("CStreamManager::run(): connection, fd %d\n", connfd);
|
||||
if(connfd < 0) {
|
||||
perror("CStreamManager::run(): accept");
|
||||
continue;
|
||||
}
|
||||
stream_pids_t pids;
|
||||
t_channel_id channel_id;
|
||||
if (Parse(connfd, pids, channel_id)) {
|
||||
mutex.lock();
|
||||
streammap_iterator_t it = streams.find(channel_id);
|
||||
if (it != streams.end()) {
|
||||
it->second->AddClient(connfd);
|
||||
} else {
|
||||
CStreamInstance * stream = new CStreamInstance(connfd, channel_id, pids);
|
||||
if (stream->Start())
|
||||
streams.insert(streammap_pair_t(channel_id, stream));
|
||||
else
|
||||
delete stream;
|
||||
}
|
||||
mutex.unlock();
|
||||
} else {
|
||||
close(connfd);
|
||||
}
|
||||
} else {
|
||||
if (pfd[i].revents & (POLLHUP | POLLRDHUP)) {
|
||||
printf("CStreamManager::run(): POLLHUP, fd %d\n", pfd[i].fd);
|
||||
mutex.lock();
|
||||
for (streammap_iterator_t it = streams.begin(); it != streams.end(); ++it) {
|
||||
if (it->second->HasFd(pfd[i].fd)) {
|
||||
CStreamInstance *stream = it->second;
|
||||
stream->RemoveClient(pfd[i].fd);
|
||||
if (stream->GetFds().empty()) {
|
||||
streams.erase(stream->GetChannelId());
|
||||
delete stream;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
packet_stdout(fd, buf, pos, NULL);
|
||||
}
|
||||
close(dvrfd);
|
||||
free(buf);
|
||||
|
||||
return;
|
||||
printf("CStreamManager::run: stopping...\n");
|
||||
close(listenfd);
|
||||
listenfd = -1;
|
||||
StopAll();
|
||||
}
|
||||
|
||||
bool CStreamManager::StopAll()
|
||||
{
|
||||
bool ret = !streams.empty();
|
||||
for (streammap_iterator_t it = streams.begin(); it != streams.end(); ++it) {
|
||||
it->second->Stop();
|
||||
delete it->second;
|
||||
}
|
||||
streams.clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CStreamManager::StopStream(t_channel_id channel_id)
|
||||
{
|
||||
bool ret = false;
|
||||
mutex.lock();
|
||||
if (channel_id) {
|
||||
streammap_iterator_t it = streams.find(channel_id);
|
||||
if (it != streams.end()) {
|
||||
delete it->second;
|
||||
streams.erase(channel_id);
|
||||
ret = true;
|
||||
}
|
||||
} else {
|
||||
ret = StopAll();
|
||||
}
|
||||
mutex.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CStreamManager::StreamStatus(t_channel_id channel_id)
|
||||
{
|
||||
bool ret;
|
||||
mutex.lock();
|
||||
if (channel_id)
|
||||
ret = (streams.find(channel_id) != streams.end());
|
||||
else
|
||||
ret = !streams.empty();
|
||||
mutex.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CStreamManager::Listen()
|
||||
{
|
||||
struct sockaddr_in socketAddr;
|
||||
int socketOptActive = 1;
|
||||
int sendsize = 10*IN_SIZE;
|
||||
unsigned int m = sizeof(sendsize);
|
||||
|
||||
if ((listenfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
fprintf (stderr, "network port %u open: ", port);
|
||||
perror ("socket");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setsockopt (listenfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&socketOptActive, sizeof (int)) < 0) {
|
||||
fprintf (stderr, "network port %u open: error setsockopt\n", port);
|
||||
perror ("setsockopt");
|
||||
goto _error;
|
||||
}
|
||||
|
||||
socketAddr.sin_family = AF_INET;
|
||||
socketAddr.sin_port = htons (port);
|
||||
socketAddr.sin_addr.s_addr = htonl (INADDR_ANY);
|
||||
|
||||
if (bind (listenfd, (struct sockaddr *) &socketAddr, sizeof (socketAddr)) < 0) {
|
||||
fprintf (stderr, "network port %u open: ", port);
|
||||
perror ("bind");
|
||||
goto _error;
|
||||
}
|
||||
|
||||
if (listen (listenfd, 5) < 0) {
|
||||
fprintf (stderr, "network port %u open: ", port);
|
||||
perror ("listen");
|
||||
goto _error;
|
||||
}
|
||||
|
||||
#if 1
|
||||
setsockopt(listenfd, SOL_SOCKET, SO_SNDBUF, (void *)&sendsize, m);
|
||||
sendsize = 0;
|
||||
getsockopt(listenfd, SOL_SOCKET, SO_SNDBUF, (void *)&sendsize, &m);
|
||||
printf("CStreamManager::Listen: on %d, fd %d (%d)\n", port, listenfd, sendsize);
|
||||
#endif
|
||||
return true;
|
||||
_error:
|
||||
close (listenfd);
|
||||
return false;
|
||||
}
|
||||
#endif
|
96
src/driver/streamts.h
Normal file
96
src/driver/streamts.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
Neutrino-GUI - DBoxII-Project
|
||||
|
||||
Copyright (C) 2011-2012 CoolStream International Ltd
|
||||
|
||||
License: GPLv2
|
||||
|
||||
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;
|
||||
|
||||
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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __streamts_h__
|
||||
#define __streamts_h__
|
||||
|
||||
#include <OpenThreads/Thread>
|
||||
#include <OpenThreads/Condition>
|
||||
|
||||
#include <dmx.h>
|
||||
#include <zapit/client/zapittypes.h>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
typedef std::set<int> stream_pids_t;
|
||||
typedef std::set<int> stream_fds_t;
|
||||
|
||||
class CStreamInstance : public OpenThreads::Thread
|
||||
{
|
||||
private:
|
||||
bool running;
|
||||
cDemux * dmx;
|
||||
OpenThreads::Mutex mutex;
|
||||
unsigned char * buf;
|
||||
|
||||
t_channel_id channel_id;
|
||||
stream_pids_t pids;
|
||||
stream_fds_t fds;
|
||||
|
||||
bool Send(ssize_t r);
|
||||
void Close();
|
||||
void run();
|
||||
public:
|
||||
CStreamInstance(int clientfd, t_channel_id chid, stream_pids_t &pids);
|
||||
~CStreamInstance();
|
||||
bool Start();
|
||||
bool Stop();
|
||||
void AddClient(int clientfd);
|
||||
void RemoveClient(int clientfd);
|
||||
bool HasFd(int fd);
|
||||
stream_fds_t & GetFds() { return fds; }
|
||||
t_channel_id GetChannelId() { return channel_id; }
|
||||
};
|
||||
|
||||
typedef std::pair<t_channel_id, CStreamInstance*> streammap_pair_t;
|
||||
typedef std::map<t_channel_id, CStreamInstance*> streammap_t;
|
||||
typedef streammap_t::iterator streammap_iterator_t;
|
||||
|
||||
class CStreamManager : public OpenThreads::Thread
|
||||
{
|
||||
private:
|
||||
bool enabled;
|
||||
bool running;
|
||||
int listenfd;
|
||||
int port;
|
||||
|
||||
OpenThreads::Mutex mutex;
|
||||
static CStreamManager * sm;
|
||||
|
||||
streammap_t streams;
|
||||
|
||||
bool Listen();
|
||||
bool Parse(int fd, stream_pids_t &pids, t_channel_id &chid);
|
||||
bool StopAll();
|
||||
void run();
|
||||
CStreamManager();
|
||||
public:
|
||||
~CStreamManager();
|
||||
static CStreamManager * getInstance();
|
||||
bool Start(int port = 0);
|
||||
bool Stop();
|
||||
bool StopStream(t_channel_id channel_id = 0);
|
||||
bool StreamStatus(t_channel_id channel_id = 0);
|
||||
bool SetPort(int newport);
|
||||
int GetPort() { return port; }
|
||||
};
|
||||
|
||||
#endif
|
@@ -99,12 +99,6 @@ int CStartUpWizard::exec(CMenuTarget* parent, const string & /*actionKey*/)
|
||||
res = CNetworkSetup::getInstance()->exec(NULL, "");
|
||||
CNetworkSetup::getInstance()->setWizardMode(CNetworkSetup::N_SETUP_MODE_WIZARD_NO);
|
||||
}
|
||||
if(res != menu_return::RETURN_EXIT_ALL)
|
||||
{
|
||||
CScanSetup::getInstance()->setWizardMode(CScanSetup::SCAN_SETUP_MODE_WIZARD);
|
||||
res = CScanSetup::getInstance()->exec(NULL, "");
|
||||
CScanSetup::getInstance()->setWizardMode(CScanSetup::SCAN_SETUP_MODE_WIZARD_NO);
|
||||
}
|
||||
bool init_settings = false;
|
||||
if (g_info.delivery_system == DVB_S)
|
||||
init_settings = file_exists("/var/tuxbox/config/initial/");
|
||||
@@ -119,9 +113,13 @@ int CStartUpWizard::exec(CMenuTarget* parent, const string & /*actionKey*/)
|
||||
CZapit::getInstance()->PrepareChannels();
|
||||
}
|
||||
}
|
||||
if(res != menu_return::RETURN_EXIT_ALL)
|
||||
{
|
||||
CScanSetup::getInstance()->setWizardMode(CScanSetup::SCAN_SETUP_MODE_WIZARD);
|
||||
res = CScanSetup::getInstance()->exec(NULL, "");
|
||||
CScanSetup::getInstance()->setWizardMode(CScanSetup::SCAN_SETUP_MODE_WIZARD_NO);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
killBackgroundLogo();
|
||||
return res;
|
||||
|
@@ -56,6 +56,7 @@
|
||||
#include <driver/record.h>
|
||||
#include <driver/screenshot.h>
|
||||
#include <driver/volume.h>
|
||||
#include <driver/streamts.h>
|
||||
|
||||
#include "gui/audioplayer.h"
|
||||
#include "gui/bouquetlist.h"
|
||||
@@ -133,10 +134,6 @@ t_channel_id standby_channel_id;
|
||||
static pthread_t timer_thread;
|
||||
void * timerd_main_thread(void *data);
|
||||
|
||||
extern int streamts_stop;
|
||||
void * streamts_main_thread(void *data);
|
||||
static pthread_t stream_thread ;
|
||||
|
||||
void * nhttpd_main_thread(void *data);
|
||||
static pthread_t nhttpd_thread ;
|
||||
|
||||
@@ -1825,7 +1822,7 @@ TIMER_START();
|
||||
|
||||
pthread_create (&nhttpd_thread, NULL, nhttpd_main_thread, (void *) NULL);
|
||||
|
||||
pthread_create (&stream_thread, NULL, streamts_main_thread, (void *) NULL);
|
||||
CStreamManager::getInstance()->Start();
|
||||
|
||||
#ifndef DISABLE_SECTIONSD
|
||||
CSectionsdClient::epg_config config;
|
||||
@@ -3105,7 +3102,8 @@ void CNeutrinoApp::standbyMode( bool bOnOff, bool fromDeepStandby )
|
||||
g_Radiotext->radiotext_stop();
|
||||
|
||||
|
||||
if(!fromDeepStandby && !CRecordManager::getInstance()->RecordingStatus()) {
|
||||
bool stream_status = CStreamManager::getInstance()->StreamStatus();
|
||||
if(!fromDeepStandby && !CRecordManager::getInstance()->RecordingStatus() && !stream_status) {
|
||||
g_Zapit->setStandby(true);
|
||||
} else {
|
||||
g_Zapit->stopPlayBack();
|
||||
@@ -3442,7 +3440,6 @@ bool CNeutrinoApp::changeNotify(const neutrino_locale_t OptionName, void * /*dat
|
||||
**************************************************************************************/
|
||||
void stop_daemons(bool stopall)
|
||||
{
|
||||
streamts_stop = 1;
|
||||
dvbsub_close();
|
||||
tuxtxt_stop();
|
||||
tuxtxt_close();
|
||||
@@ -3455,7 +3452,7 @@ void stop_daemons(bool stopall)
|
||||
pthread_cancel(nhttpd_thread);
|
||||
pthread_join(nhttpd_thread, NULL);
|
||||
printf("httpd shutdown done\n");
|
||||
pthread_join(stream_thread, NULL);
|
||||
CStreamManager::getInstance()->Stop();
|
||||
if(stopall) {
|
||||
printf("timerd shutdown\n");
|
||||
g_Timerd->shutdown();
|
||||
|
@@ -32,7 +32,7 @@
|
||||
#include <dvbsi++/program_map_section.h>
|
||||
#include <dvbsi++/ca_program_map_section.h>
|
||||
|
||||
#define DEBUG_CAPMT
|
||||
//#define DEBUG_CAPMT
|
||||
|
||||
CCam::CCam()
|
||||
{
|
||||
|
Reference in New Issue
Block a user