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:
Jacek Jendrzej
2012-11-08 16:19:47 +01:00
10 changed files with 713 additions and 511 deletions

View File

@@ -26,7 +26,7 @@ libneutrino_driver_a_SOURCES = \
file.cpp \
fontrenderer.cpp \
framebuffer.cpp \
genpsi.c \
genpsi.cpp \
radiotext.cpp \
radiotools.cpp \
rcinput.cpp \

View File

@@ -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>

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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
View 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

View File

@@ -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;

View File

@@ -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();

View File

@@ -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()
{