diff --git a/data/locale/deutsch.locale b/data/locale/deutsch.locale
index a3a470790..ba8f1d949 100644
--- a/data/locale/deutsch.locale
+++ b/data/locale/deutsch.locale
@@ -211,6 +211,7 @@ channellist.foot_freq Tuning-Parameter
channellist.foot_next Nachfolgesendung
channellist.foot_off aus
channellist.foot_sort_alpha Sortiert[alpha]
+channellist.foot_sort_chnum Sortiert[nummer]
channellist.foot_sort_freq Sortiert[freq]
channellist.foot_sort_sat Sortiert[sat]
channellist.head Alle Kanäle
@@ -436,6 +437,7 @@ filesystem.is.utf8 Dateisystem
filesystem.is.utf8.option.iso8859.1 ISO-8859-1
filesystem.is.utf8.option.utf8 UTF-8
flashupdate.actionreadflash lese Flash
+flashupdate.apply_settings Sollen die aktuellen Einstellungen in das neue Image übernommen werden?
flashupdate.cantopenfile kann Datei nicht öffnen
flashupdate.cantopenmtd kann MTD nicht öffnen
flashupdate.checkupdate_internet Online nach Updates suchen
@@ -748,6 +750,7 @@ menu.hint_epg_fonts Ändern Sie für die EPG-Details die Schriftgrößen
menu.hint_epg_max_events Maximum an Events im Zwischenspeicher. Nach Erreichen der\nGrenze werden EPG-Daten für zukünftige gelöscht
menu.hint_epg_old_events EPG im Speicher behalten in Stunden,\nauch wenn es veraltet ist
menu.hint_epg_save Speichert die EPG-Daten auf einer Harddisk oder USB-Stick\nund läd es nach einen Neustart
+menu.hint_epg_save_standby Speichert die EPG-Daten in Bereitschaft Modus
menu.hint_event_textcolor Ändern Sie die Event-Farbe für farbige Event-Optionen in Kanalliste und Infobar
menu.hint_eventlist_fonts Ändern Sie in der Event-Liste die Schriftgrößen
menu.hint_extended Energiespar-, EPG-Speicher- / Lade-Optionen,\nHDMI-CEC, Startkanal, Zap-Optionen
@@ -1099,6 +1102,7 @@ miscsettings.epg_old_events EPG verwerfen nach (Std.)
miscsettings.epg_old_events_hint1 Wie lange abgelaufene EPG-Daten aufheben?
miscsettings.epg_old_events_hint2 Angabe in Stunden
miscsettings.epg_save EPG zwischenspeichern
+miscsettings.epg_save_standby EPG speichern in Standby-Modus
miscsettings.general Allgemein
miscsettings.head Erweitert
miscsettings.infobar Infobar
@@ -1318,6 +1322,8 @@ networkmenu.dhcp DHCP
networkmenu.error_no_address Keine %s-Adresse angegeben!
networkmenu.gateway Standard Gateway
networkmenu.hostname Hostname
+networkmenu.hostname_hint1 Geben sie den Hostnamen ein
+networkmenu.hostname_hint2 Eine Änderung benötigt einen Neustart
networkmenu.inactive_network Netzwerk nicht aktiviert!
networkmenu.ipaddress IP
networkmenu.mount Netzwerkfreigaben bearbeiten
diff --git a/data/locale/english.locale b/data/locale/english.locale
index b10b81d96..59b3fe7da 100644
--- a/data/locale/english.locale
+++ b/data/locale/english.locale
@@ -211,6 +211,7 @@ channellist.foot_freq Sat/Freq Info
channellist.foot_next next Event
channellist.foot_off off
channellist.foot_sort_alpha sorted[alpha]
+channellist.foot_sort_chnum sorted[number]
channellist.foot_sort_freq sorted[freq]
channellist.foot_sort_sat sorted[sat]
channellist.head All Services
@@ -436,6 +437,7 @@ filesystem.is.utf8 file system
filesystem.is.utf8.option.iso8859.1 ISO-8859-1
filesystem.is.utf8.option.utf8 UTF-8
flashupdate.actionreadflash reading
+flashupdate.apply_settings Import current settings into new image?
flashupdate.cantopenfile can't open file
flashupdate.cantopenmtd can't open MTD
flashupdate.checkupdate_internet Check for online updates
@@ -748,6 +750,7 @@ menu.hint_epg_fonts Change EPG details window font sizes
menu.hint_epg_max_events Maximum events to cache. After reaching limit\nEPG cache will remove future events
menu.hint_epg_old_events Hours after event end time to consider\nevent old and remove it from cache
menu.hint_epg_save Save cached EPG to harddisk or usb flash\nand load it after boot
+menu.hint_epg_save_standby Save EPG on soft standby mode
menu.hint_event_textcolor Change event color for colored-event options\nin channel list and infobar
menu.hint_eventlist_fonts Change event list font sizes
menu.hint_extended Power saving, EPG save/load options\nHDMI-CEC, Start channel, zap options
@@ -1099,6 +1102,7 @@ miscsettings.epg_old_events EPG remove after (std.)
miscsettings.epg_old_events_hint1 How long will EPG-Data be stored after they timed out?
miscsettings.epg_old_events_hint2 Set in hours
miscsettings.epg_save Save/Restore epg on reboot
+miscsettings.epg_save_standby Save epg on soft standby
miscsettings.general General
miscsettings.head Extended settings
miscsettings.infobar Infobar
@@ -1318,6 +1322,8 @@ networkmenu.dhcp DHCP
networkmenu.error_no_address Missing %s-address!
networkmenu.gateway default gateway
networkmenu.hostname Hostname
+networkmenu.hostname_hint1 enter hostname
+networkmenu.hostname_hint2 need reboot after change
networkmenu.inactive_network Network inactiv!
networkmenu.ipaddress IP address
networkmenu.mount Edit network shares
diff --git a/data/satellites.xml b/data/satellites.xml
index 66bad02de..739e4d754 100755
--- a/data/satellites.xml
+++ b/data/satellites.xml
@@ -1572,6 +1572,7 @@
+
diff --git a/data/settingsupdate.conf b/data/settingsupdate.conf
index bae28ab75..795e0025b 100644
--- a/data/settingsupdate.conf
+++ b/data/settingsupdate.conf
@@ -1,6 +1,6 @@
# settings for logfile
-Log=1
-LogFile=/tmp/update.log
+#:Log=1
+#:LogFile=/tmp/update.log
## Mögliche Einträge:
diff --git a/src/driver/Makefile.am b/src/driver/Makefile.am
index 0f6ed16c5..efc14c773 100644
--- a/src/driver/Makefile.am
+++ b/src/driver/Makefile.am
@@ -25,7 +25,7 @@ libneutrino_driver_a_SOURCES = \
fb_window.cpp \
file.cpp \
fontrenderer.cpp \
- genpsi.c \
+ genpsi.cpp \
radiotext.cpp \
radiotools.cpp \
rcinput.cpp \
diff --git a/src/driver/file.h b/src/driver/file.h
index 49cdaa04d..0ab9bca9c 100644
--- a/src/driver/file.h
+++ b/src/driver/file.h
@@ -40,7 +40,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 */
#endif
diff --git a/src/driver/genpsi.c b/src/driver/genpsi.cpp
similarity index 69%
rename from src/driver/genpsi.c
rename to src/driver/genpsi.cpp
index 6724369ea..266b727fd 100644
--- a/src/driver/genpsi.c
+++ b/src/driver/genpsi.cpp
@@ -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
+
#include
#include
#include
@@ -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> 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> 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>8);
+ pkt[ofs+3] = (vpid & 0xFF);
+ //-- for each audio stream, write row with desc. --
+ ofs += SIZE_ENIGMA_TAB_ROW;
+ for (i=0; 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>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;
}
diff --git a/src/driver/genpsi.h b/src/driver/genpsi.h
index 113eb883b..3e5c0a051 100644
--- a/src/driver/genpsi.h
+++ b/src/driver/genpsi.h
@@ -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
-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
diff --git a/src/driver/record.cpp b/src/driver/record.cpp
index 9fdb848bb..1f2b428da 100644
--- a/src/driver/record.cpp
+++ b/src/driver/record.cpp
@@ -51,6 +51,7 @@
#include
+#include
#include
#include
#include
@@ -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;
@@ -231,9 +233,9 @@ bool CRecordInstance::Stop(bool remove_event)
CCamManager::getInstance()->Stop(channel_id, CCamManager::RECORD);
if((autoshift && g_settings.auto_delete) /* || autoshift_delete*/) {
- snprintf(buf,sizeof(buf), "\"%s.ts\"", filename);
- my_system("nice", "-n20", "rm", "-f", buf);
- snprintf(buf,sizeof(buf), "%s.xml", filename);
+ snprintf(buf,sizeof(buf), "nice -n 20 rm -f \"%s.ts\" &", filename);
+ my_system("/bin/sh", "-c", buf);
+ snprintf(buf,sizeof(buf), "%s.xml", filename);
//autoshift_delete = false;
unlink(buf);
}
@@ -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 %" PRIx64 " result %d\n", __func__, 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);
diff --git a/src/driver/streamts.cpp b/src/driver/streamts.cpp
index 83d2ced89..9649e37f8 100644
--- a/src/driver/streamts.cpp
+++ b/src/driver/streamts.cpp
@@ -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
+ Copyright (C) 2001 TripleDES
+ Copyright (C) 2000, 2001 Marcus Metzler
+
+ 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
#include
#include
@@ -13,10 +39,8 @@
#include
#include
-/* work around for building with old kernel headers */
-#ifndef POLLRDHUP
-#define POLLRDHUP 0
-#endif
+#include
+#include
#ifdef HAVE_CONFIG_H
#include
@@ -28,250 +52,238 @@
#include
#include
#include
+#include
+#include
+#include
+#include
+/* 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, &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_cancel(st);
- 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);
+
+#ifndef HAVE_COOL_HARDWARE
+ /* right now, only one stream is possible anyway and it is not possible
+ * to stream a different channel than the live channel AFAICT, so we can
+ * as well use the live demux */
+ dmx = new cDemux(0);
+#else
+ dmx = new cDemux(STREAM_DEMUX);//FIXME
+#endif
+
+ 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);
- FILE * fp;
- unsigned char demuxfd_count = 0;
- printf("Starting LIVE STREAM thread, fd %d\n", fd);
- fp = fdopen(fd, "r+");
+ FILE * fp = fdopen(fd, "r+");
if(fp == NULL) {
perror("fdopen");
- return 0;
+ return false;
}
-
- writebuf_size = 0;
-
cbuf[0] = 0;
bp = &cbuf[0];
@@ -281,7 +293,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;
@@ -290,7 +302,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)) {
@@ -299,172 +311,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 = (unsigned char *) malloc(IN_SIZE);
- if (buf == NULL) {
- perror("malloc");
- 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);
-#ifndef HAVE_COOL_HARDWARE
- /* right now, only one stream is possible anyway and it is not possible
- * to stream a different channel than the live channel AFAICT, so we can
- * as well use the live demux */
- cDemux * dmx = new cDemux(0);
-#else
- cDemux * dmx = new cDemux(STREAM_DEMUX);//FIXME
-#endif
-
- 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;
- free(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;
+}
diff --git a/src/driver/streamts.h b/src/driver/streamts.h
new file mode 100644
index 000000000..9b10ddeca
--- /dev/null
+++ b/src/driver/streamts.h
@@ -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
+#include
+
+#include
+#include
+#include
+#include