Compare commits
86 commits
master
...
release/3.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
faee94bcb3 | ||
![]() |
661124c7a3 | ||
![]() |
e09a52f2c6 | ||
![]() |
72b4cd2a2a | ||
![]() |
98f5e898fd | ||
![]() |
165e3d4cb0 | ||
![]() |
c9e438e148 | ||
![]() |
b6862fe94a | ||
![]() |
e444d80a23 | ||
![]() |
897d243dbc | ||
![]() |
3aae092860 | ||
![]() |
4f9f348503 | ||
![]() |
0e589a3a43 | ||
![]() |
90236176ed | ||
![]() |
e8b55993af | ||
![]() |
4a67395ccc | ||
![]() |
40a8920a2a | ||
![]() |
ca5f880027 | ||
![]() |
10f7cb6f5c | ||
![]() |
4380a8051d | ||
![]() |
29dff2d94f | ||
![]() |
699d0464fc | ||
![]() |
c109026800 | ||
![]() |
144ec7dd14 | ||
![]() |
2aa067c73a | ||
![]() |
72e369a839 | ||
![]() |
74e73a98e9 | ||
![]() |
959d727be8 | ||
![]() |
e9fe361907 | ||
![]() |
b4c0cfe108 | ||
![]() |
940bc46014 | ||
![]() |
82dc9c035d | ||
![]() |
008b7058ac | ||
![]() |
8a29f8baf8 | ||
![]() |
97e0d05070 | ||
![]() |
90f4cdef23 | ||
![]() |
5ebb86fbf1 | ||
![]() |
e3231ec004 | ||
![]() |
af060cb70d | ||
![]() |
9b447c8ed7 | ||
![]() |
c74b0cf130 | ||
![]() |
6fe1bb5e7c | ||
![]() |
4bd0c355b4 | ||
![]() |
304a6ce26e | ||
![]() |
4303374f77 | ||
![]() |
89071bf55f | ||
![]() |
5bc5d30c66 | ||
![]() |
2ad41d959f | ||
![]() |
aa42a1c4af | ||
![]() |
091a4d608b | ||
![]() |
3e3c54100a | ||
![]() |
8a7db81088 | ||
![]() |
2dc947c5dc | ||
![]() |
1bc2dd9a25 | ||
![]() |
4e2ed9f406 | ||
![]() |
4daa250749 | ||
![]() |
6d3874c262 | ||
![]() |
9ee800a572 | ||
![]() |
78605b4a81 | ||
![]() |
b80fdefe16 | ||
![]() |
bf9b74be15 | ||
![]() |
274dd64c2c | ||
![]() |
c4ec5aae9e | ||
![]() |
af291917ae | ||
![]() |
7fc4b013c8 | ||
![]() |
4dce901813 | ||
![]() |
713d8cf511 | ||
![]() |
a652cbe541 | ||
![]() |
7771a7d7ef | ||
![]() |
fca3d93575 | ||
![]() |
7687dd4ecd | ||
![]() |
a0bf0d1d8f | ||
![]() |
9c44621116 | ||
![]() |
91cdb11c0d | ||
![]() |
da7869ebe8 | ||
![]() |
c8d4befefa | ||
![]() |
1b357d7040 | ||
![]() |
eee0a98600 | ||
![]() |
de85fef7c2 | ||
![]() |
48bc79843a | ||
![]() |
391f5912fe | ||
![]() |
329c7566aa | ||
![]() |
1c2dcd94bf | ||
![]() |
4e57ef651b | ||
![]() |
34c1fcb0bc | ||
![]() |
4ef346bda0 |
83 changed files with 1742 additions and 516 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -1,6 +1,8 @@
|
|||
build.*
|
||||
.config.mk
|
||||
|
||||
src/version.c
|
||||
|
||||
.cproject
|
||||
.project
|
||||
.settings
|
||||
|
@ -8,3 +10,9 @@ data/dvb-scan
|
|||
|
||||
*.pyc
|
||||
.*.sw[op]
|
||||
|
||||
debian/files
|
||||
debian/tvheadend
|
||||
debian/tvheadend-dbg
|
||||
debian/tvheadend*substvars
|
||||
debian/tvheadend*.debhelper*
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
BUILD_DEPS=`awk 'BEGIN {cnt = 1;} /^Build-Depends:/ {split($0, line, ":");split(line[2], deps, ",");for (i in deps) {d = deps[i];sub(/^ */, "", d);sub(/ *$/, "", d);split(d, tokens, " ");packages[cnt] = tokens[1];cnt++;}} END {out = ""; for(i = 1; i <= cnt; i++) {out = out packages[i] " ";} print out; }' debian/control`
|
||||
CHANGELOG=debian/changelog
|
||||
NOW=`date -R`
|
||||
VER=`git describe | sed "s/\([0-9]*\)\.\([0-9]*\)-\([0-9]*\)-.*/\1.\2.\3/"`
|
||||
VER=`$(dirname $0)/support/version`
|
||||
[ -z "${DEBDIST:-}" ] && DEBDIST=""
|
||||
|
||||
build()
|
||||
{
|
||||
echo >${CHANGELOG} "tvheadend (${VER}) unstable; urgency=low"
|
||||
echo >>${CHANGELOG}
|
||||
echo >>${CHANGELOG} " * The full changelog can be found at "
|
||||
echo >>${CHANGELOG} " http://www.lonelycoder.com/tvheadend/download"
|
||||
echo >>${CHANGELOG}
|
||||
echo >>${CHANGELOG} " -- Andreas Öman <andreas@lonelycoder.com> ${NOW}"
|
||||
$(dirname $0)/support/changelog "$CHANGELOG" "$DEBDIST" "$VER"
|
||||
|
||||
export JOBSARGS
|
||||
export JARGS
|
||||
|
@ -18,22 +14,22 @@ build()
|
|||
dpkg-buildpackage -b -us -uc
|
||||
|
||||
for a in ../tvheadend*${VER}*.deb; do
|
||||
versioned_artifact "$a" deb application/x-deb `basename $a`
|
||||
versioned_artifact "$a" deb application/x-deb `basename $a`
|
||||
done
|
||||
|
||||
for a in ../tvheadend*${VER}*.changes; do
|
||||
versioned_artifact "$a" changes text/plain `basename $a`
|
||||
versioned_artifact "$a" changes text/plain `basename $a`
|
||||
done
|
||||
}
|
||||
|
||||
clean()
|
||||
{
|
||||
for a in ../tvheadend*${VER}*.deb; do
|
||||
rm -f "$a"
|
||||
rm -f "$a"
|
||||
done
|
||||
|
||||
for a in ../tvheadend*${VER}*.changes; do
|
||||
rm -f "$a"
|
||||
rm -f "$a"
|
||||
done
|
||||
|
||||
rm -f ${CHANGELOG}
|
||||
|
@ -43,8 +39,8 @@ clean()
|
|||
deps()
|
||||
{
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "Build dependencies must be installed as root"
|
||||
exit 1
|
||||
echo "Build dependencies must be installed as root"
|
||||
exit 1
|
||||
fi
|
||||
apt-get -y install ${BUILD_DEPS}
|
||||
}
|
||||
|
|
3
Autobuild/lucid-amd64.sh
Normal file
3
Autobuild/lucid-amd64.sh
Normal file
|
@ -0,0 +1,3 @@
|
|||
AUTOBUILD_CONFIGURE_EXTRA="${AUTOBUILD_CONFIGURE_EXTRA:-} --arch=x86_64"
|
||||
DEBDIST=lucid
|
||||
source Autobuild/debian.sh
|
3
Autobuild/lucid-i386.sh
Normal file
3
Autobuild/lucid-i386.sh
Normal file
|
@ -0,0 +1,3 @@
|
|||
AUTOBUILD_CONFIGURE_EXTRA="${AUTOBUILD_CONFIGURE_EXTRA:-} --arch=i686"
|
||||
DEBDIST=lucid
|
||||
source Autobuild/debian.sh
|
|
@ -1,2 +1,3 @@
|
|||
AUTOBUILD_CONFIGURE_EXTRA="${AUTOBUILD_CONFIGURE_EXTRA:-_} --arch=x86_64"
|
||||
AUTOBUILD_CONFIGURE_EXTRA="${AUTOBUILD_CONFIGURE_EXTRA:-} --arch=x86_64"
|
||||
DEBDIST=precise
|
||||
source Autobuild/debian.sh
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
AUTOBUILD_CONFIGURE_EXTRA="${AUTOBUILD_CONFIGURE_EXTRA:-_} --arch=i686"
|
||||
AUTOBUILD_CONFIGURE_EXTRA="${AUTOBUILD_CONFIGURE_EXTRA:-} --arch=i686"
|
||||
DEBDIST=precise
|
||||
source Autobuild/debian.sh
|
||||
|
|
6
Makefile
6
Makefile
|
@ -146,6 +146,7 @@ SRCS += src/muxer.c \
|
|||
SRCS-${CONFIG_LINUXDVB} += \
|
||||
src/dvb/dvb.c \
|
||||
src/dvb/dvb_support.c \
|
||||
src/dvb/dvb_charset.c \
|
||||
src/dvb/dvb_fe.c \
|
||||
src/dvb/dvb_tables.c \
|
||||
src/dvb/diseqc.c \
|
||||
|
@ -232,9 +233,8 @@ distclean: clean
|
|||
rm -f ${CURDIR}/.config.mk
|
||||
|
||||
# Create buildversion.h
|
||||
src/version.c: $(BUILDDIR)/buildversion.h
|
||||
$(BUILDDIR)/buildversion.h: FORCE
|
||||
@$(CURDIR)/support/version.sh $(CURDIR) $@
|
||||
src/version.c: FORCE
|
||||
@$(CURDIR)/support/version $@ > /dev/null
|
||||
FORCE:
|
||||
|
||||
# Include dependency files if they exist.
|
||||
|
|
18
README
18
README
|
@ -1,8 +1,7 @@
|
|||
Tvheadend TV streaming server
|
||||
=============================
|
||||
|
||||
(c) 2006 - 2010 Andreas Öman, et al.
|
||||
|
||||
(c) 2006 - 2012 Andreas Öman, et al.
|
||||
|
||||
|
||||
How to build for Linux
|
||||
|
@ -12,17 +11,20 @@ First you need to configure:
|
|||
|
||||
$ ./configure
|
||||
|
||||
If any dependencies are missing the configure script will complain.
|
||||
You then have the option to disable that particular module/subsystem.
|
||||
If any dependencies are missing the configure script will complain or attempt
|
||||
to disable optional features.
|
||||
|
||||
$ make
|
||||
|
||||
Build the binary, after build the binary resides in 'build.Linux/'.
|
||||
Build the binary, after build the binary resides in 'build.linux/'.
|
||||
Thus, to start it, just type:
|
||||
|
||||
$ build.linux/tvheadend
|
||||
$ ./build.linux/tvheadend
|
||||
|
||||
Settings are stored in $HOME/.hts/tvheadend
|
||||
|
||||
For more information and latest versions, please visit:
|
||||
http://www.lonelycoder.com/hts/
|
||||
Further information
|
||||
===================
|
||||
|
||||
For more information about building, including generating packages please
|
||||
visit https://www.lonelycoder.com/redmine/projects/tvheadend/wiki/Building
|
||||
|
|
415
data/conf/charset
Normal file
415
data/conf/charset
Normal file
|
@ -0,0 +1,415 @@
|
|||
[
|
||||
{
|
||||
"tsid": 200,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 13878,
|
||||
"description": "ESP2 NE Polish"
|
||||
},
|
||||
{
|
||||
"tsid": 200,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 13865,
|
||||
"description": "Hotbird Eutelsat (Eurosport)"
|
||||
},
|
||||
{
|
||||
"tsid": 300,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 15206,
|
||||
"description": "Animal Planet HD"
|
||||
},
|
||||
{
|
||||
"tsid": 400,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 13020,
|
||||
"description": "Hotbird 13.0 Cyfra+ Canal+ HD Polska"
|
||||
},
|
||||
{
|
||||
"tsid": 400,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 13022,
|
||||
"description": "Hotbird 13.0 Cyfra+ Canal+ Sport HD Polska"
|
||||
},
|
||||
{
|
||||
"tsid": 400,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 13023,
|
||||
"description": "Hotbird 13.0 Cyfra+ National Geographic HD Polska"
|
||||
},
|
||||
{
|
||||
"tsid": 400,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 13025,
|
||||
"description": "Hotbird 13.0 Cyfra+ Filmbox HD"
|
||||
},
|
||||
{
|
||||
"tsid": 400,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 13026,
|
||||
"description": "Hotbird 13.0 Cyfra+ AXN Spin HD"
|
||||
},
|
||||
{
|
||||
"tsid": 400,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 13027,
|
||||
"description": "Hotbird 13.0 Cyfra+ TVN 7 HD"
|
||||
},
|
||||
{
|
||||
"tsid": 400,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 13070,
|
||||
"description": "Hotbird 13.0 Cyfra+ ESP HD PL"
|
||||
},
|
||||
{
|
||||
"tsid": 400,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 13081,
|
||||
"description": "EUROSPORT HD"
|
||||
},
|
||||
{
|
||||
"tsid": 400,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 13082,
|
||||
"description": "EUROSPORT HD"
|
||||
},
|
||||
{
|
||||
"tsid": 1000,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 4314,
|
||||
"description": "nSport"
|
||||
},
|
||||
{
|
||||
"tsid": 1000,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 0,
|
||||
"description": "Hotbird 13.0 Grupa ITI"
|
||||
},
|
||||
{
|
||||
"tsid": 1100,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 0,
|
||||
"description": "Hotbird 13.0 Cyfra+"
|
||||
},
|
||||
{
|
||||
"tsid": 1500,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 5110,
|
||||
"description": "TV Info"
|
||||
},
|
||||
{
|
||||
"tsid": 1500,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 5108,
|
||||
"description": "Fox Polska"
|
||||
},
|
||||
{
|
||||
"tsid": 1500,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 5102,
|
||||
"description": "TVS"
|
||||
},
|
||||
{
|
||||
"tsid": 1500,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 5122,
|
||||
"description": "Animal Planet Poland"
|
||||
},
|
||||
{
|
||||
"tsid": 1500,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 0,
|
||||
"description": "Hotbird 13.0 Cyfra+"
|
||||
},
|
||||
{
|
||||
"tsid": 1600,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 0,
|
||||
"description": "Hotbird 13.0 EskaTV, TVN"
|
||||
},
|
||||
{
|
||||
"tsid": 1800,
|
||||
"onid": 200,
|
||||
"charset": "ISO6937",
|
||||
"sid": 3623,
|
||||
"description": "Hotbird 13.0 Polo TV"
|
||||
},
|
||||
{
|
||||
"tsid": 7400,
|
||||
"onid": 113,
|
||||
"charset": "ISO6937",
|
||||
"sid": 0,
|
||||
"description": "Hotbird 13.0 Cyfrowy Polsat"
|
||||
},
|
||||
{
|
||||
"tsid": 7800,
|
||||
"onid": 113,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 0,
|
||||
"description": "Hotbird 13.0 Cyfrowy Polsat"
|
||||
},
|
||||
{
|
||||
"tsid": 7900,
|
||||
"onid": 113,
|
||||
"charset": "ISO6937",
|
||||
"sid": 10510,
|
||||
"description": "TV6 Polska"
|
||||
},
|
||||
{
|
||||
"tsid": 7900,
|
||||
"onid": 113,
|
||||
"charset": "ISO6937",
|
||||
"sid": 10508,
|
||||
"description": "Hotbird 13.0 Cyfrowy Polsat Jim Jam"
|
||||
},
|
||||
{
|
||||
"tsid": 7900,
|
||||
"onid": 113,
|
||||
"charset": "ISO6937",
|
||||
"sid": 10521,
|
||||
"description": "SuperStacja"
|
||||
},
|
||||
{
|
||||
"tsid": 7900,
|
||||
"onid": 113,
|
||||
"charset": "ISO6937",
|
||||
"sid": 10520,
|
||||
"description": "Travel Channel"
|
||||
},
|
||||
{
|
||||
"tsid": 7900,
|
||||
"onid": 113,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 0,
|
||||
"description": "Hotbird 13.0 Cyfrowy Polsat"
|
||||
},
|
||||
{
|
||||
"tsid": 8100,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 14911,
|
||||
"description": "UNIVERSAL POL"
|
||||
},
|
||||
{
|
||||
"tsid": 8100,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 14910,
|
||||
"description": "Sport Klub POL"
|
||||
},
|
||||
{
|
||||
"tsid": 8100,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 0,
|
||||
"description": "Hotbird 13.0 Eutelsat (Universal)"
|
||||
},
|
||||
{
|
||||
"tsid": 11000,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 0,
|
||||
"description": "Hotbird 13.0 Cyfra+"
|
||||
},
|
||||
{
|
||||
"tsid": 11400,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 15716,
|
||||
"description": "Discovery Channel Polska"
|
||||
},
|
||||
{
|
||||
"tsid": 11400,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 15701,
|
||||
"description": "Discovery Science Polska"
|
||||
},
|
||||
{
|
||||
"tsid": 11400,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 15703,
|
||||
"description": "Discovery World Polska"
|
||||
},
|
||||
{
|
||||
"tsid": 11400,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 0,
|
||||
"description": "Hotbird 13.0 Cyfra+"
|
||||
},
|
||||
{
|
||||
"tsid": 11600,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 3514,
|
||||
"description": "Disney XD Polska"
|
||||
},
|
||||
{
|
||||
"tsid": 11600,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 0,
|
||||
"description": "Hotbird 13.0 BBC HD, ITI"
|
||||
},
|
||||
{
|
||||
"tsid": 11900,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 0,
|
||||
"description": "Hotbird 13.0 Cyfra+"
|
||||
},
|
||||
{
|
||||
"tsid": 12200,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 0,
|
||||
"description": "Hotbird 13.0 Disney Channel Polska, TCM and other"
|
||||
},
|
||||
{
|
||||
"tsid": 12800,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 24,
|
||||
"description": "CC Family."
|
||||
},
|
||||
{
|
||||
"tsid": 12800,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 6,
|
||||
"description": "Viacom Blink!"
|
||||
},
|
||||
{
|
||||
"tsid": 12800,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 22,
|
||||
"description": "MTV Polska."
|
||||
},
|
||||
{
|
||||
"tsid": 12800,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 30,
|
||||
"description": "Comedy Central Polska."
|
||||
},
|
||||
{
|
||||
"tsid": 12800,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 25,
|
||||
"description": "VIVA Polska."
|
||||
},
|
||||
{
|
||||
"tsid": 12800,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 0,
|
||||
"description": "Hotbird 13.0 Viacom ... MTV / VH1 Polska"
|
||||
},
|
||||
{
|
||||
"tsid": 13000,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 14612,
|
||||
"description": "Investigation Discovery Polska"
|
||||
},
|
||||
{
|
||||
"tsid": 13000,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 14613,
|
||||
"description": "TLC Polska"
|
||||
},
|
||||
{
|
||||
"tsid": 13000,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 14602,
|
||||
"description": "BBC Entertainment Poland"
|
||||
},
|
||||
{
|
||||
"tsid": 13000,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 14603,
|
||||
"description": "BBC Knowledge Poland"
|
||||
},
|
||||
{
|
||||
"tsid": 13000,
|
||||
"onid": 318,
|
||||
"charset": "ISO8859-2",
|
||||
"sid": 0,
|
||||
"description": "Hotbird 13.0 BBC Polska, TLC and other"
|
||||
},
|
||||
{
|
||||
"tsid": 13100,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 7322,
|
||||
"description": "TV5 Monde Europe"
|
||||
},
|
||||
{
|
||||
"tsid": 13100,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 7324,
|
||||
"description": "Hotbird 13.0 Crime and Investigation"
|
||||
},
|
||||
{
|
||||
"tsid": 13200,
|
||||
"onid": 113,
|
||||
"charset": "ISO88959-2",
|
||||
"sid": 13104,
|
||||
"description": "Polsat Sport"
|
||||
},
|
||||
{
|
||||
"tsid": 13200,
|
||||
"onid": 113,
|
||||
"charset": "ISO88959-2",
|
||||
"sid": 13105,
|
||||
"description": "Polsat Sport Extra"
|
||||
},
|
||||
{
|
||||
"tsid": 13200,
|
||||
"onid": 113,
|
||||
"charset": "ISO88959-2",
|
||||
"sid": 13107,
|
||||
"description": "TV Biznes"
|
||||
},
|
||||
{
|
||||
"tsid": 13200,
|
||||
"onid": 113,
|
||||
"charset": "ISO6937",
|
||||
"sid": 0,
|
||||
"description": "Hotbird 13.0 Cyfrowy Polsat"
|
||||
},
|
||||
{
|
||||
"tsid": 15700,
|
||||
"onid": 318,
|
||||
"charset": "ISO6937",
|
||||
"sid": 10626,
|
||||
"description": "Hotbird 13.0 Disco TV"
|
||||
}
|
||||
]
|
2
debian/rules
vendored
2
debian/rules
vendored
|
@ -5,7 +5,7 @@ export DH_VERBOSE=1
|
|||
dh $@
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- ${JOBSARGS} --enable-avahi --enable-zlib
|
||||
dh_auto_configure -- ${JOBSARGS}
|
||||
|
||||
override_dh_auto_build:
|
||||
make ${JARGS}
|
||||
|
|
|
@ -47,12 +47,18 @@ The columns have the following functions:
|
|||
<dd>
|
||||
Only match events from the given channel.
|
||||
|
||||
<dt>Series Link
|
||||
<dd>
|
||||
Checkbox indicates that a series link (using EPG provided info) is being
|
||||
used, rather than a simple title match. The title field is still populated,
|
||||
for clarity, with the title of the event used to create the series link.
|
||||
|
||||
<dt>Channel tag
|
||||
<dd>
|
||||
Only match events from the channels which are included in the given tag.
|
||||
Tags are used for grouping channels and is configured by the administrator.
|
||||
|
||||
<dt>Content group
|
||||
<dt>Genre
|
||||
<dd>
|
||||
Only match events belonging to the given content group.
|
||||
|
||||
|
@ -65,6 +71,14 @@ The columns have the following functions:
|
|||
<dd>
|
||||
Only record events if they are scheduled +-15 minutes from this given time.
|
||||
|
||||
<dt>Priority
|
||||
<dd>
|
||||
The priority to give any recordings scheduled by this auto recording rule.
|
||||
|
||||
<dt>DVR configuration
|
||||
<dd>
|
||||
Select the DVR configuration profile to be used for scheduled recordings.
|
||||
|
||||
<dt>Created by
|
||||
<dd>
|
||||
Free text field, but will be copied to the recording session.
|
||||
|
|
|
@ -61,8 +61,11 @@ The columns have the following functions:
|
|||
|
||||
<dt>Video Recorder
|
||||
<dd>
|
||||
Enables access to all video recording functions. This also include administration
|
||||
of the auto recordings.
|
||||
Enables access to all video recording functions. This also include administration of the auto recordings.
|
||||
|
||||
<dt>All Configs (VR)
|
||||
<dd>
|
||||
Allow use of and configuration of DVR configuration profiles.
|
||||
|
||||
<dt>Web interface
|
||||
<dd>
|
||||
|
|
|
@ -31,12 +31,20 @@
|
|||
Changing name of a channel does not interfere with scheduled
|
||||
recordings etc.
|
||||
|
||||
<dt>XML-TV Source
|
||||
<dd>Name of the XML-TV channel. If you have XML-TV enabled you can
|
||||
select which XML-TV channel to obtain data from. By default
|
||||
Tvheadend tries to match the name itself, but sometimes it might
|
||||
not match between the XML-TV source and the TV provider so in
|
||||
such cases you can change it yourself.
|
||||
<dt>Play
|
||||
<dd>Play the channel using the VLC plugin (if available) else it will
|
||||
display a direct link that can be used to open in preferred media
|
||||
player.
|
||||
|
||||
<dt>EPG Grab Source
|
||||
<dd>Name of the Internet based EPG provider (typically XMLTV) channel
|
||||
that should be used to update this channels EPG info.
|
||||
By default Tvheadend tries to match the name itself, but sometimes
|
||||
it might not match correctly in which case you can do the mapping
|
||||
manually.
|
||||
<p>
|
||||
Over the air (OTA) sources do NOT need to be mapped in this way, the
|
||||
linking is implicitly tied since they are all part of the DVB system.
|
||||
|
||||
<dt>Tags
|
||||
<dd>Each channel can be bound to a zero, one or many tags.
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
|
||||
<dt>Adapter name
|
||||
<dd>
|
||||
You can change the display name for the adapter.
|
||||
You can change the display name for the adapter. This is highly recommended
|
||||
for multi-adapter setups with adapters that report the same name to avoid
|
||||
confusion.
|
||||
|
||||
<dt>Autodetect muxes
|
||||
<dd>
|
||||
|
@ -30,6 +32,15 @@
|
|||
on the same network. If this checkbox is enabled, Tvheadend will
|
||||
automatically create new muxes as it receives configuration for them
|
||||
via the DVB networks.
|
||||
|
||||
<dt>Skip initial scan
|
||||
<dd>
|
||||
By default Tvheadend will rescan all muxes before more detailed background
|
||||
scanning (including EPG scans) can be properly started. This is to verify
|
||||
all muxes are still valid.
|
||||
<br/>
|
||||
This will not stop the ability to watch live TV, however for most setups
|
||||
this option can be checked.
|
||||
|
||||
<dt>Idle scanning
|
||||
<dd>
|
||||
|
@ -37,11 +48,71 @@
|
|||
muxes and tune to them to verify that they are still working.
|
||||
If your adapter have problems with lots of tuning, try to disable this.
|
||||
|
||||
<dt>Detailed logging
|
||||
<dt>Close device handle when idle
|
||||
<dd>
|
||||
If this is enabled, Tvheadend will log more information related to
|
||||
this specific adapter. You might wanna enable this if you have some
|
||||
kind of issues in order to better diagnose the problems.
|
||||
This will attempt to close all available device handles. This can be
|
||||
necessary to allow some devices to go into low power states.
|
||||
<br/>
|
||||
However this option has been known to cause problems with some multi tuner
|
||||
DVB cards. If you have signal problems, try disabling this option.
|
||||
<br/>
|
||||
Note: this option has no effect if idle scanning is enabled.
|
||||
|
||||
<dt>Skip service availability check when mapping
|
||||
<dd>
|
||||
By default Tvheadend will validate that a service can be correctly
|
||||
received (including any descrambling) when mapping channels. You can disable
|
||||
this checking by enabling this option.
|
||||
|
||||
<dt>Use SID as channel number during mapping
|
||||
<dd>
|
||||
If you enable this option then the initial mapping of channels will use
|
||||
the service ID as the channel number, should no local channel number be
|
||||
provided in the service information tables.
|
||||
|
||||
<dt>Monitor signal quality
|
||||
<dd>
|
||||
If you enable this option Tvheadend will attempt to monitor signal quality
|
||||
of a mux using an internal metric. If the calculated quality falls to low
|
||||
the mux/adapter will generally be ignored.
|
||||
|
||||
<dt>Disable PMT monitoring
|
||||
<dd>
|
||||
This disable monitoring Program Map Table (PMT) for all services on a mux.
|
||||
<br/>
|
||||
Most people should not require this, but because this involves creating a
|
||||
lot of table filters, some DVB cards have problems and report errors related
|
||||
to too many open file descriptors. If this happens try enabling this option.
|
||||
|
||||
<dt>Write full DVB MUX to disk
|
||||
<dd>
|
||||
If this is enabled, Tvheadend will store the full mux stream to disk for
|
||||
debugging and development purposes. Don't enable this unless you know what
|
||||
you're doing.
|
||||
|
||||
<dt>Original Network ID
|
||||
<dd>
|
||||
If you experience problems caused by overlaps between multiple network
|
||||
providers this option can be used to filter which network ID is received
|
||||
by a given adapter.
|
||||
|
||||
<dt>Extra priority
|
||||
<dd>
|
||||
This field can be used to define a priority ordering for adapters. This will
|
||||
be used when determining which adapter to use to service a subscription
|
||||
request. It could be used for example to prefer a DVB-S adapter over a
|
||||
DVB-T one.
|
||||
|
||||
<dt>DiSEqC version (DVB-S only)
|
||||
<dd>
|
||||
If you're using a DiSEqC switch, then specify the version here.
|
||||
|
||||
<dt>Turn off LNB when idle
|
||||
<dd>
|
||||
This option can be enabled to disable the power to the LNB when the adapter
|
||||
is not in use. This can reduce power consumption, however for poorly shieled
|
||||
multi tuner setups you may some inteference when the LNB is re-enabled.
|
||||
|
||||
</dl>
|
||||
</dl>
|
||||
|
||||
|
@ -79,7 +150,16 @@
|
|||
|
||||
<dt>Modulation
|
||||
<dd>Information about the modulation used on the mux. Can not be changed
|
||||
|
||||
<dt>Polarisation
|
||||
<dd>Information about the polarisation used on the mux. Can not be changed
|
||||
|
||||
<dt>Satellite config (DVB-S only)
|
||||
<dd>The satellite configuration in use on this mux. Can not be changed.
|
||||
|
||||
<dt>Frontend status
|
||||
<dd>The status of the frontend signal last time the mux was tuned. Can not be changed
|
||||
|
||||
<dt>Mux id
|
||||
<dd>Unique ID for this mux in the dvb network. Can not be changed
|
||||
|
||||
|
@ -116,6 +196,9 @@
|
|||
<dt>Service name
|
||||
<dd>Service name as given in the DVB stream. Can not be changed
|
||||
|
||||
<dt>Play
|
||||
<dd>Open the VLC plugin window to play this service.
|
||||
|
||||
<dt>Channel name
|
||||
<dd>Double-click on this column to map the service to a channel.
|
||||
|
||||
|
@ -126,8 +209,8 @@
|
|||
but fail to correctly announce it. To fix this you can set the default
|
||||
charset to use when none is specified by the broadcaster.
|
||||
|
||||
<dt>EIT
|
||||
<dd>Uncheck this if EIT data should not be retreived for this service.
|
||||
<dt>EPG
|
||||
<dd>Uncheck this if EPG data should not be retreived for this service.
|
||||
|
||||
<dt>Type
|
||||
<dd>Type of service. Can not be changed
|
||||
|
@ -144,9 +227,47 @@
|
|||
<dt>Information button
|
||||
<dd>Press this to get a popup with more information about the service
|
||||
</dl>
|
||||
</dl>
|
||||
|
||||
<p>
|
||||
A word about DVB adapters
|
||||
<dl>
|
||||
<dt>Satellite config (DVB-S only)</dt>
|
||||
Satellite configurations in use on this adapter (for controlling
|
||||
switch equipment). The default entry will work fine for non-switched
|
||||
setups.
|
||||
|
||||
<ul>
|
||||
<li>To edit a cell, double-click on it. After a cell is changed it
|
||||
will flags one of its corner to red to indicated that it has been
|
||||
changed. To commit these changes back to Tvheadend press the
|
||||
'Save changes' button. In order to change a Checkbox cell you only
|
||||
have to click once in it.
|
||||
|
||||
<li>To delete one or more entries, select the lines (by clicking once on
|
||||
them), and press the 'Delete selected' button. A popup
|
||||
will ask you to confirm your request. Note, that if you have
|
||||
automatic mux discovery enabled the mux will probably come back
|
||||
quite soon.
|
||||
</ul>
|
||||
|
||||
The columns have the following functions:
|
||||
|
||||
<dl>
|
||||
<dt>Name
|
||||
<dd>Descriptive name for this configuration
|
||||
|
||||
<dt>Switchport
|
||||
<dd>Port number to select for this configuration (numbering begins at 0).
|
||||
|
||||
<dt>LNB type
|
||||
<dd>Select the LNB type from the list of supported LNBs. If your LNB
|
||||
is not supported please contact the Tvheadend team.
|
||||
|
||||
<dt>Comment
|
||||
<dd>General comment to remind you what this is for.
|
||||
</dl>
|
||||
</dl>
|
||||
|
||||
<h2>A word about DVB adapters</h2>
|
||||
<p>
|
||||
A DVB adapter represents a piece of hardware attached to the system.
|
||||
DVB receivers with dual tuners will present themselves as two adapters
|
||||
|
@ -169,6 +290,5 @@
|
|||
Warning2: Suspending a system is (from a USB driver perspective) equivalent
|
||||
to a unplug/insert event. Thus, suspending a system running Tvheadend
|
||||
with USB adapters is not recommended at the moment.
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -13,11 +13,22 @@
|
|||
<dd>Path to where Tvheadend will write recorded events. If components of
|
||||
the path does not exist, Tvheadend will try to create them.
|
||||
|
||||
<dt>Media container
|
||||
<dd>Select the container format used to store recordings.
|
||||
|
||||
<dt>DVR Log retention time (days)
|
||||
<dd>Time that Tvheadend will keep information about the recording in
|
||||
its internal database. Notice that the actual recorded file will not
|
||||
be deleted when the log entry is deleted.
|
||||
|
||||
<dt>Extra time before recordings (minutes)
|
||||
<dd>Specify the number of minutes to record before the events scheduled
|
||||
start time. Used to cope with small scheduling errors.
|
||||
|
||||
<dt>Extra time after recordings (minutes)
|
||||
<dd>Specify the number of minutes to record after the events scheduled
|
||||
stop time. Used to cope with small scheduling errors.
|
||||
|
||||
<dt>Make sub-directories per day
|
||||
<dd>If checked, Tvheadend will create a new directory per day in the
|
||||
recording system path. Only days when anything is recorded will be
|
||||
|
@ -52,6 +63,17 @@
|
|||
<dd>If checked, Tvheadend will include the season and episode in the
|
||||
title (if such info is available).
|
||||
|
||||
<dt>Remove all unsafe characters from filename
|
||||
<dd>If checked, all characters that could possibly cause problems for
|
||||
filenaming will be removed.
|
||||
|
||||
<dt>Replace whitespace in title with '-'
|
||||
<dd>If checked, all whitespace characters will be replaced with '-'.
|
||||
|
||||
<dt>Tag files with metadata
|
||||
<dd>If checked, media containers that support metadata will be tagged with
|
||||
the metadata associated with the event being recorded.
|
||||
|
||||
<dt>Post-processor command
|
||||
<dd>Command to run after finishing a recording. The command will be
|
||||
run in background and is executed even if a recording is aborted
|
||||
|
|
|
@ -3,56 +3,78 @@
|
|||
<p>
|
||||
This tab is used to configure EPG grabbing capabilities. TVheadend supports
|
||||
a variety of different EPG grabbing mechanisms. These fall into 3 broad
|
||||
categories, within which there are a variety of specific grabber implementations.
|
||||
categories, within which there are a variety of specific grabber
|
||||
implementations.
|
||||
</p>
|
||||
|
||||
<h2>Grabber Types</h2>
|
||||
<ul>
|
||||
<li>Over the Air (OTA) - these receive EPG data directly from the DVB network. This is often the easiest way to get up and running, and does provide timely updates should scheduling change. However the information isn't always as rich as some of the other grabbers.</li>
|
||||
<li>Interanl - These are grabbers which can be internally initiated from within TVheadend based on IP based grabbing solutions (see below). This can be a quick way to get richer EPG data where you don't have decent OTA support.</li>
|
||||
<li>External - These provide the option to run the grabber scripts externally and to pump the data into TVheadend via Unix domain sockets. It provides more complex configurations using things like cronjob's etc.</li>
|
||||
<li>Over-the-Air (OTA) - These grabbers receive EPG data directly from the DVB network. This is often the easiest way to get up and running and does provide timely updates should scheduling change. However the information isn't always as rich as some of the other grabbers.
|
||||
<li>Internal - These are grabbers which can be internally initiated from within TVheadend using a very simple scheduler. These are typically Internet based services. This can be a quick way to get richer EPG data where you don't have decent OTA support.
|
||||
<li>External - These provide the option to run grabber scripts externally and to send data into TVheadend via Unix domain sockets. It provides the ability to run more complex configurations using things like cronjob's, script chains, etc.
|
||||
</ul>
|
||||
|
||||
<h2>Grabber Modules</h2>
|
||||
<ul>
|
||||
<li>EIT - This is a DVB standards compatible EIT grabber. Typically it will
|
||||
retrieve now/next information, though on some networks there may be more
|
||||
extensive data published.</li>
|
||||
<li>OpenTV - This is a proprietary OTA EPG grabber. Its known to be used on the SKY networks, but others may use it. You need two configuration files to define settings for your particular network, if you don't see yours listed please visit IRC #hts for help.</li>
|
||||
<li>XMLTV - This is a IP network based scraper, for more information about XMLTV please visit <a href="http://www.xmltv.org">http://www.xmltv.org</a>. To make use of the internal XMLTV grabber you must have tv_find_grabbers installed. If you install new grabbers you will need to restart TVheadend to pick these up asthey're loaded at startup.</li>
|
||||
<li>PyEPG - This is another IP network based scraper. It currently only supports the Atlas UK system (for which you need a key), but it does provide a very rich EPG data set. For more information see <a href='http://github.com/adamsutton/PyEPG'>http://github.com/adamsutton/PyEPG</a>.</li>
|
||||
extensive data published.
|
||||
<li>Freesat/view - This is an extended version of EIT that is used by the Free-to-air DVB providers in the UK. It includes additional information such as series links and episode identifiers.
|
||||
<li>OpenTV - This is a proprietary OTA EPG grabber. Its known to be used on the SKY networks, but others may use it. You need two configuration files to define settings for your particular network, if you don't see yours listed please visit IRC #hts for help.
|
||||
<li>XMLTV - This is am Internet based suite of scripts, for more information about XMLTV please visit <a href="http://www.xmltv.org">http://www.xmltv.org</a>. To make use of the internal XMLTV grabber you typically require the xmltv-utils package to be installed. If you install new grabbers you will need to restart TVheadend to pick these up as they're loaded at startup. If you see no XMLTV grabbers listed then most probably XMLTV is not properly installed and in the PATH.
|
||||
<li>PyEPG - This is another Internet based scraper. It currently only supports the Atlas UK system (for which you need a key), but it does provide a very rich EPG data set. For more information see <a href='http://github.com/adamsutton/PyEPG'>http://github.com/adamsutton/PyEPG</a>.</li>
|
||||
</ul>
|
||||
|
||||
<h2>Configuration options</h2>
|
||||
<p>
|
||||
|
||||
<h3>General Config</h3>
|
||||
<dl>
|
||||
<dt>Update channel name
|
||||
<dd>Automatically update channel names using information provided
|
||||
by the enabled EPG providers.
|
||||
<dt>Update channel number
|
||||
<dd>Automatically update channel numbers using information provided
|
||||
by the enabled EPG providers.
|
||||
<dt>Update channel name
|
||||
<dd>Automatically update channel icons using information provided
|
||||
by the enabled EPG providers.
|
||||
</dl>
|
||||
|
||||
<h3>Internal Grabber</h3>
|
||||
<dl>
|
||||
<dt>Module:
|
||||
<dd>Select which internal grabber to use.
|
||||
|
||||
<dt>Grab interval
|
||||
<dd>Time period between grabs.
|
||||
|
||||
<dt>External interfaces
|
||||
<dd>Check tick boxes for whichever you want to make available, the Path column displays where the unix socket you need to use lives.
|
||||
|
||||
<dt>OTA interfaces
|
||||
<dd>Check tick boxes for whichever you want to use.
|
||||
|
||||
<dd>Time period between grabs. Value and unit are indepdently set.
|
||||
</dl>
|
||||
Changes to any of these settings must be confirmed by pressing the
|
||||
'Save configuration' button before taking effect.
|
||||
</p>
|
||||
|
||||
|
||||
<h3>Over-the-air Grabbers</h3>
|
||||
<p>
|
||||
Checkbox list to enable/disable available modules.
|
||||
By default all grabbers should be enabled.
|
||||
|
||||
<h3>External interfaces</h3>
|
||||
<p>
|
||||
Checkbox list to enable/disable available modules. The path field
|
||||
contains the absolute path of the unix domain socket into which EPG
|
||||
data can be sent.`
|
||||
<p>
|
||||
To send data to the socket use the command "netcat -u SOCKET_PATH".
|
||||
<br/>
|
||||
Note: for some systems the netcat flags can vary so please consult the
|
||||
man page.
|
||||
|
||||
<h2>Notes</h2>
|
||||
|
||||
<p>
|
||||
To apply any changes please use the [Save configuration button]
|
||||
|
||||
<p>
|
||||
XMLTV/PyEPG - if you are using the internal versions of these modules then
|
||||
you must first configure them (if required) externally as TVHeadend provides
|
||||
no support for this. Once configured though TVheadend will do the rest.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Mixed grabbers - Although as much as possible is done to avoid contention, generally speaking using a mixture of grabbers should be avoided (where each grabber updates the same channels). They typically tend to contain differing information which results in them "fighting" over which information is correct and can result in a high level of EPG update messages.
|
||||
you must first configure them externally as Tvheadend provides
|
||||
no support for this. Nor does it provide the ability to pass command line
|
||||
options (for this use the external interface).
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
|
48
docs/html/config_iptv.html
Normal file
48
docs/html/config_iptv.html
Normal file
|
@ -0,0 +1,48 @@
|
|||
<div class="hts-doc-text">
|
||||
|
||||
Tvheadend support receiving streams from compatible IPTV services. Currently
|
||||
the only compatible services are those that broadcast using MPEGTS over
|
||||
multicast UDP.
|
||||
|
||||
<p>
|
||||
The services are listed / edited in a grid.
|
||||
|
||||
<ul>
|
||||
<li>To edit a cell, double click on it. After a cell is changed it
|
||||
will flags one of its corner to red to indicated that it has been
|
||||
changed. To commit these changes back to Tvheadend press the
|
||||
'Save changes' button. In order to change a Checkbox cell you only
|
||||
have to click once in it.
|
||||
|
||||
<li>To add a new entry, press the 'Add entry' button. The new (empty) entry
|
||||
will be created on the server but will not be in its enabled state.
|
||||
You can now change all the cells to the desired values, check the
|
||||
'enable' box and then press 'Save changes' to activate the new entry.
|
||||
|
||||
<li>To delete one or more entries, select the lines (by clicking once on
|
||||
them), and press the 'Delete selected' button. A pop up
|
||||
will ask you to confirm your request.
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
The columns have the following functions:
|
||||
|
||||
<dl>
|
||||
<dt>Enabled
|
||||
<dd>If selected, the IPTV service will be enabled an use for channel
|
||||
subscriptions.
|
||||
|
||||
<dt>Channel name
|
||||
<dd>Select the channel this service will be mapped to.
|
||||
|
||||
<dt>Interface
|
||||
<dd>The ethernet interface to receive data on.
|
||||
|
||||
<dt>Group
|
||||
<dd>The multicast group to register with to receive data.
|
||||
|
||||
<dt>UDP Port
|
||||
<dd>Server UDP port
|
||||
|
||||
</dl>
|
||||
</div>
|
|
@ -6,10 +6,19 @@
|
|||
</p>
|
||||
|
||||
<dl>
|
||||
<dt>DVB scan files path:
|
||||
<dd>Select the path to use for DVB scan configuration files. Typically</dt>
|
||||
dvb-apps stores these in /usr/share/dvb/. Leave blank to use TVH's internal
|
||||
file set (probably stored at /usr/share/tvheadend/data/dvb-scan/)</dd>
|
||||
</dl>
|
||||
<dt>Default Language(s)
|
||||
<dd>
|
||||
Select the list of languages (in order of priority) to be used for supplying
|
||||
EPG information to clients that don't provide their own configuration.
|
||||
<p>
|
||||
The EPG information is NOT translated, this only applies to EPG providers
|
||||
that give information (titles, descriptions, etc..) in multiple languages.
|
||||
|
||||
<dt>DVB scan files path:
|
||||
<dd>
|
||||
Select the path to use for DVB scan configuration files. Typically
|
||||
dvb-apps stores these in /usr/share/dvb/. Leave blank to use TVH's internal
|
||||
file set.
|
||||
|
||||
</dl>
|
||||
</div>
|
||||
|
|
|
@ -21,20 +21,21 @@ sorted based on start time.
|
|||
expression. If you don't know what a regular expression is this means
|
||||
that you can type just parts of the title and filter on that too.
|
||||
(No need for exact matching).
|
||||
<dt>[Only include channel...]
|
||||
<dt>[Filter channel...]
|
||||
<dd>
|
||||
Only display events from the selected channel.
|
||||
<dt>[Only include tag...]
|
||||
Only display events from the selected channel. Channels in the drop down are
|
||||
ordered by channel number and can be filtered (by name) by typing in the box.
|
||||
<dt>[Filter tag...]
|
||||
<dd>
|
||||
Only display events from the channels which are included in the selected tag.
|
||||
Tags are used for grouping channels and is configured by the administrator.
|
||||
<dt>[Only include content...]
|
||||
<dt>[Filter content type...]
|
||||
<dd>
|
||||
Most DVB networks classify their events into content groups. This field
|
||||
allows you to filter based on content type.
|
||||
</dl>
|
||||
Thus, if you only would like to browse Movies from your HD-channels you
|
||||
would select 'HD channels' in the [Only include tag...]-field, and select
|
||||
would select 'HDTV' in the [Filter tag...]-field, and select
|
||||
'Movie / Drama' in the [Only include content...]-field.
|
||||
<p>
|
||||
Notice that you don't have to press a 'Search' button, the grid immediately
|
||||
|
@ -45,8 +46,8 @@ sorted based on start time.
|
|||
<dt>Paging
|
||||
|
||||
<dd>
|
||||
In an installation with many (hundreds of) channels and full EPG feed from
|
||||
both DVB and XMLTV there will be tens of thousands of events in the database.
|
||||
In large installations with many channels and full EPG feed there could be
|
||||
tens of thousands of events in the database.
|
||||
Therefore the EPG display employs a paging bar at the bottom of the grid.
|
||||
Use it to browse backwards and forwards in the EPG. It also displays the
|
||||
total amount of events matched by the current query.
|
||||
|
@ -57,6 +58,12 @@ sorted based on start time.
|
|||
about the event. It also allows the user to schedule the event for recording
|
||||
by clicking on the [Record program] button.
|
||||
<p>
|
||||
For EPG providers that supply series link information there will also be a
|
||||
[Record series] button that will record all entries in the series.
|
||||
<p>
|
||||
For events without any series link information, a [Autorec] button will be
|
||||
provided to create a pseudo series link using hte Autorec feature.
|
||||
<p>
|
||||
<img src="docresources/epg2.png">
|
||||
<p>
|
||||
To close the popup, just close it with the [X] window button.
|
||||
|
@ -67,7 +74,7 @@ sorted based on start time.
|
|||
<dt>Autorecordings
|
||||
<dd>
|
||||
Should you wish to record all events matching a specific query. (Record
|
||||
your favorite TV-show, etc) you can press the 'Create Autorec' button
|
||||
your favorite TV-show, etc) you can press the [Create Autorec] button
|
||||
in the top toolbar.
|
||||
<p>
|
||||
A popup with details about the to-be-created autorecording rule needs to
|
||||
|
@ -78,5 +85,11 @@ sorted based on start time.
|
|||
The autorecordings can later be changed/deleted in under the
|
||||
'Digital Video Recorder'-tag. Use that editor if you temporary want
|
||||
to disable an autorecording or make adjustments, etc.
|
||||
|
||||
<dt>Watch TV
|
||||
<dd>
|
||||
If you want to watch live TV in the web UI, the [Watch TV] button will pop-up
|
||||
a VLC plugin window (if you don't have the plugin installed a direct URL should be
|
||||
provided to load into your preferred media player).
|
||||
</dl>
|
||||
</div>
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
<dl>
|
||||
<dt>HTSP (Home TV Streaming Protocol), supported by Showtime Media player and <a href="http://www.xbmc.org/">XBMC</a>
|
||||
<dt>The Built-in Digital Video Recorder
|
||||
<dt>RTSP server
|
||||
</dl>
|
||||
|
||||
<dt>Modern web user interface
|
||||
|
@ -48,14 +47,14 @@
|
|||
|
||||
<dt>Digital Video Recorder
|
||||
<dd>
|
||||
Built in video recorder stores recorded programs as
|
||||
<a href="http://www.matroska.org/">Matroska (.mkv)</a> files.
|
||||
Built in video recorder stores recorded programs as either
|
||||
<a href="http://www.matroska.org/">Matroska (.mkv)</a> or MPEG TS (.ts) files.
|
||||
Multiple simultaneous recordings are supported.
|
||||
All original streams (multiple audio tracks, etc) are recorded.
|
||||
|
||||
<dt>Electronic Program Guide
|
||||
<dd>
|
||||
Imports data from DVB and <a href="http://www.xmltv.org">XMLTV</a>.
|
||||
Imports data from DVB and Internet providers such as <a href="http://www.xmltv.org">XMLTV</a>.
|
||||
Searchable from the web user interface. Results can be scheduled
|
||||
for recording with a single click.
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
|
||||
<center>
|
||||
<h1>HTS Tvheadend 2.11</h1>
|
||||
© 2006 - 2010, Andreas Öman, et al.<br><br>
|
||||
<h1>HTS Tvheadend 3.2</h1>
|
||||
© 2006 - 2012, Andreas Öman, et al.<br><br>
|
||||
<img style="padding: 0px" src="docresources/tvheadendlogo.png">
|
||||
</center>
|
||||
|
||||
|
|
|
@ -186,8 +186,6 @@ avc_convert_pkt(th_pkt_t *src)
|
|||
pkt->pkt_header = NULL;
|
||||
pkt->pkt_payload = NULL;
|
||||
|
||||
pkt->pkt_payload = malloc(sizeof(pktbuf_t));
|
||||
pkt->pkt_payload->pb_refcount=1;
|
||||
if (src->pkt_header) {
|
||||
sbuf_t headers;
|
||||
sbuf_init(&headers);
|
||||
|
|
|
@ -46,6 +46,13 @@ skip_bits(bitstream_t *bs, int num)
|
|||
bs->offset += num;
|
||||
}
|
||||
|
||||
int
|
||||
bs_eof(const bitstream_t *bs)
|
||||
{
|
||||
return bs->offset >= bs->len;
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
read_bits(bitstream_t *bs, int num)
|
||||
{
|
||||
|
@ -76,7 +83,7 @@ read_golomb_ue(bitstream_t *bs)
|
|||
{
|
||||
int b, lzb = -1;
|
||||
|
||||
for(b = 0; !b; lzb++)
|
||||
for(b = 0; !b && !bs_eof(bs); lzb++)
|
||||
b = read_bits1(bs);
|
||||
|
||||
return (1 << lzb) - 1 + read_bits(bs, lzb);
|
||||
|
|
|
@ -44,4 +44,6 @@ unsigned int remaining_bits(bitstream_t *gb);
|
|||
|
||||
void put_bits(bitstream_t *bs, int val, int num);
|
||||
|
||||
int bs_eof(const bitstream_t *bs);
|
||||
|
||||
#endif /* BITSTREAM_H_ */
|
||||
|
|
|
@ -210,14 +210,14 @@ channel_find_by_name(const char *name, int create, int channel_number)
|
|||
{
|
||||
channel_t skel, *ch;
|
||||
|
||||
if (!name || !*name) return NULL;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
skel.ch_name = (char *)name;
|
||||
ch = RB_FIND(&channel_name_tree, &skel, ch_name_link, channelcmp);
|
||||
if(ch != NULL || create == 0)
|
||||
return ch;
|
||||
if (name) {
|
||||
skel.ch_name = (char *)name;
|
||||
ch = RB_FIND(&channel_name_tree, &skel, ch_name_link, channelcmp);
|
||||
if(ch != NULL || create == 0)
|
||||
return ch;
|
||||
}
|
||||
return channel_create2(name, channel_number);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,9 +20,11 @@
|
|||
#include "tvheadend.h"
|
||||
#include "dvb.h"
|
||||
#include "dvb_support.h"
|
||||
#include "dvb_charset.h"
|
||||
|
||||
void
|
||||
dvb_init(uint32_t adapter_mask)
|
||||
{
|
||||
dvb_charset_init();
|
||||
dvb_adapter_init(adapter_mask);
|
||||
}
|
||||
|
|
|
@ -215,7 +215,7 @@ typedef struct th_dvb_adapter {
|
|||
struct dvb_satconf_queue tda_satconfs;
|
||||
|
||||
|
||||
struct th_dvb_mux_instance_list tda_mux_hash[TDA_MUX_HASH_WIDTH];
|
||||
struct th_dvb_mux_instance_list tda_mux_list;
|
||||
|
||||
uint32_t tda_dump_muxes;
|
||||
|
||||
|
@ -395,7 +395,7 @@ void dvb_mux_add_to_scan_queue (th_dvb_mux_instance_t *tdmi);
|
|||
/**
|
||||
* DVB Transport (aka DVB service)
|
||||
*/
|
||||
void dvb_transport_load(th_dvb_mux_instance_t *tdmi);
|
||||
void dvb_transport_load(th_dvb_mux_instance_t *tdmi, const char *tdmi_identifier);
|
||||
|
||||
struct service *dvb_transport_find(th_dvb_mux_instance_t *tdmi,
|
||||
uint16_t sid, int pmt_pid,
|
||||
|
|
|
@ -88,6 +88,7 @@ tda_save(th_dvb_adapter_t *tda)
|
|||
htsmsg_add_u32(m, "idlescan", tda->tda_idlescan);
|
||||
htsmsg_add_u32(m, "idleclose", tda->tda_idleclose);
|
||||
htsmsg_add_u32(m, "skip_checksubscr", tda->tda_skip_checksubscr);
|
||||
htsmsg_add_u32(m, "sidtochan", tda->tda_sidtochan);
|
||||
htsmsg_add_u32(m, "qmon", tda->tda_qmon);
|
||||
htsmsg_add_u32(m, "dump_muxes", tda->tda_dump_muxes);
|
||||
htsmsg_add_u32(m, "poweroff", tda->tda_poweroff);
|
||||
|
@ -481,7 +482,9 @@ dvb_adapter_start ( th_dvb_adapter_t *tda )
|
|||
|
||||
/* Start DVR thread */
|
||||
if (tda->tda_dvr_pipe[0] == -1) {
|
||||
assert(pipe(tda->tda_dvr_pipe) != -1);
|
||||
int err = pipe(tda->tda_dvr_pipe);
|
||||
assert(err != -1);
|
||||
|
||||
fcntl(tda->tda_dvr_pipe[0], F_SETFD, fcntl(tda->tda_dvr_pipe[0], F_GETFD) | FD_CLOEXEC);
|
||||
fcntl(tda->tda_dvr_pipe[0], F_SETFL, fcntl(tda->tda_dvr_pipe[0], F_GETFL) | O_NONBLOCK);
|
||||
fcntl(tda->tda_dvr_pipe[1], F_SETFD, fcntl(tda->tda_dvr_pipe[1], F_GETFD) | FD_CLOEXEC);
|
||||
|
@ -509,7 +512,8 @@ dvb_adapter_stop ( th_dvb_adapter_t *tda )
|
|||
/* Stop DVR thread */
|
||||
if (tda->tda_dvr_pipe[0] != -1) {
|
||||
tvhlog(LOG_DEBUG, "dvb", "%s stopping thread", tda->tda_rootpath);
|
||||
assert(write(tda->tda_dvr_pipe[1], "", 1) == 1);
|
||||
int err = write(tda->tda_dvr_pipe[1], "", 1);
|
||||
assert(err != -1);
|
||||
pthread_join(tda->tda_dvr_thread, NULL);
|
||||
close(tda->tda_dvr_pipe[0]);
|
||||
close(tda->tda_dvr_pipe[1]);
|
||||
|
@ -567,6 +571,7 @@ dvb_adapter_init(uint32_t adapter_mask)
|
|||
htsmsg_get_u32(c, "idlescan", &tda->tda_idlescan);
|
||||
htsmsg_get_u32(c, "idleclose", &tda->tda_idleclose);
|
||||
htsmsg_get_u32(c, "skip_checksubscr", &tda->tda_skip_checksubscr);
|
||||
htsmsg_get_u32(c, "sidtochan", &tda->tda_sidtochan);
|
||||
htsmsg_get_u32(c, "qmon", &tda->tda_qmon);
|
||||
htsmsg_get_u32(c, "dump_muxes", &tda->tda_dump_muxes);
|
||||
htsmsg_get_u32(c, "poweroff", &tda->tda_poweroff);
|
||||
|
@ -742,6 +747,7 @@ dvb_adapter_input_dvr(void *aux)
|
|||
|
||||
/* Create poll */
|
||||
efd = epoll_create(2);
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.fd = fd;
|
||||
epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ev);
|
||||
|
@ -760,8 +766,16 @@ dvb_adapter_input_dvr(void *aux)
|
|||
if (c < 0) {
|
||||
if (errno == EAGAIN || errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
else if (errno == EOVERFLOW) {
|
||||
tvhlog(LOG_WARNING, "dvb", "\"%s\" read() EOVERFLOW",
|
||||
tda->tda_identifier);
|
||||
continue;
|
||||
} else {
|
||||
// TODO: should we try to recover?
|
||||
tvhlog(LOG_ERR, "dvb", "\"%s\" read() error %d",
|
||||
tda->tda_identifier, errno);
|
||||
break;
|
||||
}
|
||||
}
|
||||
r += c;
|
||||
|
||||
|
@ -803,7 +817,7 @@ dvb_adapter_input_dvr(void *aux)
|
|||
pthread_mutex_unlock(&tda->tda_delivery_mutex);
|
||||
|
||||
/* reset buffer */
|
||||
if (r) {memmove(tsb, tsb+i, r);printf("move");}
|
||||
if (r) memmove(tsb, tsb+i, r);
|
||||
i = 0;
|
||||
}
|
||||
|
||||
|
|
96
src/dvb/dvb_charset.c
Normal file
96
src/dvb/dvb_charset.c
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* tvheadend, charset list
|
||||
* Copyright (C) 2012 Mariusz Białończyk
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "tvheadend.h"
|
||||
#include "settings.h"
|
||||
#include "dvb/dvb_charset.h"
|
||||
|
||||
/*
|
||||
* Process a file
|
||||
*/
|
||||
static void _charset_load_file()
|
||||
{
|
||||
htsmsg_t *l, *e;
|
||||
htsmsg_field_t *f;
|
||||
|
||||
dvb_charset_t *enc;
|
||||
const char *charset;
|
||||
uint32_t tsid, onid, sid;
|
||||
int i = 0;
|
||||
|
||||
l = hts_settings_load("charset");
|
||||
if (l)
|
||||
{
|
||||
HTSMSG_FOREACH(f, l) {
|
||||
if ((e = htsmsg_get_map_by_field(f))) {
|
||||
tsid = onid = sid = 0;
|
||||
htsmsg_get_u32(e, "onid", &onid);
|
||||
htsmsg_get_u32(e, "tsid", &tsid);
|
||||
htsmsg_get_u32(e, "sid", &sid);
|
||||
charset = htsmsg_get_str(e, "charset");
|
||||
|
||||
if (tsid == 0 || onid == 0 || !charset)
|
||||
continue;
|
||||
|
||||
enc = calloc(1, sizeof(dvb_charset_t));
|
||||
if (enc)
|
||||
{
|
||||
enc->onid = onid;
|
||||
enc->tsid = tsid;
|
||||
enc->sid = sid;
|
||||
enc->charset = strdup(charset);
|
||||
LIST_INSERT_HEAD(&dvb_charset_list, enc, link);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
};
|
||||
htsmsg_destroy(l);
|
||||
};
|
||||
|
||||
if (i > 0)
|
||||
tvhlog(LOG_INFO, "charset", "%d entries loaded", i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise the charset list
|
||||
*/
|
||||
void dvb_charset_init ( void )
|
||||
{
|
||||
_charset_load_file();
|
||||
}
|
||||
|
||||
/*
|
||||
* Find default charset
|
||||
*/
|
||||
const char *dvb_charset_find
|
||||
( uint16_t tsid, uint16_t sid )
|
||||
{
|
||||
dvb_charset_t *ret = NULL, *enc;
|
||||
LIST_FOREACH(enc, &dvb_charset_list, link) {
|
||||
if (tsid == enc->tsid) {
|
||||
if (sid == enc->sid) {
|
||||
ret = enc;
|
||||
break;
|
||||
} else if (!enc->sid) {
|
||||
ret = enc;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret ? ret->charset : NULL;
|
||||
}
|
37
src/dvb/dvb_charset.h
Normal file
37
src/dvb/dvb_charset.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* tvheadend, dvb charset config
|
||||
* Copyright (C) 2012 Mariusz Białończyk
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __TVH_DVB_CHARSET_H__
|
||||
#define __TVH_DVB_CHARSET_H__
|
||||
|
||||
typedef struct dvb_charset {
|
||||
LIST_ENTRY(dvb_charset) link;
|
||||
uint16_t onid;
|
||||
uint16_t tsid;
|
||||
uint16_t sid;
|
||||
const char *charset;
|
||||
} dvb_charset_t;
|
||||
|
||||
LIST_HEAD(,dvb_charset) dvb_charset_list;
|
||||
|
||||
void dvb_charset_init ( void );
|
||||
|
||||
const char *dvb_charset_find
|
||||
(uint16_t tsid, uint16_t sid);
|
||||
|
||||
#endif /* __TVH_DVB_CHARSET_H__ */
|
|
@ -104,7 +104,10 @@ static int
|
|||
tdmi_compare_key(const struct dvb_mux_conf *a,
|
||||
const struct dvb_mux_conf *b)
|
||||
{
|
||||
return a->dmc_fe_params.frequency == b->dmc_fe_params.frequency &&
|
||||
int32_t fd = (int32_t)a->dmc_fe_params.frequency
|
||||
- (int32_t)b->dmc_fe_params.frequency;
|
||||
fd = labs(fd);
|
||||
return fd < 2000 &&
|
||||
a->dmc_polarisation == b->dmc_polarisation &&
|
||||
a->dmc_satconf == b->dmc_satconf;
|
||||
}
|
||||
|
@ -155,15 +158,12 @@ dvb_mux_create(th_dvb_adapter_t *tda, const struct dvb_mux_conf *dmc,
|
|||
dvb_satconf_t *satconf)
|
||||
{
|
||||
th_dvb_mux_instance_t *tdmi, *c;
|
||||
unsigned int hash;
|
||||
char buf[200];
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
hash = (dmc->dmc_fe_params.frequency +
|
||||
dmc->dmc_polarisation) % TDA_MUX_HASH_WIDTH;
|
||||
|
||||
LIST_FOREACH(tdmi, &tda->tda_mux_hash[hash], tdmi_adapter_hash_link) {
|
||||
/* HACK - we hash/compare based on 2KHz spacing and compare on +/-500Hz */
|
||||
LIST_FOREACH(tdmi, &tda->tda_mux_list, tdmi_adapter_hash_link) {
|
||||
if(tdmi_compare_key(&tdmi->tdmi_conf, dmc))
|
||||
break; /* Mux already exist */
|
||||
}
|
||||
|
@ -172,6 +172,7 @@ dvb_mux_create(th_dvb_adapter_t *tda, const struct dvb_mux_conf *dmc,
|
|||
/* Update stuff ... */
|
||||
int save = 0;
|
||||
char buf2[1024];
|
||||
buf2[0] = 0;
|
||||
|
||||
if(tdmi_compare_conf(tda->tda_type, &tdmi->tdmi_conf, dmc)) {
|
||||
#if DVB_API_VERSION >= 5
|
||||
|
@ -189,19 +190,25 @@ dvb_mux_create(th_dvb_adapter_t *tda, const struct dvb_mux_conf *dmc,
|
|||
dvb_mux_rolloff2str(tdmi->tdmi_conf.dmc_fe_rolloff),
|
||||
dvb_mux_rolloff2str(dmc->dmc_fe_rolloff));
|
||||
sprintf(buf2, "%s)", buf2);
|
||||
#else
|
||||
buf2[0] = 0;
|
||||
#endif
|
||||
|
||||
memcpy(&tdmi->tdmi_conf, dmc, sizeof(struct dvb_mux_conf));
|
||||
save = 1;
|
||||
}
|
||||
|
||||
if(tdmi->tdmi_transport_stream_id != tsid) {
|
||||
if(tsid != 0xFFFF && tdmi->tdmi_transport_stream_id != tsid) {
|
||||
tdmi->tdmi_transport_stream_id = tsid;
|
||||
save = 1;
|
||||
}
|
||||
|
||||
/* HACK - load old transports and remove old mux config */
|
||||
if(identifier) {
|
||||
save = 1;
|
||||
dvb_transport_load(tdmi, identifier);
|
||||
hts_settings_remove("dvbmuxes/%s/%s",
|
||||
tda->tda_identifier, identifier);
|
||||
}
|
||||
|
||||
if(save) {
|
||||
dvb_mux_save(tdmi);
|
||||
dvb_mux_nicename(buf, sizeof(buf), tdmi);
|
||||
|
@ -268,7 +275,7 @@ dvb_mux_create(th_dvb_adapter_t *tda, const struct dvb_mux_conf *dmc,
|
|||
tdmi, tdmi_satconf_link);
|
||||
}
|
||||
|
||||
LIST_INSERT_HEAD(&tda->tda_mux_hash[hash], tdmi, tdmi_adapter_hash_link);
|
||||
LIST_INSERT_HEAD(&tda->tda_mux_list, tdmi, tdmi_adapter_hash_link);
|
||||
LIST_INSERT_HEAD(&tda->tda_muxes, tdmi, tdmi_adapter_link);
|
||||
|
||||
if(source != NULL) {
|
||||
|
@ -279,15 +286,17 @@ dvb_mux_create(th_dvb_adapter_t *tda, const struct dvb_mux_conf *dmc,
|
|||
dvb_adapter_notify(tda);
|
||||
}
|
||||
|
||||
dvb_transport_load(tdmi);
|
||||
dvb_transport_load(tdmi, identifier);
|
||||
dvb_mux_notify(tdmi);
|
||||
|
||||
if(enabled && initialscan) {
|
||||
tda->tda_initial_num_mux++;
|
||||
tdmi->tdmi_table_initial = 1;
|
||||
mux_link_initial(tda, tdmi);
|
||||
} else {
|
||||
dvb_mux_add_to_scan_queue(tdmi);
|
||||
if(enabled) {
|
||||
if(initialscan) {
|
||||
tda->tda_initial_num_mux++;
|
||||
tdmi->tdmi_table_initial = 1;
|
||||
mux_link_initial(tda, tdmi);
|
||||
} else {
|
||||
dvb_mux_add_to_scan_queue(tdmi);
|
||||
}
|
||||
}
|
||||
|
||||
return tdmi;
|
||||
|
@ -864,6 +873,9 @@ tdmi_set_enable(th_dvb_mux_instance_t *tdmi, int enabled)
|
|||
|
||||
if(tdmi->tdmi_enabled) {
|
||||
|
||||
if(tda->tda_mux_current == tdmi)
|
||||
dvb_fe_stop(tdmi, 0);
|
||||
|
||||
if(tdmi->tdmi_scan_queue != NULL) {
|
||||
TAILQ_REMOVE(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
|
||||
tdmi->tdmi_scan_queue = NULL;
|
||||
|
@ -1174,8 +1186,8 @@ dvb_mux_copy(th_dvb_adapter_t *dst, th_dvb_mux_instance_t *tdmi_src,
|
|||
if(t_src->s_svcname != NULL)
|
||||
t_dst->s_svcname = strdup(t_src->s_svcname);
|
||||
|
||||
if(t_src->s_dvb_default_charset != NULL)
|
||||
t_dst->s_dvb_default_charset = strdup(t_src->s_dvb_default_charset);
|
||||
if(t_src->s_dvb_charset != NULL)
|
||||
t_dst->s_dvb_charset = strdup(t_src->s_dvb_charset);
|
||||
|
||||
if(t_src->s_ch != NULL)
|
||||
service_map_channel(t_dst, t_src->s_ch, 0);
|
||||
|
|
|
@ -296,6 +296,7 @@ dvb_lnblist_get(void)
|
|||
add_to_lnblist(array, "C-Band");
|
||||
add_to_lnblist(array, "C-Multi");
|
||||
add_to_lnblist(array, "Circular 10750");
|
||||
add_to_lnblist(array, "Ku 11300");
|
||||
return array;
|
||||
}
|
||||
|
||||
|
@ -338,5 +339,9 @@ dvb_lnb_get_frequencies(const char *id, int *f_low, int *f_hi, int *f_switch)
|
|||
*f_low = 10750000;
|
||||
*f_hi = 0;
|
||||
*f_switch = 0;
|
||||
} else if(!strcmp(id, "Ku 11300")) {
|
||||
*f_low = 11300000;
|
||||
*f_hi = 0;
|
||||
*f_switch = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,10 +95,7 @@ static inline size_t conv_8859(int conv,
|
|||
(*dstlen)--;
|
||||
dst++;
|
||||
} else if (c <= 0x9f) {
|
||||
// codes 0x80 - 0x9f (control codes) are mapped to ' '
|
||||
*dst = ' ';
|
||||
(*dstlen)--;
|
||||
dst++;
|
||||
// codes 0x80 - 0x9f (control codes) are ignored
|
||||
} else {
|
||||
// map according to character table, skipping
|
||||
// unmapped chars (value 0 in the table)
|
||||
|
@ -135,10 +132,7 @@ static inline size_t conv_6937(const uint8_t *src, size_t srclen,
|
|||
(*dstlen)--;
|
||||
dst++;
|
||||
} else if (c <= 0x9f) {
|
||||
// codes 0x80 - 0x9f (control codes) are mapped to ' '
|
||||
*dst = ' ';
|
||||
(*dstlen)--;
|
||||
dst++;
|
||||
// codes 0x80 - 0x9f (control codes) are ignored
|
||||
} else {
|
||||
uint16_t uc;
|
||||
if (c >= 0xc0 && c <= 0xcf) {
|
||||
|
@ -202,7 +196,7 @@ static inline size_t dvb_convert(int conv,
|
|||
*/
|
||||
|
||||
int
|
||||
dvb_get_string(char *dst, size_t dstlen, const uint8_t *src, size_t srclen, char *dvb_default_charset, dvb_string_conv_t *conv)
|
||||
dvb_get_string(char *dst, size_t dstlen, const uint8_t *src, size_t srclen, const char *dvb_charset, dvb_string_conv_t *conv)
|
||||
{
|
||||
int ic;
|
||||
size_t len, outlen;
|
||||
|
@ -220,6 +214,7 @@ dvb_get_string(char *dst, size_t dstlen, const uint8_t *src, size_t srclen, char
|
|||
conv++;
|
||||
}
|
||||
|
||||
// automatic charset detection
|
||||
switch(src[0]) {
|
||||
case 0:
|
||||
return -1;
|
||||
|
@ -250,16 +245,17 @@ dvb_get_string(char *dst, size_t dstlen, const uint8_t *src, size_t srclen, char
|
|||
return -1;
|
||||
|
||||
default:
|
||||
if (dvb_default_charset != NULL && sscanf(dvb_default_charset, "ISO8859-%d", &i) > 0) {
|
||||
if (i > 0 && i < 16) {
|
||||
ic = convert_iso_8859[i];
|
||||
} else {
|
||||
ic = convert_iso6937;
|
||||
}
|
||||
ic = convert_iso6937;
|
||||
break;
|
||||
}
|
||||
|
||||
// manual charset override
|
||||
if (dvb_charset != NULL && dvb_charset[0] != 0) {
|
||||
if (sscanf(dvb_charset, "ISO8859-%d", &i) > 0 && i > 0 && i < 16) {
|
||||
ic = convert_iso_8859[i];
|
||||
} else {
|
||||
ic = convert_iso6937;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(srclen < 1) {
|
||||
|
@ -284,7 +280,7 @@ dvb_get_string(char *dst, size_t dstlen, const uint8_t *src, size_t srclen, char
|
|||
|
||||
int
|
||||
dvb_get_string_with_len(char *dst, size_t dstlen,
|
||||
const uint8_t *buf, size_t buflen, char *dvb_default_charset,
|
||||
const uint8_t *buf, size_t buflen, const char *dvb_charset,
|
||||
dvb_string_conv_t *conv)
|
||||
{
|
||||
int l = buf[0];
|
||||
|
@ -292,7 +288,7 @@ dvb_get_string_with_len(char *dst, size_t dstlen,
|
|||
if(l + 1 > buflen)
|
||||
return -1;
|
||||
|
||||
if(dvb_get_string(dst, dstlen, buf + 1, l, dvb_default_charset, conv))
|
||||
if(dvb_get_string(dst, dstlen, buf + 1, l, dvb_charset, conv))
|
||||
return -1;
|
||||
|
||||
return l + 1;
|
||||
|
|
|
@ -62,11 +62,11 @@ typedef struct dvb_string_conv
|
|||
} dvb_string_conv_t;
|
||||
|
||||
int dvb_get_string(char *dst, size_t dstlen, const uint8_t *src,
|
||||
const size_t srclen, char *dvb_default_charset,
|
||||
const size_t srclen, const char *dvb_charset,
|
||||
dvb_string_conv_t *conv);
|
||||
|
||||
int dvb_get_string_with_len(char *dst, size_t dstlen,
|
||||
const uint8_t *buf, size_t buflen, char *dvb_default_charset,
|
||||
const uint8_t *buf, size_t buflen, const char *dvb_charset,
|
||||
dvb_string_conv_t *conv);
|
||||
|
||||
#define bcdtoint(i) ((((i & 0xf0) >> 4) * 10) + (i & 0x0f))
|
||||
|
|
|
@ -186,12 +186,59 @@ dvb_transport_refresh(service_t *t)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
dvb_transport_save(service_t *t)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
htsmsg_add_u32(m, "service_id", t->s_dvb_service_id);
|
||||
htsmsg_add_u32(m, "pmt", t->s_pmt_pid);
|
||||
htsmsg_add_u32(m, "stype", t->s_servicetype);
|
||||
htsmsg_add_u32(m, "scrambled", t->s_scrambled);
|
||||
htsmsg_add_u32(m, "channel", t->s_channel_number);
|
||||
|
||||
if(t->s_provider != NULL)
|
||||
htsmsg_add_str(m, "provider", t->s_provider);
|
||||
|
||||
if(t->s_svcname != NULL)
|
||||
htsmsg_add_str(m, "servicename", t->s_svcname);
|
||||
|
||||
if(t->s_ch != NULL) {
|
||||
htsmsg_add_str(m, "channelname", t->s_ch->ch_name);
|
||||
htsmsg_add_u32(m, "mapped", 1);
|
||||
}
|
||||
|
||||
if(t->s_dvb_charset != NULL)
|
||||
htsmsg_add_str(m, "dvb_charset", t->s_dvb_charset);
|
||||
|
||||
htsmsg_add_u32(m, "dvb_eit_enable", t->s_dvb_eit_enable);
|
||||
|
||||
if(t->s_default_authority)
|
||||
htsmsg_add_str(m, "default_authority", t->s_default_authority);
|
||||
|
||||
pthread_mutex_lock(&t->s_stream_mutex);
|
||||
psi_save_service_settings(m, t);
|
||||
pthread_mutex_unlock(&t->s_stream_mutex);
|
||||
|
||||
hts_settings_save(m, "dvbtransports/%s/%s",
|
||||
t->s_dvb_mux_instance->tdmi_identifier,
|
||||
t->s_identifier);
|
||||
|
||||
htsmsg_destroy(m);
|
||||
dvb_transport_notify(t);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load config for the given mux
|
||||
*/
|
||||
void
|
||||
dvb_transport_load(th_dvb_mux_instance_t *tdmi)
|
||||
dvb_transport_load(th_dvb_mux_instance_t *tdmi, const char *tdmi_identifier)
|
||||
{
|
||||
htsmsg_t *l, *c;
|
||||
htsmsg_field_t *f;
|
||||
|
@ -199,10 +246,17 @@ dvb_transport_load(th_dvb_mux_instance_t *tdmi)
|
|||
const char *s;
|
||||
unsigned int u32;
|
||||
service_t *t;
|
||||
int old;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
if((l = hts_settings_load("dvbtransports/%s", tdmi->tdmi_identifier)) == NULL)
|
||||
/* HACK - use provided identifier to load config incase we've migrated
|
||||
* mux freq */
|
||||
if (!tdmi_identifier)
|
||||
tdmi_identifier = tdmi->tdmi_identifier;
|
||||
old = strcmp(tdmi_identifier, tdmi->tdmi_identifier);
|
||||
|
||||
if((l = hts_settings_load("dvbtransports/%s", tdmi_identifier)) == NULL)
|
||||
return;
|
||||
|
||||
HTSMSG_FOREACH(f, l) {
|
||||
|
@ -237,8 +291,9 @@ dvb_transport_load(th_dvb_mux_instance_t *tdmi)
|
|||
psi_load_service_settings(c, t);
|
||||
pthread_mutex_unlock(&t->s_stream_mutex);
|
||||
|
||||
s = htsmsg_get_str(c, "dvb_default_charset");
|
||||
t->s_dvb_default_charset = s ? strdup(s) : NULL;
|
||||
if (!(s = htsmsg_get_str(c, "dvb_charset")))
|
||||
s = htsmsg_get_str(c, "dvb_default_charset");
|
||||
t->s_dvb_charset = s ? strdup(s) : NULL;
|
||||
|
||||
s = htsmsg_get_str(c, "default_authority");
|
||||
t->s_default_authority = s ? strdup(s) : NULL;
|
||||
|
@ -253,57 +308,22 @@ dvb_transport_load(th_dvb_mux_instance_t *tdmi)
|
|||
|
||||
if(s && u32)
|
||||
service_map_channel(t, channel_find_by_name(s, 1, 0), 0);
|
||||
|
||||
/* HACK - force save for old config */
|
||||
if(old)
|
||||
dvb_transport_save(t);
|
||||
}
|
||||
|
||||
/* HACK - remove old settings */
|
||||
if(old) {
|
||||
HTSMSG_FOREACH(f, l)
|
||||
hts_settings_remove("dvbtransports/%s/%s", tdmi_identifier, f->hmf_name);
|
||||
hts_settings_remove("dvbtransports/%s", tdmi_identifier);
|
||||
}
|
||||
|
||||
htsmsg_destroy(l);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
dvb_transport_save(service_t *t)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
htsmsg_add_u32(m, "service_id", t->s_dvb_service_id);
|
||||
htsmsg_add_u32(m, "pmt", t->s_pmt_pid);
|
||||
htsmsg_add_u32(m, "stype", t->s_servicetype);
|
||||
htsmsg_add_u32(m, "scrambled", t->s_scrambled);
|
||||
htsmsg_add_u32(m, "channel", t->s_channel_number);
|
||||
|
||||
if(t->s_provider != NULL)
|
||||
htsmsg_add_str(m, "provider", t->s_provider);
|
||||
|
||||
if(t->s_svcname != NULL)
|
||||
htsmsg_add_str(m, "servicename", t->s_svcname);
|
||||
|
||||
if(t->s_ch != NULL) {
|
||||
htsmsg_add_str(m, "channelname", t->s_ch->ch_name);
|
||||
htsmsg_add_u32(m, "mapped", 1);
|
||||
}
|
||||
|
||||
if(t->s_dvb_default_charset != NULL)
|
||||
htsmsg_add_str(m, "dvb_default_charset", t->s_dvb_default_charset);
|
||||
|
||||
htsmsg_add_u32(m, "dvb_eit_enable", t->s_dvb_eit_enable);
|
||||
|
||||
if(t->s_default_authority)
|
||||
htsmsg_add_str(m, "default_authority", t->s_default_authority);
|
||||
|
||||
pthread_mutex_lock(&t->s_stream_mutex);
|
||||
psi_save_service_settings(m, t);
|
||||
pthread_mutex_unlock(&t->s_stream_mutex);
|
||||
|
||||
hts_settings_save(m, "dvbtransports/%s/%s",
|
||||
t->s_dvb_mux_instance->tdmi_identifier,
|
||||
t->s_identifier);
|
||||
|
||||
htsmsg_destroy(m);
|
||||
dvb_transport_notify(t);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called to get quality for the given transport
|
||||
|
@ -459,8 +479,8 @@ dvb_transport_build_msg(service_t *t)
|
|||
if(t->s_ch != NULL)
|
||||
htsmsg_add_str(m, "channelname", t->s_ch->ch_name);
|
||||
|
||||
if(t->s_dvb_default_charset != NULL)
|
||||
htsmsg_add_str(m, "dvb_default_charset", t->s_dvb_default_charset);
|
||||
if(t->s_dvb_charset != NULL)
|
||||
htsmsg_add_str(m, "dvb_charset", t->s_dvb_charset);
|
||||
|
||||
htsmsg_add_u32(m, "dvb_eit_enable", t->s_dvb_eit_enable);
|
||||
|
||||
|
|
|
@ -247,6 +247,8 @@ void dvr_config_delete(const char *name);
|
|||
|
||||
void dvr_entry_notify(dvr_entry_t *de);
|
||||
|
||||
void dvr_entry_save(dvr_entry_t *de);
|
||||
|
||||
const char *dvr_entry_status(dvr_entry_t *de);
|
||||
|
||||
const char *dvr_entry_schedstatus(dvr_entry_t *de);
|
||||
|
@ -280,6 +282,8 @@ void dvr_init(void);
|
|||
|
||||
void dvr_autorec_init(void);
|
||||
|
||||
void dvr_autorec_update(void);
|
||||
|
||||
void dvr_destroy_by_channel(channel_t *ch);
|
||||
|
||||
void dvr_rec_subscribe(dvr_entry_t *de);
|
||||
|
|
|
@ -38,12 +38,14 @@ dtable_t *autorec_dt;
|
|||
|
||||
TAILQ_HEAD(dvr_autorec_entry_queue, dvr_autorec_entry);
|
||||
|
||||
static int dvr_autorec_in_init = 0;
|
||||
|
||||
struct dvr_autorec_entry_queue autorec_entries;
|
||||
|
||||
static void dvr_autorec_changed(dvr_autorec_entry_t *dae);
|
||||
static void dvr_autorec_changed(dvr_autorec_entry_t *dae, int purge);
|
||||
|
||||
/**
|
||||
*
|
||||
* Unlink - and remove any unstarted
|
||||
*/
|
||||
static void
|
||||
dvr_autorec_purge_spawns(dvr_autorec_entry_t *dae)
|
||||
|
@ -53,7 +55,10 @@ dvr_autorec_purge_spawns(dvr_autorec_entry_t *dae)
|
|||
while((de = LIST_FIRST(&dae->dae_spawns)) != NULL) {
|
||||
LIST_REMOVE(de, de_autorec_link);
|
||||
de->de_autorec = NULL;
|
||||
dvr_entry_cancel(de);
|
||||
if (de->de_sched_state == DVR_SCHEDULED)
|
||||
dvr_entry_cancel(de);
|
||||
else
|
||||
dvr_entry_save(de);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,11 +82,14 @@ autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e)
|
|||
(dae->dae_title == NULL ||
|
||||
dae->dae_title[0] == '\0') &&
|
||||
dae->dae_brand == NULL &&
|
||||
dae->dae_season == NULL)
|
||||
dae->dae_season == NULL &&
|
||||
dae->dae_serieslink == NULL)
|
||||
return 0; // Avoid super wildcard match
|
||||
|
||||
// Note: we always test season first, though it will only be set
|
||||
// if configured
|
||||
if(dae->dae_serieslink)
|
||||
if (!e->serieslink || dae->dae_serieslink != e->serieslink) return 0;
|
||||
if(dae->dae_season)
|
||||
if (!e->episode->season || dae->dae_season != e->episode->season) return 0;
|
||||
if(dae->dae_brand)
|
||||
|
@ -199,9 +207,11 @@ autorec_entry_destroy(dvr_autorec_entry_t *dae)
|
|||
LIST_REMOVE(dae, dae_channel_tag_link);
|
||||
|
||||
if(dae->dae_brand)
|
||||
dae->dae_brand->putref((epg_object_t*)dae->dae_brand);
|
||||
dae->dae_brand->putref(dae->dae_brand);
|
||||
if(dae->dae_season)
|
||||
dae->dae_season->putref((epg_object_t*)dae->dae_season);
|
||||
dae->dae_season->putref(dae->dae_season);
|
||||
if(dae->dae_serieslink)
|
||||
dae->dae_serieslink->putref(dae->dae_serieslink);
|
||||
|
||||
|
||||
TAILQ_REMOVE(&autorec_entries, dae, dae_link);
|
||||
|
@ -417,7 +427,8 @@ autorec_record_update(void *opaque, const char *id, htsmsg_t *values,
|
|||
if (dae->dae_serieslink)
|
||||
dae->dae_serieslink->getref(dae->dae_serieslink);
|
||||
}
|
||||
dvr_autorec_changed(dae);
|
||||
if (!dvr_autorec_in_init)
|
||||
dvr_autorec_changed(dae, 1);
|
||||
|
||||
return autorec_record_build(dae);
|
||||
}
|
||||
|
@ -460,7 +471,18 @@ dvr_autorec_init(void)
|
|||
{
|
||||
TAILQ_INIT(&autorec_entries);
|
||||
autorec_dt = dtable_create(&autorec_dtc, "autorec", NULL);
|
||||
dvr_autorec_in_init = 1;
|
||||
dtable_load(autorec_dt);
|
||||
dvr_autorec_in_init = 0;
|
||||
}
|
||||
|
||||
void
|
||||
dvr_autorec_update(void)
|
||||
{
|
||||
dvr_autorec_entry_t *dae;
|
||||
TAILQ_FOREACH(dae, &autorec_entries, dae_link) {
|
||||
dvr_autorec_changed(dae, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -520,7 +542,7 @@ _dvr_autorec_add(const char *config_name,
|
|||
htsmsg_add_u32(m, "reload", 1);
|
||||
notify_by_msg("autorec", m);
|
||||
|
||||
dvr_autorec_changed(dae);
|
||||
dvr_autorec_changed(dae, 1);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -559,14 +581,10 @@ void
|
|||
dvr_autorec_check_event(epg_broadcast_t *e)
|
||||
{
|
||||
dvr_autorec_entry_t *dae;
|
||||
dvr_entry_t *existingde;
|
||||
|
||||
TAILQ_FOREACH(dae, &autorec_entries, dae_link)
|
||||
if(autorec_cmp(dae, e)) {
|
||||
existingde = dvr_entry_find_by_event_fuzzy(e);
|
||||
if (existingde == NULL)
|
||||
dvr_entry_create_by_autorec(e, dae);
|
||||
}
|
||||
if(autorec_cmp(dae, e))
|
||||
dvr_entry_create_by_autorec(e, dae);
|
||||
// Note: no longer updating event here as it will be done from EPG
|
||||
// anyway
|
||||
}
|
||||
|
@ -593,12 +611,13 @@ void dvr_autorec_check_serieslink(epg_serieslink_t *s)
|
|||
*
|
||||
*/
|
||||
static void
|
||||
dvr_autorec_changed(dvr_autorec_entry_t *dae)
|
||||
dvr_autorec_changed(dvr_autorec_entry_t *dae, int purge)
|
||||
{
|
||||
channel_t *ch;
|
||||
epg_broadcast_t *e;
|
||||
|
||||
dvr_autorec_purge_spawns(dae);
|
||||
if (purge)
|
||||
dvr_autorec_purge_spawns(dae);
|
||||
|
||||
RB_FOREACH(ch, &channel_name_tree, ch_name_link) {
|
||||
RB_FOREACH(e, &ch->ch_epg_schedule, sched_link) {
|
||||
|
|
|
@ -37,8 +37,6 @@ int dvr_iov_max;
|
|||
struct dvr_config_list dvrconfigs;
|
||||
struct dvr_entry_list dvrentries;
|
||||
|
||||
static void dvr_entry_save(dvr_entry_t *de);
|
||||
|
||||
static void dvr_timer_expire(void *aux);
|
||||
static void dvr_timer_start_recording(void *aux);
|
||||
|
||||
|
@ -258,19 +256,6 @@ static dvr_entry_t *_dvr_entry_create (
|
|||
if(de->de_start == start && de->de_sched_state != DVR_COMPLETED)
|
||||
return NULL;
|
||||
|
||||
/* Reject duplicate episodes (unless earlier) */
|
||||
if (e && cfg->dvr_dup_detect_episode) {
|
||||
de = dvr_entry_find_by_episode(e);
|
||||
if (de) {
|
||||
if (de->de_start > start) {
|
||||
dvr_event_replaced(de->de_bcast, e);
|
||||
return de;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
de = calloc(1, sizeof(dvr_entry_t));
|
||||
de->de_id = ++de_tally;
|
||||
|
||||
|
@ -586,7 +571,7 @@ dvr_db_load(void)
|
|||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
void
|
||||
dvr_entry_save(dvr_entry_t *de)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
|
@ -1050,6 +1035,7 @@ dvr_init(void)
|
|||
dvr_db_load();
|
||||
|
||||
dvr_autorec_init();
|
||||
dvr_autorec_update();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -205,6 +205,11 @@ pvr_generate_filename(dvr_entry_t *de, const streaming_start_t *ss)
|
|||
|
||||
snprintf(path, sizeof(path), "%s", cfg->dvr_storage);
|
||||
|
||||
/* Remove trailing slash */
|
||||
|
||||
if (path[strlen(path)-1] == '/')
|
||||
path[strlen(path)-1] = '\0';
|
||||
|
||||
/* Append per-day directory */
|
||||
|
||||
if(cfg->dvr_flags & DVR_DIR_PER_DAY) {
|
||||
|
@ -345,7 +350,7 @@ dvr_rec_start(dvr_entry_t *de, const streaming_start_t *ss)
|
|||
return;
|
||||
}
|
||||
|
||||
if(cfg->dvr_flags & DVR_TAG_FILES) {
|
||||
if(cfg->dvr_flags & DVR_TAG_FILES && de->de_bcast) {
|
||||
if(muxer_write_meta(de->de_mux, de->de_bcast)) {
|
||||
dvr_rec_fatal_error(de, "Unable to write meta data");
|
||||
return;
|
||||
|
@ -442,8 +447,8 @@ dvr_thread(void *aux)
|
|||
if(dispatch_clock > de->de_start - (60 * de->de_start_extra)) {
|
||||
dvr_rec_set_state(de, DVR_RS_RUNNING, 0);
|
||||
|
||||
if(!muxer_write_pkt(de->de_mux, sm->sm_data))
|
||||
sm->sm_data = NULL;
|
||||
muxer_write_pkt(de->de_mux, sm->sm_data);
|
||||
sm->sm_data = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -528,6 +533,10 @@ dvr_thread(void *aux)
|
|||
pthread_mutex_lock(&sq->sq_mutex);
|
||||
}
|
||||
pthread_mutex_unlock(&sq->sq_mutex);
|
||||
|
||||
if(de->de_mux)
|
||||
dvr_thread_epilog(de);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -801,6 +801,9 @@ mk_write_cues(mk_mux_t *mkm)
|
|||
mk_mux_t *mk_mux_create(void)
|
||||
{
|
||||
mk_mux_t *mkm = calloc(1, sizeof(struct mk_mux));
|
||||
|
||||
mkm->fd = -1;
|
||||
|
||||
return mkm;
|
||||
}
|
||||
|
||||
|
@ -899,8 +902,7 @@ mk_mux_write_pkt(mk_mux_t *mkm, struct th_pkt *pkt)
|
|||
mk_write_frame_i(mkm, t, pkt);
|
||||
}
|
||||
|
||||
if(!mkm->error)
|
||||
pkt_ref_dec(pkt);
|
||||
pkt_ref_dec(pkt);
|
||||
|
||||
return mkm->error;
|
||||
}
|
||||
|
|
21
src/epg.c
21
src/epg.c
|
@ -746,13 +746,13 @@ static htsmsg_t *epg_episode_num_serialize ( epg_episode_num_t *num )
|
|||
if (num->e_cnt)
|
||||
htsmsg_add_u32(m, "e_cnt", num->e_cnt);
|
||||
if (num->s_num)
|
||||
htsmsg_add_u32(m, "s_num", num->e_num);
|
||||
htsmsg_add_u32(m, "s_num", num->s_num);
|
||||
if (num->s_cnt)
|
||||
htsmsg_add_u32(m, "s_cnt", num->e_cnt);
|
||||
htsmsg_add_u32(m, "s_cnt", num->s_cnt);
|
||||
if (num->p_num)
|
||||
htsmsg_add_u32(m, "p_num", num->e_num);
|
||||
htsmsg_add_u32(m, "p_num", num->p_num);
|
||||
if (num->p_cnt)
|
||||
htsmsg_add_u32(m, "p_cnt", num->e_cnt);
|
||||
htsmsg_add_u32(m, "p_cnt", num->p_cnt);
|
||||
if (num->text)
|
||||
htsmsg_add_str(m, "text", num->text);
|
||||
return m;
|
||||
|
@ -990,6 +990,7 @@ int epg_episode_set_genre
|
|||
g2 = LIST_NEXT(g1, link);
|
||||
if (!epg_genre_list_contains(genre, g1, 0)) {
|
||||
LIST_REMOVE(g1, link);
|
||||
free(g1);
|
||||
save = 1;
|
||||
}
|
||||
g1 = g2;
|
||||
|
@ -1354,6 +1355,8 @@ static void _epg_channel_rem_broadcast
|
|||
{
|
||||
if (new) dvr_event_replaced(ebc, new);
|
||||
RB_REMOVE(&ch->ch_epg_schedule, ebc, sched_link);
|
||||
if (ch->ch_epg_now == ebc) ch->ch_epg_now = NULL;
|
||||
if (ch->ch_epg_next == ebc) ch->ch_epg_next = NULL;
|
||||
_epg_object_putref(ebc);
|
||||
}
|
||||
|
||||
|
@ -1468,7 +1471,6 @@ static epg_broadcast_t *_epg_channel_add_broadcast
|
|||
/* Remove overlapping (before) */
|
||||
while ( (ebc = RB_PREV(ret, sched_link)) != NULL ) {
|
||||
if ( ebc->stop <= ret->start ) break;
|
||||
if ( ch->ch_epg_now == ebc ) ch->ch_epg_now = NULL;
|
||||
_epg_channel_rem_broadcast(ch, ebc, ret);
|
||||
}
|
||||
|
||||
|
@ -1838,10 +1840,15 @@ epg_broadcast_t *epg_broadcast_deserialize
|
|||
if (!htsmsg_get_u32(m, "is_repeat", &u32))
|
||||
*save |= epg_broadcast_set_is_repeat(ebc, u32, NULL);
|
||||
|
||||
if ((ls = lang_str_deserialize(m, "summary")))
|
||||
if ((ls = lang_str_deserialize(m, "summary"))) {
|
||||
*save |= epg_broadcast_set_summary2(ebc, ls, NULL);
|
||||
if ((ls = lang_str_deserialize(m, "description")))
|
||||
lang_str_destroy(ls);
|
||||
}
|
||||
|
||||
if ((ls = lang_str_deserialize(m, "description"))) {
|
||||
*save |= epg_broadcast_set_description2(ebc, ls, NULL);
|
||||
lang_str_destroy(ls);
|
||||
}
|
||||
|
||||
/* Series link */
|
||||
if ((str = htsmsg_get_str(m, "serieslink")))
|
||||
|
|
|
@ -287,7 +287,7 @@ char *epggrab_module_grab_spawn ( void *m )
|
|||
/* Grab */
|
||||
outlen = spawn_and_store_stdout(mod->path, NULL, &outbuf);
|
||||
if ( outlen < 1 ) {
|
||||
tvhlog(LOG_ERR, "pyepg", "no output detected");
|
||||
tvhlog(LOG_ERR, mod->id, "no output detected");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -300,13 +300,14 @@ htsmsg_t *epggrab_module_trans_xml ( void *m, char *c )
|
|||
{
|
||||
htsmsg_t *ret;
|
||||
char errbuf[100];
|
||||
epggrab_module_t *mod = m;
|
||||
|
||||
if (!c) return NULL;
|
||||
|
||||
/* Extract */
|
||||
ret = htsmsg_xml_deserialize(c, errbuf, sizeof(errbuf));
|
||||
if (!ret)
|
||||
tvhlog(LOG_ERR, "pyepg", "htsmsg_xml_deserialize error %s", errbuf);
|
||||
tvhlog(LOG_ERR, mod->id, "htsmsg_xml_deserialize error %s", errbuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "epg.h"
|
||||
#include "epggrab.h"
|
||||
#include "epggrab/private.h"
|
||||
#include "dvb/dvb_charset.h"
|
||||
|
||||
/* ************************************************************************
|
||||
* Status handling
|
||||
|
@ -149,7 +150,7 @@ typedef struct eit_event
|
|||
lang_str_t *summary;
|
||||
lang_str_t *desc;
|
||||
|
||||
char *default_charset;
|
||||
const char *default_charset;
|
||||
|
||||
htsmsg_t *extra;
|
||||
|
||||
|
@ -200,7 +201,7 @@ static dvb_string_conv_t _eit_freesat_conv[2] = {
|
|||
static int _eit_get_string_with_len
|
||||
( epggrab_module_t *m,
|
||||
char *dst, size_t dstlen,
|
||||
const uint8_t *src, size_t srclen, char *charset )
|
||||
const uint8_t *src, size_t srclen, const char *charset )
|
||||
{
|
||||
dvb_string_conv_t *cptr = NULL;
|
||||
|
||||
|
@ -534,7 +535,15 @@ static int _eit_process_event
|
|||
|
||||
/* Process tags */
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.default_charset = svc->s_dvb_default_charset;
|
||||
ev.default_charset = svc->s_dvb_charset;
|
||||
|
||||
/* Override */
|
||||
if (!ev.default_charset) {
|
||||
ev.default_charset
|
||||
= dvb_charset_find(svc->s_dvb_mux_instance->tdmi_transport_stream_id,
|
||||
svc->s_dvb_service_id);
|
||||
}
|
||||
|
||||
while (dllen > 2) {
|
||||
int r;
|
||||
dtag = ptr[0];
|
||||
|
|
|
@ -233,6 +233,8 @@ static char *_opentv_parse_string
|
|||
int ok = 0;
|
||||
char *ret, *tmp;
|
||||
|
||||
if (len <= 0) return NULL;
|
||||
|
||||
// Note: unlikely decoded string will be longer (though its possible)
|
||||
ret = tmp = malloc(2*len);
|
||||
*ret = 0;
|
||||
|
@ -264,15 +266,17 @@ static int _opentv_parse_event_record
|
|||
if (rlen+2 <= len) {
|
||||
switch (rtag) {
|
||||
case 0xb5: // title
|
||||
ev->start = (((int)buf[2] << 9) | (buf[3] << 1))
|
||||
+ mjd;
|
||||
ev->stop = (((int)buf[4] << 9) | (buf[5] << 1))
|
||||
+ ev->start;
|
||||
ev->cat = buf[6];
|
||||
if (prov->genre)
|
||||
ev->cat = prov->genre->map[ev->cat];
|
||||
if (!ev->title)
|
||||
ev->title = _opentv_parse_string(prov, buf+9, rlen-7);
|
||||
if (rlen >= 7) {
|
||||
ev->start = (((int)buf[2] << 9) | (buf[3] << 1))
|
||||
+ mjd;
|
||||
ev->stop = (((int)buf[4] << 9) | (buf[5] << 1))
|
||||
+ ev->start;
|
||||
ev->cat = buf[6];
|
||||
if (prov->genre)
|
||||
ev->cat = prov->genre->map[ev->cat];
|
||||
if (!ev->title)
|
||||
ev->title = _opentv_parse_string(prov, buf+9, rlen-7);
|
||||
}
|
||||
break;
|
||||
case 0xb9: // summary
|
||||
if (!ev->summary)
|
||||
|
|
|
@ -59,28 +59,46 @@ static epggrab_channel_t *_xmltv_channel_find
|
|||
/**
|
||||
*
|
||||
*/
|
||||
static time_t _xmltv_str2time(const char *str)
|
||||
static time_t _xmltv_str2time(const char *in)
|
||||
{
|
||||
struct tm tm;
|
||||
int tz, r;
|
||||
int tz = 0, r;
|
||||
int sp = 0;
|
||||
char str[32];
|
||||
|
||||
memset(&tm, 0, sizeof(tm));
|
||||
strcpy(str, in);
|
||||
|
||||
r = sscanf(str, "%04d%02d%02d%02d%02d%02d %d",
|
||||
/* split tz */
|
||||
while (str[sp] && str[sp] != ' ')
|
||||
sp++;
|
||||
|
||||
/* parse tz */
|
||||
// TODO: handle string TZ?
|
||||
if (str[sp]) {
|
||||
sscanf(str+sp+1, "%d", &tz);
|
||||
tz = (tz % 100) + (tz / 100) * 3600; // Convert from HHMM to seconds
|
||||
str[sp] = 0;
|
||||
sp = 1;
|
||||
} else {
|
||||
sp = 0;
|
||||
}
|
||||
|
||||
/* parse time */
|
||||
r = sscanf(str, "%04d%02d%02d%02d%02d%02d",
|
||||
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
|
||||
&tm.tm_hour, &tm.tm_min, &tm.tm_sec,
|
||||
&tz);
|
||||
&tm.tm_hour, &tm.tm_min, &tm.tm_sec);
|
||||
|
||||
/* adjust */
|
||||
tm.tm_mon -= 1;
|
||||
tm.tm_year -= 1900;
|
||||
tm.tm_isdst = -1;
|
||||
|
||||
tz = (tz % 100) + (tz / 100) * 60; // Convert from HHMM to minutes
|
||||
|
||||
if(r == 6) {
|
||||
return mktime(&tm);
|
||||
} else if(r == 7) {
|
||||
return timegm(&tm) - tz * 60;
|
||||
if (r >= 5) {
|
||||
if(sp)
|
||||
return timegm(&tm) - tz;
|
||||
else
|
||||
return mktime(&tm);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
@ -190,7 +208,10 @@ static void parse_xmltv_dd_progid
|
|||
snprintf(buf, sizeof(buf)-1, "ddprogid://%s/%s", mod->id, s);
|
||||
|
||||
/* SH - series without episode id so ignore */
|
||||
if (strncmp("SH", s, 2)) *uri = strdup(buf);
|
||||
if (strncmp("SH", s, 2))
|
||||
*uri = strdup(buf);
|
||||
else
|
||||
*suri = strdup(buf);
|
||||
|
||||
/* Episode */
|
||||
if (!strncmp("EP", s, 2)) {
|
||||
|
@ -613,7 +634,7 @@ static void _xmltv_load_grabbers ( void )
|
|||
size_t i, p, n;
|
||||
char *outbuf;
|
||||
char name[1000];
|
||||
char *tmp, *path;
|
||||
char *tmp, *tmp2 = NULL, *path;
|
||||
|
||||
/* Load data */
|
||||
outlen = spawn_and_store_stdout(XMLTV_FIND, NULL, &outbuf);
|
||||
|
@ -647,7 +668,7 @@ static void _xmltv_load_grabbers ( void )
|
|||
NULL
|
||||
};
|
||||
path = strdup(tmp);
|
||||
tmp = strtok(path, ":");
|
||||
tmp = strtok_r(path, ":", &tmp2);
|
||||
while (tmp) {
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
|
@ -656,7 +677,8 @@ static void _xmltv_load_grabbers ( void )
|
|||
while ((de = readdir(dir))) {
|
||||
if (strstr(de->d_name, XMLTV_GRAB) != de->d_name) continue;
|
||||
snprintf(bin, sizeof(bin), "%s/%s", tmp, de->d_name);
|
||||
if (lstat(bin, &st)) continue;
|
||||
if (epggrab_module_find_by_id(bin)) continue;
|
||||
if (stat(bin, &st)) continue;
|
||||
if (!(st.st_mode & S_IEXEC)) continue;
|
||||
if (!S_ISREG(st.st_mode)) continue;
|
||||
if ((outlen = spawn_and_store_stdout(bin, argv, &outbuf)) > 0) {
|
||||
|
@ -667,9 +689,9 @@ static void _xmltv_load_grabbers ( void )
|
|||
free(outbuf);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
closedir(dir);
|
||||
tmp = strtok(NULL, ":");
|
||||
tmp = strtok_r(NULL, ":", &tmp2);
|
||||
}
|
||||
free(path);
|
||||
}
|
||||
|
|
|
@ -136,6 +136,7 @@ void epggrab_ota_load ( void )
|
|||
if ((l = htsmsg_get_list_by_field(f)))
|
||||
_epggrab_ota_load_one((epggrab_module_ota_t*)mod, l);
|
||||
}
|
||||
htsmsg_destroy(m);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,6 +172,7 @@ void epggrab_ota_save ( void )
|
|||
}
|
||||
|
||||
hts_settings_save(m, "epggrab/otamux");
|
||||
htsmsg_destroy(m);
|
||||
}
|
||||
|
||||
/* **************************************************************************
|
||||
|
|
|
@ -214,12 +214,13 @@ fb_dir *fb_opendir ( const char *path )
|
|||
|
||||
/* Bundle */
|
||||
#if ENABLE_BUNDLE
|
||||
char *tmp1 = strdup(path);
|
||||
char *tmp2 = strtok(tmp1, "/");
|
||||
char *tmp1, *tmp2, *tmp3 = NULL;
|
||||
tmp1 = strdup(path);
|
||||
tmp2 = strtok_r(tmp1, "/", &tmp3);
|
||||
filebundle_entry_t *fb = filebundle_root;
|
||||
while (fb && tmp2) {
|
||||
if (fb->type == FB_DIR && !strcmp(fb->name, tmp2)) {
|
||||
tmp2 = strtok(NULL, "/");
|
||||
tmp2 = strtok_r(NULL, "/", &tmp3);
|
||||
if (tmp2) fb = fb->d.child;
|
||||
} else {
|
||||
fb = fb->next;
|
||||
|
|
146
src/htsp.c
146
src/htsp.c
|
@ -467,7 +467,8 @@ htsp_build_dvrentry(dvr_entry_t *de, const char *method)
|
|||
*/
|
||||
static htsmsg_t *
|
||||
htsp_build_event
|
||||
(epg_broadcast_t *e, const char *method, const char *lang, time_t update )
|
||||
(epg_broadcast_t *e, const char *method, const char *lang, time_t update,
|
||||
htsp_connection_t *htsp )
|
||||
{
|
||||
htsmsg_t *out;
|
||||
epg_broadcast_t *n;
|
||||
|
@ -501,11 +502,11 @@ htsp_build_event
|
|||
htsmsg_add_s64(out, "stop", e->stop);
|
||||
if ((str = epg_broadcast_get_title(e, lang)))
|
||||
htsmsg_add_str(out, "title", str);
|
||||
if ((str = epg_broadcast_get_description(e, lang)))
|
||||
if ((str = epg_broadcast_get_description(e, lang))) {
|
||||
htsmsg_add_str(out, "description", str);
|
||||
if ((str = epg_broadcast_get_description(e, lang)))
|
||||
if ((str = epg_broadcast_get_summary(e, lang)))
|
||||
htsmsg_add_str(out, "summary", str);
|
||||
else if((str = epg_broadcast_get_summary(e, lang)))
|
||||
} else if((str = epg_broadcast_get_summary(e, lang)))
|
||||
htsmsg_add_str(out, "description", str);
|
||||
if (e->serieslink)
|
||||
htsmsg_add_u32(out, "serieslinkId", e->serieslink->id);
|
||||
|
@ -516,8 +517,11 @@ htsp_build_event
|
|||
htsmsg_add_u32(out, "brandId", ee->brand->id);
|
||||
if (ee->season)
|
||||
htsmsg_add_u32(out, "seasonId", ee->season->id);
|
||||
if((g = LIST_FIRST(&ee->genre)))
|
||||
htsmsg_add_u32(out, "contentType", g->code);
|
||||
if((g = LIST_FIRST(&ee->genre))) {
|
||||
uint32_t code = g->code;
|
||||
if (htsp->htsp_version < 6) code = (code >> 4) & 0xF;
|
||||
htsmsg_add_u32(out, "contentType", code);
|
||||
}
|
||||
if (ee->age_rating)
|
||||
htsmsg_add_u32(out, "ageRating", ee->age_rating);
|
||||
if (ee->star_rating)
|
||||
|
@ -650,35 +654,6 @@ htsp_method_getSysTime(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request a ticket for a http url pointing to a channel or dvr
|
||||
*/
|
||||
static htsmsg_t *
|
||||
htsp_method_getTicket(htsp_connection_t *htsp, htsmsg_t *in)
|
||||
{
|
||||
htsmsg_t *out;
|
||||
uint32_t id;
|
||||
char path[255];
|
||||
const char *ticket = NULL;
|
||||
|
||||
if(!htsmsg_get_u32(in, "channelId", &id)) {
|
||||
snprintf(path, sizeof(path), "/stream/channelid/%d", id);
|
||||
ticket = access_ticket_create(path);
|
||||
} else if(!htsmsg_get_u32(in, "dvrId", &id)) {
|
||||
snprintf(path, sizeof(path), "/dvrfile/%d", id);
|
||||
ticket = access_ticket_create(path);
|
||||
} else {
|
||||
return htsp_error("Missing argument 'channelId' or 'dvrId'");
|
||||
}
|
||||
|
||||
out = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_str(out, "path", path);
|
||||
htsmsg_add_str(out, "ticket", ticket);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch the HTSP connection into async mode
|
||||
*/
|
||||
|
@ -735,7 +710,7 @@ htsp_method_async(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
RB_FOREACH(ch, &channel_name_tree, ch_name_link)
|
||||
RB_FOREACH(ebc, &ch->ch_epg_schedule, sched_link) {
|
||||
if (epgMaxTime && ebc->start > epgMaxTime) break;
|
||||
htsmsg_t *e = htsp_build_event(ebc, "eventAdd", lang, lastUpdate);
|
||||
htsmsg_t *e = htsp_build_event(ebc, "eventAdd", lang, lastUpdate, htsp);
|
||||
if (e) htsp_send_message(htsp, e, NULL);
|
||||
}
|
||||
}
|
||||
|
@ -768,7 +743,7 @@ htsp_method_getEvent(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
if((e = epg_broadcast_find_by_id(eventId, NULL)) == NULL)
|
||||
return htsp_error("Event does not exist");
|
||||
|
||||
return htsp_build_event(e, NULL, lang, 0);
|
||||
return htsp_build_event(e, NULL, lang, 0, htsp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -807,7 +782,7 @@ htsp_method_getEvents(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
events = htsmsg_create_list();
|
||||
while (e) {
|
||||
if (maxTime && e->start > maxTime) break;
|
||||
htsmsg_add_msg(events, NULL, htsp_build_event(e, NULL, lang, 0));
|
||||
htsmsg_add_msg(events, NULL, htsp_build_event(e, NULL, lang, 0, htsp));
|
||||
if (numFollowing == 1) break;
|
||||
if (numFollowing) numFollowing--;
|
||||
e = epg_broadcast_get_next(e);
|
||||
|
@ -820,7 +795,7 @@ htsp_method_getEvents(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
int num = numFollowing;
|
||||
RB_FOREACH(e, &ch->ch_epg_schedule, sched_link) {
|
||||
if (maxTime && e->start > maxTime) break;
|
||||
htsmsg_add_msg(events, NULL, htsp_build_event(e, NULL, lang, 0));
|
||||
htsmsg_add_msg(events, NULL, htsp_build_event(e, NULL, lang, 0, htsp));
|
||||
if (num == 1) break;
|
||||
if (num) num--;
|
||||
}
|
||||
|
@ -862,6 +837,7 @@ htsp_method_epgQuery(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
if (!(ct = channel_tag_find_by_identifier(u32)))
|
||||
return htsp_error("Channel tag does not exist");
|
||||
if (!htsmsg_get_u32(in, "contentType", &u32)) {
|
||||
if(htsp->htsp_version < 6) u32 <<= 4;
|
||||
genre.code = u32;
|
||||
eg = &genre;
|
||||
}
|
||||
|
@ -878,7 +854,7 @@ htsp_method_epgQuery(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
for(i = 0; i < eqr.eqr_entries; ++i) {
|
||||
if (full)
|
||||
htsmsg_add_msg(array, NULL,
|
||||
htsp_build_event(eqr.eqr_array[i], NULL, lang, 0));
|
||||
htsp_build_event(eqr.eqr_array[i], NULL, lang, 0, htsp));
|
||||
else
|
||||
htsmsg_add_u32(array, NULL, eqr.eqr_array[i]->id);
|
||||
}
|
||||
|
@ -1088,6 +1064,35 @@ htsp_method_deleteDvrEntry(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request a ticket for a http url pointing to a channel or dvr
|
||||
*/
|
||||
static htsmsg_t *
|
||||
htsp_method_getTicket(htsp_connection_t *htsp, htsmsg_t *in)
|
||||
{
|
||||
htsmsg_t *out;
|
||||
uint32_t id;
|
||||
char path[255];
|
||||
const char *ticket = NULL;
|
||||
|
||||
if(!htsmsg_get_u32(in, "channelId", &id)) {
|
||||
snprintf(path, sizeof(path), "/stream/channelid/%d", id);
|
||||
ticket = access_ticket_create(path);
|
||||
} else if(!htsmsg_get_u32(in, "dvrId", &id)) {
|
||||
snprintf(path, sizeof(path), "/dvrfile/%d", id);
|
||||
ticket = access_ticket_create(path);
|
||||
} else {
|
||||
return htsp_error("Missing argument 'channelId' or 'dvrId'");
|
||||
}
|
||||
|
||||
out = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_str(out, "path", path);
|
||||
htsmsg_add_str(out, "ticket", ticket);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request subscription for a channel
|
||||
*/
|
||||
|
@ -1200,7 +1205,6 @@ struct {
|
|||
{ "authenticate", htsp_method_authenticate, ACCESS_ANONYMOUS},
|
||||
{ "getDiskSpace", htsp_method_getDiskSpace, ACCESS_STREAMING},
|
||||
{ "getSysTime", htsp_method_getSysTime, ACCESS_STREAMING},
|
||||
{ "getTicket", htsp_method_getTicket, ACCESS_STREAMING},
|
||||
{ "enableAsyncMetadata", htsp_method_async, ACCESS_STREAMING},
|
||||
{ "getEvent", htsp_method_getEvent, ACCESS_STREAMING},
|
||||
{ "getEvents", htsp_method_getEvents, ACCESS_STREAMING},
|
||||
|
@ -1210,6 +1214,7 @@ struct {
|
|||
{ "updateDvrEntry", htsp_method_updateDvrEntry, ACCESS_RECORDER},
|
||||
{ "cancelDvrEntry", htsp_method_cancelDvrEntry, ACCESS_RECORDER},
|
||||
{ "deleteDvrEntry", htsp_method_deleteDvrEntry, ACCESS_RECORDER},
|
||||
{ "getTicket", htsp_method_getTicket, ACCESS_STREAMING},
|
||||
{ "subscribe", htsp_method_subscribe, ACCESS_STREAMING},
|
||||
{ "unsubscribe", htsp_method_unsubscribe, ACCESS_STREAMING},
|
||||
{ "subscriptionChangeWeight", htsp_method_change_weight, ACCESS_STREAMING},
|
||||
|
@ -1422,24 +1427,30 @@ htsp_write_scheduler(void *aux)
|
|||
|
||||
r = htsmsg_binary_serialize(hm->hm_msg, &dptr, &dlen, INT32_MAX);
|
||||
|
||||
#if 0
|
||||
if(hm->hm_pktref) {
|
||||
usleep(hm->hm_payloadsize * 3);
|
||||
}
|
||||
#endif
|
||||
htsp_msg_destroy(hm);
|
||||
|
||||
/* ignore return value */
|
||||
r = write(htsp->htsp_fd, dptr, dlen);
|
||||
if(r != dlen)
|
||||
tvhlog(LOG_INFO, "htsp", "%s: Write error -- %s",
|
||||
htsp->htsp_logname, strerror(errno));
|
||||
free(dptr);
|
||||
|
||||
void *freeme = dptr;
|
||||
|
||||
while(dlen > 0) {
|
||||
r = write(htsp->htsp_fd, dptr, dlen);
|
||||
if(r < 1) {
|
||||
tvhlog(LOG_INFO, "htsp", "%s: Write error -- %s",
|
||||
htsp->htsp_logname, strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
dptr += r;
|
||||
dlen -= r;
|
||||
}
|
||||
|
||||
free(freeme);
|
||||
pthread_mutex_lock(&htsp->htsp_out_mutex);
|
||||
if(r != dlen)
|
||||
if(dlen)
|
||||
break;
|
||||
}
|
||||
// Shutdown socket to make receive thread terminate entire HTSP connection
|
||||
|
||||
shutdown(htsp->htsp_fd, SHUT_RDWR);
|
||||
pthread_mutex_unlock(&htsp->htsp_out_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1500,17 +1511,28 @@ htsp_serve(int fd, void *opaque, struct sockaddr_in *source,
|
|||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
free(htsp.htsp_logname);
|
||||
free(htsp.htsp_peername);
|
||||
free(htsp.htsp_username);
|
||||
free(htsp.htsp_clientname);
|
||||
|
||||
pthread_mutex_lock(&htsp.htsp_out_mutex);
|
||||
htsp.htsp_writer_run = 0;
|
||||
pthread_cond_signal(&htsp.htsp_out_cond);
|
||||
pthread_mutex_unlock(&htsp.htsp_out_mutex);
|
||||
|
||||
pthread_join(htsp.htsp_writer_thread, NULL);
|
||||
|
||||
free(htsp.htsp_logname);
|
||||
free(htsp.htsp_peername);
|
||||
free(htsp.htsp_username);
|
||||
free(htsp.htsp_clientname);
|
||||
|
||||
htsp_msg_q_t *hmq;
|
||||
|
||||
TAILQ_FOREACH(hmq, &htsp.htsp_active_output_queues, hmq_link) {
|
||||
htsp_msg_t *hm;
|
||||
while((hm = TAILQ_FIRST(&hmq->hmq_q)) != NULL) {
|
||||
TAILQ_REMOVE(&hmq->hmq_q, hm, hm_link);
|
||||
htsp_msg_destroy(hm);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
@ -1673,7 +1695,7 @@ htsp_event_add(epg_broadcast_t *ebc)
|
|||
htsmsg_t *m;
|
||||
LIST_FOREACH(htsp, &htsp_async_connections, htsp_async_link) {
|
||||
if (!(htsp->htsp_async_mode & HTSP_ASYNC_EPG)) continue;
|
||||
m = htsp_build_event(ebc, "eventAdd", htsp->htsp_language, 0);
|
||||
m = htsp_build_event(ebc, "eventAdd", htsp->htsp_language, 0, htsp);
|
||||
htsp_send_message(htsp, m, NULL);
|
||||
}
|
||||
}
|
||||
|
@ -1688,7 +1710,7 @@ htsp_event_update(epg_broadcast_t *ebc)
|
|||
htsmsg_t *m;
|
||||
LIST_FOREACH(htsp, &htsp_async_connections, htsp_async_link) {
|
||||
if (!(htsp->htsp_async_mode & HTSP_ASYNC_EPG)) continue;
|
||||
m = htsp_build_event(ebc, "eventUpdate", htsp->htsp_language, 0);
|
||||
m = htsp_build_event(ebc, "eventUpdate", htsp->htsp_language, 0, htsp);
|
||||
htsp_send_message(htsp, m, NULL);
|
||||
}
|
||||
}
|
||||
|
@ -1700,7 +1722,7 @@ void
|
|||
htsp_event_delete(epg_broadcast_t *ebc)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "method", "eventDeleted");
|
||||
htsmsg_add_str(m, "method", "eventDelete");
|
||||
htsmsg_add_u32(m, "eventId", ebc->id);
|
||||
htsp_async_send(m, HTSP_ASYNC_EPG);
|
||||
}
|
||||
|
|
50
src/main.c
50
src/main.c
|
@ -268,9 +268,11 @@ main(int argc, char **argv)
|
|||
int crash = 0;
|
||||
webui_port = 9981;
|
||||
htsp_port = 9982;
|
||||
gid_t gid;
|
||||
uid_t uid;
|
||||
|
||||
/* Get current directory */
|
||||
tvheadend_cwd = dirname(dirname(strdup(argv[0])));
|
||||
tvheadend_cwd = dirname(dirname(tvh_strdupa(argv[0])));
|
||||
|
||||
/* Set locale */
|
||||
setlocale(LC_ALL, "");
|
||||
|
@ -346,34 +348,52 @@ main(int argc, char **argv)
|
|||
|
||||
signal(SIGPIPE, handle_sigpipe);
|
||||
|
||||
log_stderr = 1;
|
||||
log_decorate = isatty(2);
|
||||
|
||||
if(forkaway) {
|
||||
grp = getgrnam(groupnam ?: "video");
|
||||
pw = usernam ? getpwnam(usernam) : NULL;
|
||||
|
||||
if(daemon(0, 0)) {
|
||||
exit(2);
|
||||
}
|
||||
pidfile = fopen(pidpath, "w+");
|
||||
if(pidfile != NULL) {
|
||||
fprintf(pidfile, "%d\n", getpid());
|
||||
fclose(pidfile);
|
||||
}
|
||||
|
||||
if(grp != NULL) {
|
||||
setgid(grp->gr_gid);
|
||||
gid = grp->gr_gid;
|
||||
} else {
|
||||
setgid(1);
|
||||
gid = 1;
|
||||
}
|
||||
|
||||
if (pw != NULL) {
|
||||
gid_t glist[10];
|
||||
int gnum = get_user_groups(pw, glist, 10);
|
||||
setgroups(gnum, glist);
|
||||
setuid(pw->pw_uid);
|
||||
if (getuid() != pw->pw_uid) {
|
||||
gid_t glist[10];
|
||||
int gnum;
|
||||
gnum = get_user_groups(pw, glist, 10);
|
||||
if (setgroups(gnum, glist)) {
|
||||
tvhlog(LOG_ALERT, "START", "setgroups() failed, do you have permission?");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
uid = pw->pw_uid;
|
||||
homedir = pw->pw_dir;
|
||||
setenv("HOME", homedir, 1);
|
||||
} else {
|
||||
setuid(1);
|
||||
uid = 1;
|
||||
}
|
||||
if ((getgid() != gid) && setgid(gid)) {
|
||||
tvhlog(LOG_ALERT, "START", "setgid() failed, do you have permission?");
|
||||
return 1;
|
||||
}
|
||||
if ((getuid() != uid) && setuid(uid)) {
|
||||
tvhlog(LOG_ALERT, "START", "setuid() failed, do you have permission?");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(daemon(0, 0)) {
|
||||
exit(2);
|
||||
}
|
||||
if(pidfile != NULL) {
|
||||
fprintf(pidfile, "%d\n", getpid());
|
||||
fclose(pidfile);
|
||||
}
|
||||
|
||||
umask(0);
|
||||
|
|
|
@ -295,12 +295,12 @@ muxer_write_meta(muxer_t *m, struct epg_broadcast *eb)
|
|||
* sanity wrapper arround m_write_pkt()
|
||||
*/
|
||||
int
|
||||
muxer_write_pkt(muxer_t *m, struct th_pkt *pkt)
|
||||
muxer_write_pkt(muxer_t *m, void *data)
|
||||
{
|
||||
if(!m || !pkt)
|
||||
if(!m || !data)
|
||||
return -1;
|
||||
|
||||
return m->m_write_pkt(m, pkt);
|
||||
return m->m_write_pkt(m, data);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ typedef struct muxer {
|
|||
int (*m_close) (struct muxer *); // Close the muxer
|
||||
void (*m_destroy) (struct muxer *); // Free the memory
|
||||
int (*m_write_meta) (struct muxer *, struct epg_broadcast *); // Append epg data
|
||||
int (*m_write_pkt) (struct muxer *, struct th_pkt *); // Append a media packet
|
||||
int (*m_write_pkt) (struct muxer *, void *); // Append a media packet
|
||||
|
||||
int m_errors; // Number of errors
|
||||
muxer_container_type_t m_container; // The type of the container
|
||||
|
@ -68,7 +68,7 @@ int muxer_init (muxer_t *m, const struct streaming_start *ss, con
|
|||
int muxer_close (muxer_t *m);
|
||||
int muxer_destroy (muxer_t *m);
|
||||
int muxer_write_meta (muxer_t *m, struct epg_broadcast *eb);
|
||||
int muxer_write_pkt (muxer_t *m, struct th_pkt *pkt);
|
||||
int muxer_write_pkt (muxer_t *m, void *data);
|
||||
const char* muxer_mime (muxer_t *m, const struct streaming_start *ss);
|
||||
const char* muxer_suffix (muxer_t *m, const struct streaming_start *ss);
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include "psi.h"
|
||||
#include "muxer_pass.h"
|
||||
|
||||
#define TS_BUFFER_COUNT 100
|
||||
#define TS_INJECTION_RATE 1000
|
||||
|
||||
/*
|
||||
|
@ -49,7 +48,6 @@ typedef struct pass_muxer {
|
|||
char *pm_filename;
|
||||
|
||||
/* TS muxing */
|
||||
uint8_t *pm_buf;
|
||||
uint8_t *pm_pat;
|
||||
uint8_t *pm_pmt;
|
||||
uint16_t pm_pmt_pid;
|
||||
|
@ -194,7 +192,7 @@ pass_muxer_write(muxer_t *m, const void *ts, size_t len)
|
|||
* Write TS packets to the file descriptor
|
||||
*/
|
||||
static void
|
||||
pass_muxer_write_ts(muxer_t *m, struct th_pkt *pkt)
|
||||
pass_muxer_write_ts(muxer_t *m, pktbuf_t *pb)
|
||||
{
|
||||
pass_muxer_t *pm = (pass_muxer_t*)m;
|
||||
int rem;
|
||||
|
@ -209,13 +207,9 @@ pass_muxer_write_ts(muxer_t *m, struct th_pkt *pkt)
|
|||
pm->pm_ic++;
|
||||
}
|
||||
|
||||
// flush buffer
|
||||
rem = pm->pm_pc % TS_BUFFER_COUNT;
|
||||
if(pm->pm_pc && !rem)
|
||||
pass_muxer_write(m, pm->pm_buf, TS_BUFFER_COUNT * 188);
|
||||
pass_muxer_write(m, pb->pb_data, pb->pb_size);
|
||||
|
||||
memcpy(pm->pm_buf + rem * 188, pkt, 188);
|
||||
pm->pm_pc++;
|
||||
pm->pm_pc += (pb->pb_size / 188);
|
||||
}
|
||||
|
||||
|
||||
|
@ -223,21 +217,21 @@ pass_muxer_write_ts(muxer_t *m, struct th_pkt *pkt)
|
|||
* Write a packet directly to the file descriptor
|
||||
*/
|
||||
static int
|
||||
pass_muxer_write_pkt(muxer_t *m, struct th_pkt *pkt)
|
||||
pass_muxer_write_pkt(muxer_t *m, void *data)
|
||||
{
|
||||
pktbuf_t *pb = (pktbuf_t*)data;
|
||||
pass_muxer_t *pm = (pass_muxer_t*)m;
|
||||
|
||||
switch(pm->m_container) {
|
||||
case MC_MPEGTS:
|
||||
pass_muxer_write_ts(m, pkt);
|
||||
pass_muxer_write_ts(m, pb);
|
||||
break;
|
||||
default:
|
||||
//NOP
|
||||
break;
|
||||
}
|
||||
|
||||
if(!pm->pm_error)
|
||||
free(pkt);
|
||||
pktbuf_ref_dec(pb);
|
||||
|
||||
return pm->pm_error;
|
||||
}
|
||||
|
@ -290,9 +284,6 @@ pass_muxer_destroy(muxer_t *m)
|
|||
if(pm->pm_pat)
|
||||
free(pm->pm_pat);
|
||||
|
||||
if(pm->pm_buf)
|
||||
free(pm->pm_buf);
|
||||
|
||||
free(pm);
|
||||
}
|
||||
|
||||
|
@ -325,9 +316,10 @@ pass_muxer_create(service_t *s, muxer_container_type_t mc)
|
|||
pm->pm_pmt_pid = s->s_pmt_pid;
|
||||
pm->pm_pat = malloc(188);
|
||||
pm->pm_pmt = malloc(188);
|
||||
pm->pm_buf = malloc(188 * TS_BUFFER_COUNT);
|
||||
}
|
||||
|
||||
pm->pm_fd = -1;
|
||||
|
||||
return (muxer_t *)pm;
|
||||
}
|
||||
|
||||
|
|
|
@ -117,8 +117,9 @@ tvh_muxer_open_file(muxer_t *m, const char *filename)
|
|||
* Write a packet to the muxer
|
||||
*/
|
||||
static int
|
||||
tvh_muxer_write_pkt(muxer_t *m, struct th_pkt *pkt)
|
||||
tvh_muxer_write_pkt(muxer_t *m, void *data)
|
||||
{
|
||||
th_pkt_t *pkt = (th_pkt_t*)data;
|
||||
tvh_muxer_t *tm = (tvh_muxer_t*)m;
|
||||
|
||||
if(mk_mux_write_pkt(tm->tm_ref, pkt)) {
|
||||
|
|
14
src/muxes.c
14
src/muxes.c
|
@ -289,7 +289,10 @@ static void _muxes_load_file
|
|||
str++;
|
||||
}
|
||||
}
|
||||
if (!reg) return;
|
||||
if (!reg) {
|
||||
fb_close(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Network */
|
||||
str = buf;
|
||||
|
@ -338,19 +341,22 @@ static void _muxes_load_file
|
|||
*
|
||||
* Note: should we follow symlinks?
|
||||
*/
|
||||
static void _muxes_load_dir ( const char *path, const char *type )
|
||||
static void _muxes_load_dir
|
||||
( const char *path, const char *type, int lvl )
|
||||
{
|
||||
char p[256];
|
||||
fb_dir *dir;
|
||||
fb_dirent *de;
|
||||
|
||||
if (lvl >= 3) return;
|
||||
if (!(dir = fb_opendir(path))) return;
|
||||
lvl++;
|
||||
|
||||
while ((de = fb_readdir(dir))) {
|
||||
if (*de->name == '.') continue;
|
||||
if (de->type == FB_DIR) {
|
||||
snprintf(p, sizeof(p), "%s/%s", path, de->name);
|
||||
_muxes_load_dir(p, de->name);
|
||||
_muxes_load_dir(p, de->name, lvl+1);
|
||||
} else if (type) {
|
||||
_muxes_load_file(type, dir, de->name);
|
||||
}
|
||||
|
@ -371,5 +377,5 @@ void muxes_init ( void )
|
|||
#else
|
||||
path = "/usr/share/dvb";
|
||||
#endif
|
||||
_muxes_load_dir(path, NULL);
|
||||
_muxes_load_dir(path, NULL, 0);
|
||||
}
|
||||
|
|
|
@ -355,7 +355,7 @@ h264_decode_slice_header(elementary_stream_t *st, bitstream_t *bs, int *pkttype,
|
|||
int *duration, int *isfield)
|
||||
{
|
||||
h264_private_t *p;
|
||||
int slice_type, pps_id, sps_id;
|
||||
unsigned int slice_type, pps_id, sps_id;
|
||||
|
||||
if((p = st->es_priv) == NULL)
|
||||
return -1;
|
||||
|
|
|
@ -110,18 +110,21 @@ stream_clean(elementary_stream_t *st)
|
|||
st->es_global_data_len = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
service_stream_destroy(service_t *t, elementary_stream_t *st)
|
||||
service_stream_destroy(service_t *t, elementary_stream_t *es)
|
||||
{
|
||||
if(t->s_status == SERVICE_RUNNING)
|
||||
stream_clean(st);
|
||||
TAILQ_REMOVE(&t->s_components, st, es_link);
|
||||
free(st->es_nicename);
|
||||
free(st);
|
||||
stream_clean(es);
|
||||
|
||||
avgstat_flush(&es->es_rate);
|
||||
avgstat_flush(&es->es_cc_errors);
|
||||
|
||||
TAILQ_REMOVE(&t->s_components, es, es_link);
|
||||
free(es->es_nicename);
|
||||
free(es);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -364,6 +367,8 @@ service_find(channel_t *ch, unsigned int weight, const char *loginfo,
|
|||
/* First, try all services without stealing */
|
||||
for(i = off; i < cnt; i++) {
|
||||
t = vec[i];
|
||||
if(t->s_status == SERVICE_RUNNING)
|
||||
return t;
|
||||
if(t->s_quality_index(t) < 10) {
|
||||
if(loginfo != NULL) {
|
||||
tvhlog(LOG_NOTICE, "Service",
|
||||
|
@ -375,9 +380,6 @@ service_find(channel_t *ch, unsigned int weight, const char *loginfo,
|
|||
}
|
||||
tvhlog(LOG_DEBUG, "Service", "%s: Probing adapter \"%s\" without stealing for service \"%s\"",
|
||||
loginfo, service_adapter_nicename(t), service_nicename(t));
|
||||
|
||||
if(t->s_status == SERVICE_RUNNING)
|
||||
return t;
|
||||
if((r = service_start(t, 0, 0)) == 0)
|
||||
return t;
|
||||
if(loginfo != NULL)
|
||||
|
@ -486,17 +488,19 @@ service_destroy(service_t *t)
|
|||
free(t->s_identifier);
|
||||
free(t->s_svcname);
|
||||
free(t->s_provider);
|
||||
free(t->s_dvb_default_charset);
|
||||
free(t->s_dvb_charset);
|
||||
|
||||
while((st = TAILQ_FIRST(&t->s_components)) != NULL) {
|
||||
TAILQ_REMOVE(&t->s_components, st, es_link);
|
||||
free(st->es_nicename);
|
||||
free(st);
|
||||
}
|
||||
while((st = TAILQ_FIRST(&t->s_components)) != NULL)
|
||||
service_stream_destroy(t, st);
|
||||
|
||||
free(t->s_pat_section);
|
||||
free(t->s_pmt_section);
|
||||
|
||||
sbuf_free(&t->s_tsbuf);
|
||||
|
||||
avgstat_flush(&t->s_cc_errors);
|
||||
avgstat_flush(&t->s_rate);
|
||||
|
||||
service_unref(t);
|
||||
|
||||
if(ch != NULL) {
|
||||
|
@ -525,10 +529,12 @@ service_create(const char *identifier, int type, int source_type)
|
|||
t->s_refcount = 1;
|
||||
t->s_enabled = 1;
|
||||
t->s_pcr_last = PTS_UNSET;
|
||||
t->s_dvb_default_charset = NULL;
|
||||
t->s_dvb_charset = NULL;
|
||||
t->s_dvb_eit_enable = 1;
|
||||
TAILQ_INIT(&t->s_components);
|
||||
|
||||
sbuf_init(&t->s_tsbuf);
|
||||
|
||||
streaming_pad_init(&t->s_streaming_pad);
|
||||
|
||||
LIST_INSERT_HEAD(&servicehash[hash], t, s_hash_link);
|
||||
|
@ -703,15 +709,15 @@ service_map_channel(service_t *t, channel_t *ch, int save)
|
|||
*
|
||||
*/
|
||||
void
|
||||
service_set_dvb_default_charset(service_t *t, const char *dvb_default_charset)
|
||||
service_set_dvb_charset(service_t *t, const char *dvb_charset)
|
||||
{
|
||||
lock_assert(&global_lock);
|
||||
|
||||
if(t->s_dvb_default_charset != NULL && !strcmp(t->s_dvb_default_charset, dvb_default_charset))
|
||||
if(t->s_dvb_charset != NULL && !strcmp(t->s_dvb_charset, dvb_charset))
|
||||
return;
|
||||
|
||||
free(t->s_dvb_default_charset);
|
||||
t->s_dvb_default_charset = strdup(dvb_default_charset);
|
||||
free(t->s_dvb_charset);
|
||||
t->s_dvb_charset = strdup(dvb_charset);
|
||||
t->s_config_save(t);
|
||||
}
|
||||
|
||||
|
@ -1164,7 +1170,7 @@ service_is_primary_epg(service_t *svc)
|
|||
LIST_FOREACH(t, &svc->s_ch->ch_services, s_ch_link) {
|
||||
if (!t->s_dvb_mux_instance) continue;
|
||||
if (!t->s_enabled || !t->s_dvb_eit_enable) continue;
|
||||
if (!ret || dvb_extra_prio(t->s_dvb_mux_instance->tdmi_adapter) > dvb_extra_prio(ret->s_dvb_mux_instance->tdmi_adapter))
|
||||
if (!ret || service_get_prio(t) < service_get_prio(ret))
|
||||
ret = t;
|
||||
}
|
||||
return !ret ? 0 : (ret->s_dvb_service_id == svc->s_dvb_service_id);
|
||||
|
|
|
@ -447,6 +447,13 @@ typedef struct service {
|
|||
elementary_stream_t *s_video;
|
||||
elementary_stream_t *s_audio;
|
||||
|
||||
|
||||
/**
|
||||
* When a subscription request SMT_MPEGTS, chunk them togeather
|
||||
* in order to recude load.
|
||||
*/
|
||||
sbuf_t s_tsbuf;
|
||||
|
||||
/**
|
||||
* Average continuity errors
|
||||
*/
|
||||
|
@ -492,7 +499,7 @@ typedef struct service {
|
|||
* DVB default charset
|
||||
* used to overide the default ISO6937 per service
|
||||
*/
|
||||
char *s_dvb_default_charset;
|
||||
char *s_dvb_charset;
|
||||
|
||||
/**
|
||||
* Set if EIT grab is enabled for DVB service (the default).
|
||||
|
@ -584,7 +591,7 @@ int tss2errcode(int tss);
|
|||
|
||||
uint16_t service_get_encryption(service_t *t);
|
||||
|
||||
void service_set_dvb_default_charset(service_t *t, const char *dvb_default_charset);
|
||||
void service_set_dvb_charset(service_t *t, const char *dvb_charset);
|
||||
|
||||
void service_set_dvb_eit_enable(service_t *t, int dvb_eit_enable);
|
||||
|
||||
|
|
|
@ -200,11 +200,13 @@ hts_settings_load_one(const char *filename)
|
|||
mem = malloc(fb_size(fp)+1);
|
||||
n = fb_read(fp, mem, fb_size(fp));
|
||||
if (n >= 0) mem[n] = 0;
|
||||
fb_close(fp);
|
||||
|
||||
/* Decode */
|
||||
if(n == fb_size(fp))
|
||||
r = htsmsg_json_deserialize(mem);
|
||||
|
||||
/* Close */
|
||||
fb_close(fp);
|
||||
free(mem);
|
||||
|
||||
return r;
|
||||
|
@ -290,12 +292,18 @@ hts_settings_remove(const char *pathfmt, ...)
|
|||
{
|
||||
char fullpath[256];
|
||||
va_list ap;
|
||||
struct stat st;
|
||||
|
||||
va_start(ap, pathfmt);
|
||||
hts_settings_buildpath(fullpath, sizeof(fullpath),
|
||||
pathfmt, ap, settingspath);
|
||||
va_end(ap);
|
||||
unlink(fullpath);
|
||||
if (stat(fullpath, &st) == 0) {
|
||||
if (S_ISDIR(st.st_mode))
|
||||
rmdir(fullpath);
|
||||
else
|
||||
unlink(fullpath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -53,13 +53,13 @@ find_exec ( const char *name, char *out, size_t len )
|
|||
{
|
||||
int ret = 0;
|
||||
char bin[512];
|
||||
char *path, *tmp;
|
||||
char *path, *tmp, *tmp2 = NULL;
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
struct stat st;
|
||||
if (!(path = getenv("PATH"))) return 0;
|
||||
path = strdup(path);
|
||||
tmp = strtok(path, ":");
|
||||
tmp = strtok_r(path, ":", &tmp2);
|
||||
while (tmp && !ret) {
|
||||
if ((dir = opendir(tmp))) {
|
||||
while ((de = readdir(dir))) {
|
||||
|
@ -73,7 +73,7 @@ find_exec ( const char *name, char *out, size_t len )
|
|||
}
|
||||
closedir(dir);
|
||||
}
|
||||
tmp = strtok(NULL, ":");
|
||||
tmp = strtok_r(NULL, ":", &tmp2);
|
||||
}
|
||||
free(path);
|
||||
return ret;
|
||||
|
|
|
@ -197,8 +197,8 @@ streaming_msg_clone(streaming_message_t *src)
|
|||
break;
|
||||
|
||||
case SMT_MPEGTS:
|
||||
dst->sm_data = malloc(188);
|
||||
memcpy(dst->sm_data, src->sm_data, 188);
|
||||
pktbuf_ref_inc(src->sm_data);
|
||||
dst->sm_data = src->sm_data;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -256,10 +256,14 @@ streaming_msg_free(streaming_message_t *sm)
|
|||
break;
|
||||
|
||||
case SMT_SIGNAL_STATUS:
|
||||
case SMT_MPEGTS:
|
||||
free(sm->sm_data);
|
||||
break;
|
||||
|
||||
case SMT_MPEGTS:
|
||||
if(sm->sm_data)
|
||||
pktbuf_ref_dec(sm->sm_data);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
|
|
@ -75,9 +75,14 @@ subscription_link_service(th_subscription_t *s, service_t *t)
|
|||
|
||||
pthread_mutex_lock(&t->s_stream_mutex);
|
||||
|
||||
if(TAILQ_FIRST(&t->s_components) != NULL)
|
||||
if(TAILQ_FIRST(&t->s_components) != NULL) {
|
||||
|
||||
if(s->ths_start_message != NULL)
|
||||
streaming_msg_free(s->ths_start_message);
|
||||
|
||||
s->ths_start_message =
|
||||
streaming_msg_create_data(SMT_START, service_build_stream_start(t));
|
||||
}
|
||||
|
||||
// Link to service output
|
||||
streaming_target_connect(&t->s_streaming_pad, &s->ths_input);
|
||||
|
|
|
@ -40,6 +40,8 @@
|
|||
#include "parsers.h"
|
||||
#include "streaming.h"
|
||||
|
||||
#define TS_REMUX_BUFSIZE (188 * 100)
|
||||
|
||||
static void ts_remux(service_t *t, const uint8_t *tsb);
|
||||
|
||||
/**
|
||||
|
@ -281,15 +283,26 @@ ts_recv_packet2(service_t *t, const uint8_t *tsb)
|
|||
static void
|
||||
ts_remux(service_t *t, const uint8_t *src)
|
||||
{
|
||||
uint8_t tsb[188];
|
||||
memcpy(tsb, src, 188);
|
||||
|
||||
streaming_message_t sm;
|
||||
pktbuf_t *pb;
|
||||
sbuf_t *sb = &t->s_tsbuf;
|
||||
|
||||
sbuf_append(sb, src, 188);
|
||||
|
||||
if(sb->sb_ptr < TS_REMUX_BUFSIZE)
|
||||
return;
|
||||
|
||||
pb = pktbuf_alloc(sb->sb_data, sb->sb_ptr);
|
||||
|
||||
sm.sm_type = SMT_MPEGTS;
|
||||
sm.sm_data = tsb;
|
||||
sm.sm_data = pb;
|
||||
streaming_pad_deliver(&t->s_streaming_pad, &sm);
|
||||
|
||||
pktbuf_ref_dec(pb);
|
||||
|
||||
service_set_streaming_status_flags(t, TSS_PACKETS);
|
||||
|
||||
sbuf_reset(sb);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#include "buildversion.h"
|
||||
#include "config.h"
|
||||
|
||||
const char *tvheadend_version = BUILD_VERSION;
|
|
@ -190,8 +190,8 @@ page_about(http_connection_t *hc, const char *remain, void *opaque)
|
|||
"</div><br>"
|
||||
"© 2006 - 2012 Andreas \303\226man, et al.<br><br>"
|
||||
"<img src=\"docresources/tvheadendlogo.png\"><br>"
|
||||
"<a href=\"http://www.lonelycoder.com/hts\">"
|
||||
"http://www.lonelycoder.com/hts</a><br><br>"
|
||||
"<a href=\"http://www.lonelycoder.com/tvheadend\">"
|
||||
"http://www.lonelycoder.com/tvheadend</a><br><br>"
|
||||
"Based on software from "
|
||||
"<a target=\"_blank\" href=\"http://www.extjs.com/\">ExtJS</a>. "
|
||||
"Icons from "
|
||||
|
@ -199,6 +199,13 @@ page_about(http_connection_t *hc, const char *remain, void *opaque)
|
|||
"FamFamFam</a>"
|
||||
"<br><br>"
|
||||
"Build: %s"
|
||||
"<p>"
|
||||
"If you'd like to support the project, please consider a donation."
|
||||
"<br/>"
|
||||
"All proceeds are used to support server infrastructure and buy test "
|
||||
"equipment."
|
||||
"<br/>"
|
||||
"<a href='https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=andreas%%40lonelycoder%%2ecom&item_name=Donation%%20to%%20the%%20Tvheadend%%20project&currency_code=USD'><img src='https://www.paypal.com/en_US/i/btn/btn_donate_LG.gif' alt='' /></a>"
|
||||
"</center>",
|
||||
tvheadend_version,
|
||||
tvheadend_version);
|
||||
|
@ -343,7 +350,7 @@ extjs_channels_update(htsmsg_t *in)
|
|||
|
||||
if((s = htsmsg_get_str(c, "epggrabsrc")) != NULL) {
|
||||
char *tmp = strdup(s);
|
||||
char *sptr = NULL;
|
||||
char *sptr = NULL, *sptr2 = NULL;
|
||||
char *modecid = strtok_r(tmp, ",", &sptr);
|
||||
char *modid, *ecid;
|
||||
epggrab_module_t *mod;
|
||||
|
@ -368,8 +375,8 @@ extjs_channels_update(htsmsg_t *in)
|
|||
|
||||
/* Add new */
|
||||
while (modecid) {
|
||||
modid = strtok(modecid, "|");
|
||||
ecid = strtok(NULL, "|");
|
||||
modid = strtok_r(modecid, "|", &sptr2);
|
||||
ecid = strtok_r(NULL, "|", &sptr2);
|
||||
modecid = strtok_r(NULL, ",", &sptr);
|
||||
|
||||
if (!(mod = epggrab_module_find_by_id(modid)))
|
||||
|
@ -610,6 +617,7 @@ extjs_epggrab(http_connection_t *hc, const char *remain, void *opaque)
|
|||
if ( str ) save |= epggrab_enable_module_by_id(str, u32);
|
||||
}
|
||||
}
|
||||
htsmsg_destroy(array);
|
||||
}
|
||||
}
|
||||
if (save) epggrab_save();
|
||||
|
@ -1408,7 +1416,7 @@ service_update(htsmsg_t *in)
|
|||
uint32_t u32;
|
||||
const char *id;
|
||||
const char *chname;
|
||||
const char *dvb_default_charset;
|
||||
const char *dvb_charset;
|
||||
|
||||
TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
|
||||
if((c = htsmsg_get_map_by_field(f)) == NULL ||
|
||||
|
@ -1424,8 +1432,8 @@ service_update(htsmsg_t *in)
|
|||
if((chname = htsmsg_get_str(c, "channelname")) != NULL)
|
||||
service_map_channel(t, channel_find_by_name(chname, 1, 0), 1);
|
||||
|
||||
if((dvb_default_charset = htsmsg_get_str(c, "dvb_default_charset")) != NULL)
|
||||
service_set_dvb_default_charset(t, dvb_default_charset);
|
||||
if((dvb_charset = htsmsg_get_str(c, "dvb_charset")) != NULL)
|
||||
service_set_dvb_charset(t, dvb_charset);
|
||||
|
||||
if(!htsmsg_get_u32(c, "dvb_eit_enable", &u32))
|
||||
service_set_dvb_eit_enable(t, u32);
|
||||
|
@ -1510,8 +1518,8 @@ extjs_servicedetails(http_connection_t *hc,
|
|||
|
||||
htsmsg_add_msg(out, "streams", streams);
|
||||
|
||||
if(t->s_dvb_default_charset != NULL)
|
||||
htsmsg_add_str(out, "dvb_default_charset", t->s_dvb_default_charset);
|
||||
if(t->s_dvb_charset != NULL)
|
||||
htsmsg_add_str(out, "dvb_charset", t->s_dvb_charset);
|
||||
|
||||
htsmsg_add_u32(out, "dvb_eit_enable", t->s_dvb_eit_enable);
|
||||
|
||||
|
@ -1742,7 +1750,7 @@ extjs_service_update(htsmsg_t *in)
|
|||
uint32_t u32;
|
||||
const char *id;
|
||||
const char *chname;
|
||||
const char *dvb_default_charset;
|
||||
const char *dvb_charset;
|
||||
|
||||
TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
|
||||
if((c = htsmsg_get_map_by_field(f)) == NULL ||
|
||||
|
@ -1758,8 +1766,8 @@ extjs_service_update(htsmsg_t *in)
|
|||
if((chname = htsmsg_get_str(c, "channelname")) != NULL)
|
||||
service_map_channel(t, channel_find_by_name(chname, 1, 0), 1);
|
||||
|
||||
if((dvb_default_charset = htsmsg_get_str(c, "dvb_default_charset")) != NULL)
|
||||
service_set_dvb_default_charset(t, dvb_default_charset);
|
||||
if((dvb_charset = htsmsg_get_str(c, "dvb_charset")) != NULL)
|
||||
service_set_dvb_charset(t, dvb_charset);
|
||||
|
||||
if(!htsmsg_get_u32(c, "dvb_eit_enable", &u32))
|
||||
service_set_dvb_eit_enable(t, u32);
|
||||
|
|
|
@ -424,23 +424,23 @@ page_status(http_connection_t *hc,
|
|||
htsbuf_qprintf(hq,
|
||||
"<recording>"
|
||||
"<start>"
|
||||
"<date>%02d/%02d/%02d</date>"
|
||||
"<date>%d/%02d/%02d</date>"
|
||||
"<time>%02d:%02d</time>"
|
||||
"<unixtime>%"PRItime_t"</unixtime>"
|
||||
"<extra_start>%"PRItime_t"</extra_start>"
|
||||
"</start>"
|
||||
"<stop>"
|
||||
"<date>%02d/%02d/%02d</date>"
|
||||
"<date>%d/%02d/%02d</date>"
|
||||
"<time>%02d:%02d</time>"
|
||||
"<unixtime>%"PRItime_t"</unixtime>"
|
||||
"<extra_stop>%"PRItime_t"</extra_stop>"
|
||||
"</stop>"
|
||||
"<title>%s</title>",
|
||||
a.tm_year + 1900, a.tm_mon, a.tm_mday,
|
||||
a.tm_year + 1900, a.tm_mon + 1, a.tm_mday,
|
||||
a.tm_hour, a.tm_min,
|
||||
de->de_start,
|
||||
de->de_start_extra,
|
||||
b.tm_year+1900, b.tm_mon, b.tm_mday,
|
||||
b.tm_year+1900, b.tm_mon + 1, b.tm_mday,
|
||||
b.tm_hour, b.tm_min,
|
||||
de->de_stop,
|
||||
de->de_stop_extra,
|
||||
|
|
|
@ -314,7 +314,7 @@ tvheadend.chconf = function() {
|
|||
tooltop : 'Add a new channel',
|
||||
iconCls : 'add',
|
||||
text : 'Add channel',
|
||||
handler : addRecord,
|
||||
handler : addRecord
|
||||
});
|
||||
|
||||
var delBtn = new Ext.Toolbar.Button({
|
||||
|
|
|
@ -382,7 +382,7 @@ tvheadend.dvb_services = function(adapterId) {
|
|||
});
|
||||
|
||||
var eitColumn = new Ext.grid.CheckColumn({
|
||||
header : "EIT",
|
||||
header : "EPG",
|
||||
dataIndex : 'dvb_eit_enable',
|
||||
width : 45
|
||||
});
|
||||
|
@ -444,18 +444,18 @@ tvheadend.dvb_services = function(adapterId) {
|
|||
})
|
||||
},
|
||||
{
|
||||
header : "DVB default charset",
|
||||
dataIndex : 'dvb_default_charset',
|
||||
header : "DVB charset",
|
||||
dataIndex : 'dvb_charset',
|
||||
width : 200,
|
||||
renderer : function(value, metadata, record, row, col, store) {
|
||||
return value ? value
|
||||
: '<span class="tvh-grid-unset">ISO6937</span>';
|
||||
: '<span class="tvh-grid-unset">auto</span>';
|
||||
},
|
||||
editor : new fm.ComboBox({
|
||||
mode : 'local',
|
||||
store : new Ext.data.SimpleStore({
|
||||
fields : [ 'key', 'value' ],
|
||||
data : [ [ 'ISO6937', 'default' ], [ 'ISO6937', 'ISO6937' ],
|
||||
data : [ [ null, 'auto' ], [ 'ISO6937', 'ISO6937' ],
|
||||
[ 'ISO8859-1', 'ISO8859-1' ], [ 'ISO8859-2', 'ISO8859-2' ],
|
||||
[ 'ISO8859-3', 'ISO8859-3' ], [ 'ISO8859-4', 'ISO8859-4' ],
|
||||
[ 'ISO8859-5', 'ISO8859-5' ], [ 'ISO8859-6', 'ISO8859-6' ],
|
||||
|
@ -510,7 +510,7 @@ tvheadend.dvb_services = function(adapterId) {
|
|||
root : 'entries',
|
||||
fields : Ext.data.Record.create([ 'id', 'enabled', 'type', 'sid', 'pmt',
|
||||
'pcr', 'svcname', 'network', 'provider', 'mux', 'channelname',
|
||||
'dvb_default_charset', 'dvb_eit_enable' ]),
|
||||
'dvb_charset', 'dvb_eit_enable' ]),
|
||||
url : "dvb/services/" + adapterId,
|
||||
autoLoad : true,
|
||||
id : 'id',
|
||||
|
@ -1114,6 +1114,10 @@ tvheadend.dvb_adapter_general = function(adapterData, satConfStore) {
|
|||
fieldLabel : 'Skip service availability check when mapping',
|
||||
name : 'skip_checksubscr'
|
||||
}),
|
||||
new Ext.form.Checkbox({
|
||||
fieldLabel : 'Use SID as channel number during mapping',
|
||||
name : 'sidtochan'
|
||||
}),
|
||||
new Ext.form.Checkbox({
|
||||
fieldLabel : 'Monitor signal quality',
|
||||
name : 'qmon'
|
||||
|
@ -1132,7 +1136,7 @@ tvheadend.dvb_adapter_general = function(adapterData, satConfStore) {
|
|||
+ 'of diskspace. You have been warned');
|
||||
}
|
||||
}), {
|
||||
fieldLabel : 'NIT-o Network ID',
|
||||
fieldLabel : 'Original Network ID',
|
||||
name : 'nitoid',
|
||||
width : 50
|
||||
}, {
|
||||
|
@ -1158,11 +1162,6 @@ tvheadend.dvb_adapter_general = function(adapterData, satConfStore) {
|
|||
name : 'poweroff'
|
||||
});
|
||||
items.push(v);
|
||||
v = new Ext.form.Checkbox({
|
||||
fieldLabel : 'Use SID as channel number during mapping',
|
||||
name : 'sidtochan'
|
||||
}),
|
||||
items.push(v);
|
||||
}
|
||||
|
||||
var confform = new Ext.FormPanel({
|
||||
|
@ -1229,6 +1228,8 @@ tvheadend.dvb_adapter_general = function(adapterData, satConfStore) {
|
|||
var panel = new Ext.Panel({
|
||||
title : 'General',
|
||||
layout : 'column',
|
||||
autoScroll : true,
|
||||
autoHeight: true,
|
||||
items : [ toolpanel, confform, infoPanel ]
|
||||
});
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ tvheadend.dvrprio = new Ext.data.SimpleStore({
|
|||
tvheadend.containers = new Ext.data.SimpleStore({
|
||||
fields : [ 'identifier', 'name' ],
|
||||
id : 0,
|
||||
data : [ [ 'matroska', 'Matroska' ], [ 'pass', 'Pass-through' ] ]
|
||||
data : [ [ 'matroska', 'Matroska' ], [ 'pass', 'TS (Pass-through)' ] ]
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -748,9 +748,6 @@ tvheadend.dvrsettings = function() {
|
|||
}), new Ext.form.Checkbox({
|
||||
fieldLabel : 'Include channel name in filename',
|
||||
name : 'channelInTitle'
|
||||
}), new Ext.form.Checkbox({
|
||||
fieldLabel : 'Remove all unsafe characters from filename',
|
||||
name : 'cleanTitle'
|
||||
}), new Ext.form.Checkbox({
|
||||
fieldLabel : 'Include date in filename',
|
||||
name : 'dateInTitle'
|
||||
|
@ -760,6 +757,9 @@ tvheadend.dvrsettings = function() {
|
|||
}), new Ext.form.Checkbox({
|
||||
fieldLabel : 'Include episode in filename',
|
||||
name : 'episodeInTitle'
|
||||
}), new Ext.form.Checkbox({
|
||||
fieldLabel : 'Remove all unsafe characters from filename',
|
||||
name : 'cleanTitle'
|
||||
}), new Ext.form.Checkbox({
|
||||
fieldLabel : 'Replace whitespace in title with \'-\'',
|
||||
name : 'whitespaceInTitle'
|
||||
|
|
|
@ -185,15 +185,25 @@ tvheadend.epggrab = function() {
|
|||
});
|
||||
|
||||
/*
|
||||
* Simple fieldet
|
||||
* Simple fields
|
||||
*/
|
||||
var simplePanel = new Ext.form.FieldSet({
|
||||
title : 'Basic Config',
|
||||
width : 800,
|
||||
title : 'General Config',
|
||||
width : 700,
|
||||
autoHeight : true,
|
||||
collapsible : true,
|
||||
items : [ interval, internalModule, intervalValue, intervalUnit,
|
||||
channelRename, channelRenumber, channelReicon ]
|
||||
items : [ channelRename, channelRenumber, channelReicon ]
|
||||
});
|
||||
|
||||
/*
|
||||
* Internal grabber
|
||||
*/
|
||||
var internalPanel = new Ext.form.FieldSet({
|
||||
title : 'Internal Grabber',
|
||||
width : 700,
|
||||
autoHeight : true,
|
||||
collapsible : true,
|
||||
items : [ interval, internalModule, intervalValue, intervalUnit ]
|
||||
});
|
||||
|
||||
/* ****************************************************************
|
||||
|
@ -243,7 +253,7 @@ tvheadend.epggrab = function() {
|
|||
|
||||
var externalPanel = new Ext.form.FieldSet({
|
||||
title : 'External Interfaces',
|
||||
width : 800,
|
||||
width : 700,
|
||||
autoHeight : true,
|
||||
collapsible : true,
|
||||
collapsed : true,
|
||||
|
@ -287,8 +297,8 @@ tvheadend.epggrab = function() {
|
|||
});
|
||||
|
||||
var otaPanel = new Ext.form.FieldSet({
|
||||
title : 'OTA Interfaces',
|
||||
width : 800,
|
||||
title : 'Over-the-air Grabbers',
|
||||
width : 700,
|
||||
autoHeight : true,
|
||||
collapsible : true,
|
||||
collapsed : true,
|
||||
|
@ -325,7 +335,7 @@ tvheadend.epggrab = function() {
|
|||
layout : 'form',
|
||||
defaultType : 'textfield',
|
||||
autoHeight : true,
|
||||
items : [ simplePanel, externalPanel, otaPanel ],
|
||||
items : [ simplePanel, internalPanel, otaPanel, externalPanel ],
|
||||
tbar : [ saveButton, '->', helpButton ]
|
||||
});
|
||||
|
||||
|
@ -360,6 +370,7 @@ tvheadend.epggrab = function() {
|
|||
/* Hack to get display working */
|
||||
delay = new Ext.util.DelayedTask(function() {
|
||||
simplePanel.doLayout(false);
|
||||
internalPanel.doLayout(false);
|
||||
externalPanel.doLayout(false);
|
||||
otaPanel.doLayout(false);
|
||||
});
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
tvheadend.servicetypeStore = new Ext.data.JsonStore({
|
||||
root : 'entries',
|
||||
id : 'val',
|
||||
url : '/iptv/services',
|
||||
baseParams : {
|
||||
op : 'servicetypeList'
|
||||
},
|
||||
fields : [ 'val', 'str' ],
|
||||
autoLoad : true
|
||||
});
|
||||
|
||||
/**
|
||||
* IPTV service grid
|
||||
*/
|
||||
tvheadend.iptv = function(adapterId) {
|
||||
|
||||
var servicetypeStore = new Ext.data.JsonStore({
|
||||
root : 'entries',
|
||||
id : 'val',
|
||||
url : '/iptv/services',
|
||||
baseParams : {
|
||||
op : 'servicetypeList'
|
||||
},
|
||||
fields : [ 'val', 'str' ],
|
||||
autoLoad : false
|
||||
});
|
||||
|
||||
var fm = Ext.form;
|
||||
|
||||
var enabledColumn = new Ext.grid.CheckColumn({
|
||||
|
@ -113,10 +113,10 @@ tvheadend.iptv = function(adapterId) {
|
|||
editable : false,
|
||||
mode : 'local',
|
||||
triggerAction : 'all',
|
||||
store : tvheadend.servicetypeStore
|
||||
store : servicetypeStore
|
||||
}),
|
||||
renderer : function(value, metadata, record, row, col, store) {
|
||||
var val = value ? tvheadend.servicetypeStore.getById(value) : null;
|
||||
var val = value ? servicetypeStore.getById(value) : null;
|
||||
return val ? val.get('str')
|
||||
: '<span class="tvh-grid-unset">Unset</span>';
|
||||
}
|
||||
|
@ -291,7 +291,13 @@ tvheadend.iptv = function(adapterId) {
|
|||
iconCls : 'add',
|
||||
text : 'Add service',
|
||||
handler : addRecord
|
||||
}, '-', delButton, '-', saveBtn, rejectBtn ]
|
||||
}, '-', delButton, '-', saveBtn, rejectBtn, '->',
|
||||
{
|
||||
text : 'Help',
|
||||
handler : function() {
|
||||
new tvheadend.help('IPTV', 'config_iptv.html');
|
||||
}
|
||||
} ]
|
||||
});
|
||||
|
||||
store.on('update', function(s, r, o) {
|
||||
|
|
|
@ -24,6 +24,8 @@ tvheadend.comet.on('tvAdapter', function(m) {
|
|||
});
|
||||
|
||||
tvheadend.tvadapters = function() {
|
||||
tvheadend.tvAdapterStore.load();
|
||||
|
||||
var adapterSelection = new Ext.form.ComboBox({
|
||||
loadingText : 'Loading...',
|
||||
width : 300,
|
||||
|
|
|
@ -299,6 +299,7 @@ tvheadend.app = function() {
|
|||
boxMaxHeight : 45,
|
||||
boxMinHeight : 45,
|
||||
border: false,
|
||||
hidden: true,
|
||||
html: '<div id="header"><h1>Tvheadend Web-Panel</h1></div>'
|
||||
});
|
||||
|
||||
|
|
|
@ -144,6 +144,7 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq,
|
|||
{
|
||||
streaming_message_t *sm;
|
||||
int run = 1;
|
||||
int started = 0;
|
||||
muxer_t *mux = NULL;
|
||||
int timeouts = 0;
|
||||
struct timespec ts;
|
||||
|
@ -180,10 +181,10 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq,
|
|||
//Check socket status
|
||||
getsockopt(hc->hc_fd, SOL_SOCKET, SO_ERROR, (char *)&err, &errlen);
|
||||
if(err) {
|
||||
tvhlog(LOG_DEBUG, "webui", "Client hung up, exit streaming");
|
||||
tvhlog(LOG_DEBUG, "webui", "Stop streaming %s, client hung up", hc->hc_url_orig);
|
||||
run = 0;
|
||||
}else if(timeouts >= 20) {
|
||||
tvhlog(LOG_WARNING, "webui", "Timeout waiting for packets");
|
||||
tvhlog(LOG_WARNING, "webui", "Stop streaming %s, timeout waiting for packets", hc->hc_url_orig);
|
||||
run = 0;
|
||||
}
|
||||
}
|
||||
|
@ -198,9 +199,8 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq,
|
|||
switch(sm->sm_type) {
|
||||
case SMT_MPEGTS:
|
||||
case SMT_PACKET:
|
||||
if(!muxer_write_pkt(mux, sm->sm_data))
|
||||
sm->sm_data = NULL;
|
||||
|
||||
muxer_write_pkt(mux, sm->sm_data);
|
||||
sm->sm_data = NULL;
|
||||
break;
|
||||
|
||||
case SMT_START:
|
||||
|
@ -208,16 +208,19 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq,
|
|||
|
||||
http_output_content(hc, muxer_mime(mux, sm->sm_data));
|
||||
muxer_init(mux, sm->sm_data, name);
|
||||
|
||||
started = 1;
|
||||
break;
|
||||
|
||||
case SMT_STOP:
|
||||
muxer_close(mux);
|
||||
tvhlog(LOG_WARNING, "webui", "Stop streaming %s, %s", hc->hc_url_orig,
|
||||
streaming_code2txt(sm->sm_code));
|
||||
run = 0;
|
||||
break;
|
||||
|
||||
case SMT_SERVICE_STATUS:
|
||||
if(getsockopt(hc->hc_fd, SOL_SOCKET, SO_ERROR, &err, &errlen)) {
|
||||
tvhlog(LOG_DEBUG, "webui", "Client hung up, exit streaming");
|
||||
tvhlog(LOG_DEBUG, "webui", "Stop streaming %s, client hung up", hc->hc_url_orig);
|
||||
run = 0;
|
||||
}
|
||||
break;
|
||||
|
@ -226,21 +229,29 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq,
|
|||
break;
|
||||
|
||||
case SMT_NOSTART:
|
||||
tvhlog(LOG_DEBUG, "webui", "Couldn't start stream for %s", hc->hc_url_orig);
|
||||
tvhlog(LOG_WARNING, "webui", "Couldn't start streaming %s, %s", hc->hc_url_orig,
|
||||
streaming_code2txt(sm->sm_code));
|
||||
run = 0;
|
||||
break;
|
||||
|
||||
case SMT_EXIT:
|
||||
muxer_close(mux);
|
||||
tvhlog(LOG_WARNING, "webui", "Stop streaming %s, %s", hc->hc_url_orig,
|
||||
streaming_code2txt(sm->sm_code));
|
||||
run = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
streaming_msg_free(sm);
|
||||
|
||||
if(mux->m_errors)
|
||||
if(mux->m_errors) {
|
||||
tvhlog(LOG_WARNING, "webui", "Stop streaming %s, muxer reported errors", hc->hc_url_orig);
|
||||
run = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(started)
|
||||
muxer_close(mux);
|
||||
|
||||
muxer_destroy(mux);
|
||||
}
|
||||
|
||||
|
|
25
support/changelog
Executable file
25
support/changelog
Executable file
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Create the Tvheadend changelog
|
||||
#
|
||||
|
||||
# Arguments
|
||||
CHANGELOG=$1
|
||||
DIST=$2
|
||||
VER=$3
|
||||
|
||||
# Defaults
|
||||
[ -z "$DEBEMAIL" ] && DEBEMAIL="andreas@lonelycoder.com"
|
||||
[ -z "$DEBFULLNAME" ] && DEBFULLNAME="Andreas Öman"
|
||||
[ -z "$VER" ] && VER=$($(dirname $0)/version)
|
||||
[ ! -z "$DIST" ] && VER=${VER}~${DIST}
|
||||
[ -z "$DIST" ] && DIST=unstable
|
||||
|
||||
# Output
|
||||
NOW=$(date -R)
|
||||
echo >${CHANGELOG} "tvheadend (${VER}) ${DIST}; urgency=low"
|
||||
echo >>${CHANGELOG}
|
||||
echo >>${CHANGELOG} " * The full changelog can be found at "
|
||||
echo >>${CHANGELOG} " http://www.lonelycoder.com/tvheadend/download"
|
||||
echo >>${CHANGELOG}
|
||||
echo >>${CHANGELOG} " -- ${DEBFULLNAME} <${DEBEMAIL}> ${NOW}"
|
|
@ -7,20 +7,35 @@ URL=http://linuxtv.org/hg/dvb-apps/archive/tip.tar.bz2
|
|||
TMP=/tmp/getmuxlist.$$
|
||||
TVH=$(cd $(dirname $0)/..; pwd)/data/dvb-scan
|
||||
|
||||
function die
|
||||
{
|
||||
[ ! -z "$1" ] && echo $1 || echo
|
||||
rm -rf $TMP
|
||||
rm -rf $TVH
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Get files
|
||||
rm -rf $TMP
|
||||
mkdir -p $TMP
|
||||
cd $TMP
|
||||
(wget -O - -q $URL | tar xj) || (curl $URL | tar xj)
|
||||
cd dvb-apps*
|
||||
echo -n "fetching scan files ... "
|
||||
(wget -O - -q $URL | tar xj) 2> /dev/null ||\
|
||||
(curl $URL | tar xj) 2> /dev/null
|
||||
cd dvb-apps* 2> /dev/null || die "failed"
|
||||
echo "done"
|
||||
|
||||
# Copy to TVH
|
||||
echo -n "moving into tvh data/ directory ... "
|
||||
rm -rf $TVH
|
||||
mkdir -p $TVH
|
||||
mv ./util/scan/* $TVH
|
||||
echo "done"
|
||||
|
||||
# Cleanup
|
||||
echo -n "cleaning up ... "
|
||||
for f in $TVH/*; do
|
||||
[ -f $f ] && rm -f $f
|
||||
done
|
||||
rm -rf $TMP
|
||||
echo "done"
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
#!/bin/sh
|
||||
revision=`cd "$1" && git describe --dirty --abbrev=5 2>/dev/null | sed -e 's/-/./g'`
|
||||
|
||||
if ! test $revision; then
|
||||
test $revision || revision=`cd "$1" && git describe --abbrev=5 2>/dev/null | sed -e 's/-/./g'`
|
||||
fi
|
||||
|
||||
echo $revision
|
60
support/launchpad-ppa
Executable file
60
support/launchpad-ppa
Executable file
|
@ -0,0 +1,60 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Upload packages to launchpad. Note: you must configure dput for tvh-X
|
||||
# as target PPA, and you should also define DEBFULLNAME and DEBEMAIL
|
||||
# environment variables
|
||||
#
|
||||
|
||||
# CMD
|
||||
CMD=$(basename $0)
|
||||
echo $CMD
|
||||
|
||||
# Configuration
|
||||
TVH_ROOT=$(cd $(dirname $0)/..; pwd)
|
||||
[ -z "$TVH_DIST" ] && TVH_DIST="lucid natty oneiric precise quantal"
|
||||
[ -z "$TVH_ARCH" ] && TVH_ARCH="i386 amd64"
|
||||
|
||||
# Options
|
||||
[ ! -z "$1" ] && REL=$1 || REL=master
|
||||
[ ! -z "$2" ] && PPA=$2 || PPA=unstable
|
||||
|
||||
# Setup
|
||||
cd $TVH_ROOT || exit 1
|
||||
git checkout $1 && git checkout . || exit 1
|
||||
NOW=`date -R`
|
||||
CHANGELOG=$TVH_ROOT/debian/changelog
|
||||
VERFILE=$TVH_ROOT/src/version.c
|
||||
|
||||
# Create version file
|
||||
VER=$($TVH_ROOT/support/version $VERFILE)
|
||||
|
||||
# Fetch scan files
|
||||
./support/getmuxlist
|
||||
|
||||
# For each distro
|
||||
for d in $TVH_DIST; do
|
||||
V=${VER}~${d}
|
||||
echo $V
|
||||
|
||||
# Create changelog
|
||||
$TVH_ROOT/support/changelog "$CHANGELOG" "$d" "$VER"
|
||||
|
||||
# Build source package
|
||||
dpkg-buildpackage -I.git* -S -sgpg -pgpg || exit 1
|
||||
|
||||
# Build
|
||||
if [ "$CMD" == "pbuilder" ]; then
|
||||
|
||||
for a in $TVH_ARCH; do
|
||||
pbuilder-dist $d $a ../tvheadend_${V}.dsc
|
||||
done
|
||||
|
||||
# Upload
|
||||
else
|
||||
dput tvh-$PPA ../tvheadend_${V}_source.changes || exit 1
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
# Cleanup
|
||||
git checkout .
|
|
@ -125,7 +125,7 @@ def add_entry ( ents, path = "", name = "", idx = -1, next = -1 ):
|
|||
for k in ents:
|
||||
|
||||
# File
|
||||
if not ents[k]:
|
||||
if ents[k] is None:
|
||||
output_file(d, k, idx+1, p)
|
||||
p = idx = idx + 1
|
||||
c = c + 1
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
sh debian/createcopyright.sh >debian/copyright
|
||||
dpkg-buildpackage -rfakeroot -b -us -uc
|
||||
dh_clean
|
1
support/pbuilder
Symbolic link
1
support/pbuilder
Symbolic link
|
@ -0,0 +1 @@
|
|||
launchpad-ppa
|
53
support/tarball
Executable file
53
support/tarball
Executable file
|
@ -0,0 +1,53 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Build tarball of the current directory
|
||||
#
|
||||
|
||||
# Exit
|
||||
function die
|
||||
{
|
||||
echo "ERROR: $*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Switch dir
|
||||
SRCDIR=$(dirname $0)/..
|
||||
cd $SRCDIR
|
||||
|
||||
# Arguments
|
||||
REL=$1
|
||||
if [ ! -z "$REL" ]; then
|
||||
git checkout $REL || die "could not checkout $REL"
|
||||
fi
|
||||
|
||||
# Clean
|
||||
git checkout . || die "could not clean git tree"
|
||||
|
||||
# Version
|
||||
VER=$(./support/version)
|
||||
echo $VER | grep -q dirty && die "git tree is not clean"
|
||||
VER1=$(echo $VER | sed 's/~.*//')
|
||||
echo $VER1
|
||||
|
||||
# Temp directory
|
||||
TMPDIR=/tmp/tvhtar-$$
|
||||
mkdir -p $TMPDIR
|
||||
trap "rm -rf $TMPDIR" EXIT
|
||||
|
||||
# Copy
|
||||
DSTDIR=$TMPDIR/tvheadend-$VER1
|
||||
mkdir $DSTDIR
|
||||
git archive HEAD | tar -x -C $DSTDIR
|
||||
|
||||
# Remove stuff we don't need
|
||||
rm -rf $DSTDIR/.gitignore
|
||||
|
||||
# Fix changelog (store version)
|
||||
$DSTDIR/support/changelog $DSTDIR/debian/changelog "" $VER
|
||||
|
||||
# Build tarball
|
||||
TARFILE=$(cd $SRCDIR/..; pwd)/tvheadend-$VER1.tar.gz
|
||||
tar -C $TMPDIR -zcf $TARFILE tvheadend-$VER1
|
||||
|
||||
# Done
|
||||
echo "Created $TARFILE"
|
34
support/version
Executable file
34
support/version
Executable file
|
@ -0,0 +1,34 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Update Tvheadend version file (if required)
|
||||
#
|
||||
|
||||
# Path to version file
|
||||
FILE=$1
|
||||
|
||||
# Calculate version
|
||||
if [ -d ".git" ]; then
|
||||
VER=$(cd $(dirname $0); git describe --dirty --match "v*" 2> /dev/null | sed "s/^v//" | sed "s/-\([0-9]*\)-\(g[0-9a-f]*\)/.\1~\2/")
|
||||
else
|
||||
VER=$(head -1 $(dirname $0)/../debian/changelog | awk '{ print $2 }' | tr -d '()' | cut -d '-' -f 1)
|
||||
fi
|
||||
|
||||
# Output
|
||||
if [ -z "$FILE" ]; then
|
||||
echo $VER
|
||||
exit
|
||||
fi
|
||||
|
||||
# Leave (probably ppa build)
|
||||
if [ -z "$VER" -a -s "$FILE" ]; then
|
||||
cat $FILE
|
||||
exit
|
||||
fi
|
||||
|
||||
# Update?
|
||||
NEW_VER="const char *tvheadend_version = \"$VER\";"
|
||||
OLD_VER=$(cat $FILE 2> /dev/null)
|
||||
if [ "$NEW_VER" != "$OLD_VER" ]; then
|
||||
echo $NEW_VER > $FILE
|
||||
fi
|
||||
echo $VER
|
|
@ -1,11 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
revision=`$1/support/getver.sh`
|
||||
|
||||
NEW_REVISION="#define BUILD_VERSION \"$revision\""
|
||||
OLD_REVISION=`cat $2 2> /dev/null`
|
||||
|
||||
# Update version.h only on revision changes to avoid spurious rebuilds
|
||||
if test "$NEW_REVISION" != "$OLD_REVISION"; then
|
||||
echo "$NEW_REVISION" > "$2"
|
||||
fi
|
Loading…
Add table
Reference in a new issue