Merge master.

This commit is contained in:
Adam Sutton 2012-05-25 13:27:56 +01:00
commit 9e4e2be33c
46 changed files with 740 additions and 805 deletions

74
Autobuild.sh Executable file
View file

@ -0,0 +1,74 @@
#!/bin/bash
#
# Entry point for the Doozer autobuild system
#
# (c) Andreas Öman 2011. All rights reserved.
#
#
set -eu
BUILD_API_VERSION=2
EXTRA_BUILD_NAME=""
JARGS=""
JOBSARGS=""
TARGET=""
RELEASE="--release"
WORKINGDIR="/var/tmp/showtime-autobuild"
UPLOAD_BUILD_ARTIFACTS=1
while getopts "vht:e:j:w:R" OPTION
do
case $OPTION in
v)
echo $BUILD_API_VERSION
exit 0
;;
R)
UPLOAD_BUILD_ARTIFACTS=0
;;
h)
echo "This script is intended to be used by the autobuild system only"
exit 0
;;
t)
TARGET="$OPTARG"
;;
e)
EXTRA_BUILD_NAME="$OPTARG"
;;
j)
JOBSARGS="--jobs=$OPTARG"
JARGS="-j$OPTARG"
;;
w)
WORKINGDIR="$OPTARG"
;;
esac
done
if [[ -z $TARGET ]]; then
echo "target (-t) not specified"
exit 1
fi
#
# $1 = local file path
# $2 = type
# $3 = content-type
# $4 = filename
#
artifact() {
if [ $UPLOAD_BUILD_ARTIFACTS -eq 1 ]; then
echo "doozer-artifact:$PWD/$1:$2:$3:$4"
else
echo "Ignoring: $1:$2:$3:$4"
fi
}
if [ -f Autobuild/${TARGET}.sh ]; then
source Autobuild/${TARGET}.sh
else
echo "target $TARGET not supported"
exit 1
fi

26
Autobuild/debian.sh Executable file
View file

@ -0,0 +1,26 @@
CHANGELOG=debian/changelog
NOW=`date -R`
VER=`git describe | sed "s/\([0-9]*\)\.\([0-9]*\)-\([0-9]*\)-.*/\1.\2.\3/"`
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}"
cat ${CHANGELOG}
export JOBSARGS
export JARGS
dpkg-buildpackage -b -us -uc
for a in ../tvheadend*${VER}*.deb; do
artifact $a deb application/x-deb `basename $a`
rm -f $a
done
for a in ../tvheadend*${VER}*.changes; do
artifact $a changes text/plain `basename $a`
rm -f $a
done
rm -f ${CHANGELOG}
dh_clean

View file

@ -0,0 +1 @@
source Autobuild/debian.sh

1
Autobuild/ubuntu-lucid-i386.sh Executable file
View file

@ -0,0 +1 @@
source Autobuild/debian.sh

View file

@ -1 +0,0 @@
debian/changelog

View file

@ -28,6 +28,8 @@ CFLAGS += -Wall -Werror -Wwrite-strings -Wno-deprecated-declarations
CFLAGS += -Wmissing-prototypes
LDFLAGS += -lrt -ldl
BUNDLES += docs/html docs/docresources src/webui/static
#
# Core
#
@ -147,23 +149,18 @@ SLIBS += $(SLIBS-yes)
OBJS= $(SRCS:%.c=$(BUILDDIR)/%.o)
OBJS_EXTRA = $(SRCS_EXTRA:%.c=$(BUILDDIR)/%.so)
DEPS= ${OBJS:%.o=%.d}
OBJDIRS= $(sort $(dir $(OBJS))) $(sort $(dir $(OBJS_EXTRA)))
# File bundles
BUNDLE_SRCS=$(BUNDLES:%=$(BUILDDIR)/bundles/%.c)
BUNDLE_DEPS=$(BUNDLE_SRCS:%.c=%.d)
BUNDLE_OBJS=$(BUNDLE_SRCS:%.c=%.o)
OBJDIRS+= $(sort $(dir $(BUNDLE_OBJS)))
.PRECIOUS: ${BUNDLE_SRCS}
VERSION=$(shell support/version.sh)
CURVERSION=$(shell cat ${BUILDDIR}/ver || echo "0")
# Common CFLAGS for all files
CFLAGS_com = -g -funsigned-char -O2
CFLAGS_com += -D_FILE_OFFSET_BITS=64
CFLAGS_com += -I${BUILDDIR} -I${CURDIR}/src -I${CURDIR}
CFLAGS_com += -DHTS_VERSION=\"$(VERSION)\"
MKBUNDLE = $(CURDIR)/support/mkbundle
@ -180,31 +177,41 @@ all: ${PROG}
.PHONY: clean distclean
${PROG}: $(OBJDIRS) $(OBJS) $(BUNDLE_OBJS) ${OBJS_EXTRA} Makefile
$(CC) -o $@ $(OBJS) $(BUNDLE_OBJS) $(LDFLAGS) ${LDFLAGS_cfg}
#
#
#
${PROG}: $(OBJS) $(ALLDEPS) support/dataroot/wd.c
$(CC) -o $@ $(OBJS) support/dataroot/wd.c $(LDFLAGS) ${LDFLAGS_cfg}
$(OBJDIRS):
@mkdir -p $@
${PROG}.bundle: $(OBJS) $(BUNDLE_OBJS) $(ALLDEPS) support/dataroot/bundle.c
$(CC) -o $@ $(OBJS) support/dataroot/bundle.c $(BUNDLE_OBJS) $(LDFLAGS) ${LDFLAGS_cfg}
${PROG}.datadir: $(OBJS) $(ALLDEPS) support/dataroot/datadir.c
$(CC) -o $@ $(OBJS) -iquote${BUILDDIR} support/dataroot/datadir.c $(LDFLAGS) ${LDFLAGS_cfg}
#
#
#
${BUILDDIR}/%.o: %.c
@mkdir -p $(dir $@)
$(CC) -MD -MP $(CFLAGS_com) $(CFLAGS) $(CFLAGS_cfg) -c -o $@ $(CURDIR)/$<
${BUILDDIR}/%.so: ${SRCS_EXTRA}
@mkdir -p $(dir $@)
${CC} -O -fbuiltin -fomit-frame-pointer -fPIC -shared -o $@ $< -ldl
clean:
rm -rf ${BUILDDIR}/src ${BUILDDIR}/bundles ${BUILDDIR}/ver
rm -rf ${BUILDDIR}/src ${BUILDDIR}/bundles
find . -name "*~" | xargs rm -f
distclean: clean
rm -rf build.*
ifneq ($(VERSION), $(CURVERSION))
.PHONY: src/version.c
$(info Version changed)
src/version.c:
@echo $(VERSION) >${BUILDDIR}/ver
endif
# Create buildversion.h
src/version.c: $(BUILDDIR)/buildversion.h
$(BUILDDIR)/buildversion.h: FORCE
@$(CURDIR)/support/version.sh $(CURDIR) $@
FORCE:
# Include dependency files if they exist.
@ -215,7 +222,9 @@ include support/${OSENV}.mk
# Bundle files
$(BUILDDIR)/bundles/%.o: $(BUILDDIR)/bundles/%.c
@mkdir -p $(dir $@)
$(CC) -I${CURDIR}/src -c -o $@ $<
$(BUILDDIR)/bundles/%.c: %
@mkdir -p $(dir $@)
$(MKBUNDLE) -o $@ -s $< -d ${BUILDDIR}/bundles/$<.d -p $< -z

3
README
View file

@ -1,4 +1,3 @@
Tvheadend TV streaming server
=============================
@ -21,7 +20,7 @@ $ make
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

87
configure vendored
View file

@ -11,14 +11,16 @@
# Copyright (c) 2005-2008 Mans Rullgard
#
PLATFORM=`uname`
PLATFORM=linux
source support/configure.inc
CPU=generic
ARCH=`uname -m`
OSENV="posix"
PREFIX=/usr/local
prefix=/usr/local
bindir="\${prefix}/bin"
mandir="\${prefix}/share/man"
datadir="\${prefix}/share/tvheadend"
show_help(){
echo "Usage: configure [options]"
@ -26,7 +28,11 @@ show_help(){
echo
echo "Standard options:"
echo " --help print this message"
echo " --prefix=PREFIX install in PREFIX [$PREFIX]"
echo " --prefix=PREFIX Install in PREFIX [$prefix]"
echo " --bindir=DIR Install binaries in DIR [$bindir]"
echo " --mandir=DIR Install man pages in DIR [$mandir]"
echo " --datadir=DIR Install data files in DIR [$datadir]"
echo
echo " --arch=arch Build for this architecture [$ARCH]"
echo " --cpu=cpu Build and optimize for specific CPU"
echo " --cc=CC Build using the given compiler"
@ -42,8 +48,6 @@ enable v4l
for opt do
optval="${opt#*=}"
case "$opt" in
--prefix=*) PREFIX="$optval"
;;
--cpu=*) CPU="$optval"
;;
--help) show_help
@ -53,6 +57,33 @@ for opt do
;;
--cc=*) CC="$optval"
;;
--prefix=*)
prefix="$optval"
;;
--bindir=*)
bindir="$optval"
;;
--mandir=*)
mandir="$optval"
;;
--datadir=*)
datadir="$optval"
;;
--includedir=*)
;;
--infodir=*)
;;
--sysconfdir=*)
;;
--localstatedir=*)
;;
--libexecdir=*)
;;
--disable-maintainer-mode)
;;
--disable-dependency-tracking)
;;
--enable-?*|--disable-?*)
eval $(echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g')
$action $option
@ -154,38 +185,32 @@ else
die
fi
#
# Configure paths, etc
#
if [ ${RELEASE} != yes ]; then
echo NOTE:
echo NOTE: Development build.
echo NOTE: The generated binary will contained compild-in paths to
echo NOTE: the current build tree. If you plan to install or move
echo NOTE: the binary, please reconfigure with '--release'.
echo NOTE:
cat >> ${CONFIG_H} << EOF
#define TVHEADEND_CONTENT_PATH "${TOPDIR}"
EOF
else
echo >>${CONFIG_MAK} "BUNDLES += docs/html docs/docresources src/webui/static"
cat >> ${CONFIG_H} << EOF
#define TVHEADEND_CONTENT_PATH NULL
EOF
fi
#
# Finalize
#
cat >> ${CONFIG_MAK} << EOF
ARCH=$ARCH
INSTALLPREFIX=$PREFIX
LDFLAGS_cfg += -lpthread
EOF
#
# Finalize
#
echo
echo "Installation paths:"
echo " Prefix: ${prefix}"
echo " Binaries: ${bindir}"
echo " Man pages: ${mandir}"
echo " Data files: ${datadir}"
echo
echo >>${CONFIG_MAK} "prefix=$prefix"
echo >>${CONFIG_MAK} "bindir=\${DESTDIR}$bindir"
echo >>${CONFIG_MAK} "mandir=\${DESTDIR}$mandir"
echo >>${CONFIG_MAK} "datadir=\${DESTDIR}$datadir"
echo >>${CONFIG_MAK} LDFLAGS_cfg += -lpthread -lrt -ldl
eval datadirpath=${datadir}
echo >>${CONFIG_H} "#define TVHEADEND_DATADIR \"${datadirpath}\""
finalize

472
debian/changelog vendored
View file

@ -1,472 +0,0 @@
tvheadend (2.12.99) hts; urgency=low
* Debian package has been renamed from hts-tvheadend to tvheadend
* Add functionality to delete recordings
* Better support for playing in web clients.
Temporary tickets are used instead of username/password authentication
* Remove lock contention in CWC updates
* Fix bug in IPTV PAT parser (Ticket #318)
* Store EPG on disk so it can be reloaded on restart
* Add support for Viaccess EMM
* Add support for DRECrypt EMM
* Depend on OpenSSL for cryptographic features
* RTSP has been dropped. It was too buggy and noone wanted to maintain it
* Fix bug in JSON encoder. Ticket #163
* Fix crash in HTTP service. Ticket #334
* Added http-streaming of services. Tested and working with mplayer.
* Add support for building RPM packages
-- Andreas Öman <andreas@lonelycoder.com> Sat, 19 Feb 2011 12:57:09 +0100
hts-tvheadend (2.12) hts; urgency=low
* Add support for IPTV over IPv6
* Use a native matroska mutiplixer to get better support for metadata, etc
* Add support for multiple DVR configurations (can be set per recording)
* Add suport for teletext subtitles
* Add support for E-AC3
* Workaround for ITV HD (which has incorrect PMT)
Ticket #215
* Keep track of video width and height and send it over HTSP in
subscriptionStart.
Ticket #208
* Add support for Logical Channel Number descriptor (0x83)
Ticket #138
* Maintain the order of PIDs as they appear in the PMT.
Ticket #218
* When there is no video pid (service type is Radio),
start the audio stream right away.
Ticket #59
* Add subscriptionChangeWeight HTSP method.
* psi: Assume that elementary stream type 0x81 is AC3 without
relying on any further descriptors
Ticket #217
* Tvheadend no longer depends on FFmpeg so it's not externally updated
in svn, nor linked.
* Added a native matroska muxer.
Correctly writes global headers. Ticket #61
Add support for recording AAC audio. Ticket #160
Improves metadata written to files.
* Tvheadend no longer tries to fixup lack of PTS/DTS for packets
before sending them over HTSP. Rather, those fields will be left
out in the message. Currently, all HTSP clients known to mankind
handles this.
* Make error detection in timestamp parsing much more robust. Avoid
extracting persistent data (such as video width*height) from
received data if we suspect that an error has occured (MPEG-TS TEI
or continuity counter errors).
-- Andreas Öman <andreas@lonelycoder.com> Mon, 29 Nov 2010 20:06:52 +0100
hts-tvheadend (2.11) hts; urgency=low
* Add support for filtering autorecordings based on weekdays.
* Add circular 10.75 GHz LNB
* Add a new DVB adapter option that allows the entire DVB Mux to be
written to disk as Tvheadend tunes to it. This should aid a lot when
it comes to debugging
* Inject entries in DVR schedule as soon as we know about an EPG
entry that matches an autorecording rule. Previously Tvheadend
would scan the EPG continously and just grab shows as they neared
air time. The drawbacks of this approach was that it's a bit hard
to understand what is happening. It also makes (more) correct
wakeup from suspend hard to do.
* Add parsing of episode information from XMLTV and display it in the
WebUI EPG
* A bug caused the 'Automatic Recorder' tab grid not to reload
entries upon external change (Such as when a channel got deleted
or when a new auto recording was created from the EPG view). This
is now fixed.
* Add support for storing recorded events in a directory named after
the event. Ticket #150
* Add support for appending season and episode numbers to filenames
during recording.
* Prior to this release the color (i.e. connection status) of the
CWC entries were not correctly updated when a connection was established
or lost. This is now fixed. Ticket #144
* Add support for prioritized recordings. The user can chose among five
different priorities.
* Fix various issues realted to the Recording Schedule user interface.
The UI now includes better visual feedback on what's going on and if
there are errors. Also recordings that do not complete successfully
are correctly reported as failed entries. Ticket #131
* Add support for Irdeto and Seca EMM
-- Andreas Öman <andreas@lonelycoder.com> Sat, 27 Mar 2010 10:03:40 +0100
hts-tvheadend (2.10) hts; urgency=high
* Fix a crash in HTSP server.
-- Andreas Öman <andreas@lonelycoder.com> Thu, 04 Feb 2010 22:21:22 +0100
hts-tvheadend (2.9) hts; urgency=high
* A last minute bug slipped in the 2.8 release, causing Tvheadend to read
settings and configuration from incorrect path when also switching user
during startup. This has now been fixed.
-- Andreas Öman <andreas@lonelycoder.com> Mon, 25 Jan 2010 21:23:47 +0100
hts-tvheadend (2.8) hts; urgency=low
* Added support for AAC audio
* Added support for manual creation of DVR entries. Prior to this it
was only possible to schedule a recording based on EPG entries.
* It's now possible to enable/disable the signal quality monitor per
adapter. This is now default off as it seem to mostly cause problems
for people and it's only useful if you have complex setups with
multiple adapters, etc.
* Improve logging when subscriptions fail to start
* More intelligent arbitration amongst all sources when a subscription
is about to start for a channel. If we cannot descramble or if no
input is detected, skip to next source.
Fixes ticket #89
* Add option for editing channel icon URL in the channel config tab.
* Fix support for Irdeto ECM
* Automatically detect if a connected USB DVB adapter is only Full speed
(ie 12Mbit/s), and if so, limit so Tvheadend only can stream one service
at the time from the tuned frequency.
* Add support for extracting provider in the PMT for SECA/Mediaguard
* Add support for NIT-other tables.
In particular useful for Ziggo DVB-C networks in the Netherlands.
* Fix various bugs related to RTP encapsulated IPTV
* Tvheadend now support placement of configurations and settings at any path.
Use the '-c' command line option for this. By default Tvheadend puts
configuration at $HOME/.hts/tvheadend
* Make it possible to enable debug level log in the web interface.
Press the small top-right gear icon in the log console to enable/disable
debug log.
-- Andreas Öman <andreas@lonelycoder.com> Mon, 25 Jan 2010 21:23:47 +0100
hts-tvheadend (2.7) hts; urgency=low
* Added support for DVB subtitles. Currently only forwarded over HTSP
* Add support for reception of RTP encapsulated IPTV
* Fixed a crash caused by a race condition when starting a subscription
* Increase maximum packet size for IPTV to 65536 bytes
-- Andreas Öman <andreas@lonelycoder.com> Sun, 06 Dec 2009 20:40:41 +0100
hts-tvheadend (2.6) hts; urgency=low
* Tvheadend's DVB service probe will now make the channel join tags based
on the service type and DVB provider name.
* Add support for tuning on ATSC adapters
* Add support for sattelite beams with circular polarisation
* If a user changed the XMLTV source for a channel to 'None', tvheadend
would crash. This is now fixed.
* Add support for copying a selection of muxes from one DVB adapter to
another in the web UI.
* Support for DVB-S2 has been added
* Default character encoding in DVB is ISO6937, not Latin-1. Ticket #96
* Add support for DiSEqC 1.1 / 2.1, configured on per-adapter basis.
Ticket #99
* Increase logging and include various stats to XMLTV grab
* Add support for configuring a per-channel pre/post extra time for
scheduled recordings. Ticket #104
* Autodetect CPU capabilities and choose best mode for CSA descrambler.
Ticket #122
-- Andreas Öman <andreas@lonelycoder.com> Sun, 29 Nov 2009 14:02:36 +0100
hts-tvheadend (2.5) hts; urgency=low
* If a previosly detected DVB adapter was not present during startup,
Tvheadend would crash. This is now fixed.
* If XMLTV grabbing was disabled tvheadend would spin in a 100% CPU loop.
This is now fixed.
* The HTSP service is now announced via AVAHI (mDNS service discovery)
* Support for IPTV has been added. Only RAW TS in UDP is supported
at the moment.
* Add support for setting default extra times to add before and after
a recording. Useful if your TV shows never start on time.
* Use FFmpeg's av_interleaved_write_frame() or some players can't
play the recorded content (vlc is one)
-- Andreas Öman <andreas@lonelycoder.com> Wed, 19 Aug 2009 22:28:02 +0200
hts-tvheadend (2.4) hts; urgency=low
* Due to a bug, the polarisation of DVB-S muxes was not correctly
stored internally. This has now been fixed.
* Fix compilation on 64bit systems
* Make sure channel <> service mappings are saved when edited from
DVB service grid
* Add support for merging one channel into another.
Useful if you have multiple providers offering the same DVB service
but with different names.
* The embedded HTTP server now logs failed requests
* Use absolute paths when serving static content (the web app itself)
This was only a problem when fork()ing a development build
* Rework the CWC reconnection strategy.
If there are active subscription, Tvheadend will attempt to reconnect
immediately and then retry every three seconds.
If no subscription is active a reconnection attempt is performed
every minute.
Also, if any CWC configuration changes are made from the UI, Tvheadend
will try to reconnect directly.
* If the EPG receives an updated description for an even that is shorter
than the current description it will be ignored.
This typically happens if the XMLTV and DVB EIT (Event Information Table)
differs. In other words, we assume that a longer description of an
event is better than a short.
-- Andreas Öman <andreas@lonelycoder.com> Sun, 26 Jul 2009 13:27:32 +0200
hts-tvheadend (2.3) hts; urgency=low
* A simple web interface has been added. To access it, visit
http://host:9981/simple.html
This web interface is designed to be really tiny with only
a simple search field and options to record found shows.
Preferably used from handheld devices.
* All sensitive information (passwords, etc) are hidden from display
in the web ui. The text will still be displayed in cleartext when
editing.
* Redesigned the DVB configuration tab in the web userinterface:
- Each adapter have three (or four) tabs
o General setup and information
o Grid of multiplexes
o Grid of services
o For sattelite adapters, a sattelite configuration tab.
* Add support for disabling / enabling an entire DVB multiplex
* Add support for multiple DiSEqC switchports on a single adapter
* Add support for different sattelite LNBs
* Graceful handling of DVB adapters that does not support many
table filters in hardware. Tvheadend will rotate among the available
ones.
* Add support for enabling / disabling transports from the DVB configuration
* Make it possible to remove DVB multiplexes from the web ui
* Add 'Revert changes' button to all editable grids in the web ui
* Make it possible to disable the idle scan on per-DVB adapter basis.
The idle scan is a process to cycles through all multiplex to check
the quality for each mux continously.
* Hopefully fix some rounding errors in the EPG display. Ticket #69
* Use a ''livegrid'' (http://www.ext-livegrid.com/) for displaying EPG.
* Remove configuration and settings (/home/hts/.hts/tvheadend) on a
deb package purge operation. Ticket #73
* If the Program Stream Information changes during a subscription,
react and send a subscriptionStop + subscriptionStart.
This happens on SVT (in sweden) when the transmission switches
from local to nationwide broadcast (AC3 audio is only present
in nationwide broadcast)
Ticket #78
* Channel editor has been reworked a bit. It uses an editorGrid, similar
to how other grids work in Tvheadend. Tags are mapped inline using
a list-of-values combobox (http://lovcombo.extjs.eu/)
* Added a search IMDB direct link in the EPG window popup.
Ticket #79
* Add support for configuring DVB multiplexes by entering
all tuning parameters manually
Ticket #37
* Fix a bug causing channel <> tags mapping not to be restored on load.
* Add exponential backoff for reconnect attempt in code word client.
Ticket #80
* Try to detect duplicate EPG entries from the DVB feed and adjust
EPG accordingly. The EPG code will search for events with the same
DVB event ID +- 2 events from the current one. If the event id is
equal, the prvious (old) entry will be removed in favor of the new one.
Reason for not blindingly trusting the event id is that some networks
seem to (incorrectly) reuse IDs.
Ticket #65
-- Andreas Öman <andreas@lonelycoder.com> Sat, 18 Jul 2009 23:19:18 +0200
hts-tvheadend (2.2) hts; urgency=low
* Set $HOME so forked processes (XMLTV) will have correct environment
and to make the default storage of recorded videos to end up in the
correct place.
* Update built-in DVB mux presets to dvb-apps:1275:9655c8cfeed8
* Add -h option to display usage.
* Rewrite the internal streaming pipeline.
This is not externally visible, but needed for a future timeshifter.
* Make it compile on gcc 4.4
* Send 'source' and 'network' information in HTSP.subscriptionStart message.
* When deleting a channel any channel-bound autorecording would stay in
memory and, sooner or later, cause a crash. This has now been fixed.
* Add extra scan for XMLTV grabbers in $PATH. Apart from $PATH we also
scan in /bin, /usr/bin, /usr/local/bin
* Search for XMLTV grabbers in /usr/bin/perlbin/vendor (archlinux)
* Fix a bug causing DVB card which does not implement the
FE_READ_UNCORRECTED_BLOCKS operation to report insane amount of
forward correction errors.
-- Andreas Öman <andreas@lonelycoder.com> Sun, 07 Jun 2009 19:22:49 +0200
hts-tvheadend (2.1) hts; urgency=low
* Add debconf setup scripts to create a superuser account.
* HTSP server slightly modified. Now also supports the XBMC HTSP client.
* tvheadend and showtime went separate ways.
* tvheadend: Record post-processing added again, run command when a
recording is done.
* tvheadend: Fix characterset translation bug introduced in r1902.
-- Andreas Öman <andreas@lonelycoder.com> Thu, 28 May 2009 21:07:44 +0200
hts-tvheadend (2.0) unstable; urgency=low
* tvheadend: All setup and configuration is done from the web user interface.
* tvheadend: New web user interface based on ExtJS
-- Andreas Öman <andreas@lonelycoder.com> Thu, 16 Oct 2008 19:47:23 +0200
hts-tvheadend (1.4) unstable; urgency=low
* tvheadend: Add support for DVB-S (still in experimenal state)
-- Andreas Öman <andreas@lonelycoder.com> Sat, 30 Mar 2008 18:00:00 +0100
hts-tvheadend (1.3) unstable; urgency=low
* tvheadend: Add support for executing a post processing script after
recording is completed.
* tvheadend: Mark I-frames as key-frames in recorder (should make seeking
work better).
* tvheadend: Correctly set duration of packets in recorder.
-- Andreas Öman <andreas@lonelycoder.com> Thu, 28 Mar 2008 18:00:00 +0100
hts-tvheadend (1.2) unstable; urgency=low
* Tvheadend has been rewritten from scratch
-- Andreas Öman <andreas@lonelycoder.com> Thu, 28 Feb 2008 17:30:00 +0100
hts-tvheadend (1.1) unstable; urgency=low
* Bugfix: Tvheadend: Do not crash if event name is NULL
* Rewrite tvheadend internals to fix many serious issues
* tvheadend now correctly supports recording of h264 content
* RTSP interface added to tvheadend that supports time shifting of live tv
* Add web interface to tvheadend
-- Andreas Öman <andreas@lonelycoder.com> Sat, 24 Nov 2007 08:11:00 +0100
hts-tvheadend (1.0) unstable; urgency=low
* Initial release
-- Andreas Öman <andreas@lonelycoder.com> Tue, 19 Sep 2007 19:20:00 +0200

30
debian/rules vendored
View file

@ -1,38 +1,18 @@
#!/usr/bin/make -f
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
DEB_BUILD_GNU_TYPE := $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
export DH_VERBOSE=1
%:
dh $@
override_dh_clean:
dh_testdir
dh_testroot
rm -rf build.*
dh_clean
override_dh_auto_clean:
dh_clean
override_dh_auto_configure:
dh_testdir
./configure --release --prefix=/usr
dh_auto_configure -- ${JOBSARGS}
override_dh_auto_build:
$(MAKE)
override_dh_install:
$(MAKE) DESTDIR=$(CURDIR)/debian/tvheadend install
override_dh_installinit:
dh_installinit --name tvheadend
make ${JARGS}
override_dh_strip:
dh_strip --dbg-package=tvheadend-dbg
override_dh_autotest:
echo "skipped autotest"
override_dh_auto_install:
dh_auto_install --destdir=debian/tvheadend

View file

@ -13,7 +13,7 @@
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/usr/sbin:/usr/bin:/sbin:/bin
DESC="HTS Tvheadend"
DESC="Tvheadend"
NAME=tvheadend
DAEMON=/usr/bin/$NAME
DAEMON_ARGS="-f -u hts -g video"

View file

@ -51,6 +51,9 @@
<dt>Update Card
<dd>Forward Entitlement Management Messages (EMMs) to the server.
<dt>Update One
<dd>Forward EMMs only from one channel at a time.
<dt>Comment
<dd>Allows the administrator to set a comment only visible in this editor.
It does not serve any active purpose.

View file

@ -174,7 +174,7 @@ access_verify(const char *username, const char *password,
if(ae->ae_username[0] != '*') {
/* acl entry requires username to match */
if(username == NULL)
if(username == NULL || password == NULL)
continue; /* Didn't get one */
if(strcmp(ae->ae_username, username) ||
@ -391,6 +391,7 @@ access_record_build(access_entry_t *ae)
htsmsg_add_u32(e, "streaming", ae->ae_rights & ACCESS_STREAMING ? 1 : 0);
htsmsg_add_u32(e, "dvr" , ae->ae_rights & ACCESS_RECORDER ? 1 : 0);
htsmsg_add_u32(e, "dvrallcfg", ae->ae_rights & ACCESS_RECORDER_ALL ? 1 : 0);
htsmsg_add_u32(e, "webui" , ae->ae_rights & ACCESS_WEB_INTERFACE ? 1 : 0);
htsmsg_add_u32(e, "admin" , ae->ae_rights & ACCESS_ADMIN ? 1 : 0);
@ -480,6 +481,9 @@ access_record_update(void *opaque, const char *id, htsmsg_t *values,
if(!htsmsg_get_u32(values, "dvr", &u32))
access_update_flag(ae, ACCESS_RECORDER, u32);
if(!htsmsg_get_u32(values, "dvrallcfg", &u32))
access_update_flag(ae, ACCESS_RECORDER_ALL, u32);
if(!htsmsg_get_u32(values, "admin", &u32))
access_update_flag(ae, ACCESS_ADMIN, u32);

View file

@ -58,7 +58,8 @@ typedef struct access_ticket {
#define ACCESS_STREAMING 0x1
#define ACCESS_WEB_INTERFACE 0x2
#define ACCESS_RECORDER 0x4
#define ACCESS_ADMIN 0x8
#define ACCESS_RECORDER_ALL 0x8
#define ACCESS_ADMIN 0x10
#define ACCESS_FULL 0x3f
/**

294
src/cwc.c
View file

@ -47,7 +47,7 @@
#define TVHEADEND_PROTOCOL_ID 0x6502
#define CWC_KEEPALIVE_INTERVAL 30
#define CWS_NETMSGSIZE 272
#define CWS_NETMSGSIZE 362
#define CWS_FIRSTCMDNO 0xe0
/**
@ -61,6 +61,8 @@ typedef enum {
CARD_VIACCESS,
CARD_NAGRA,
CARD_NDS,
CARD_CRYPTOWORKS,
CARD_BULCRYPT,
CARD_UNKNOWN
} card_type_t;
@ -150,7 +152,8 @@ typedef struct cwc_service {
enum {
CS_UNKNOWN,
CS_RESOLVED,
CS_FORBIDDEN
CS_FORBIDDEN,
CS_IDLE
} cs_keystate;
void *cs_keys;
@ -242,7 +245,13 @@ typedef struct cwc {
int shared_toggle;
int shared_len;
uint8_t * shared_emm;
void *ca_update_id;
} cwc_viaccess_emm;
#define cwc_cryptoworks_emm cwc_viaccess_emm
/* one update id */
int64_t cwc_update_time;
void *cwc_update_id;
/* Card type */
card_type_t cwc_card_type;
@ -258,6 +267,7 @@ typedef struct cwc {
int cwc_port;
char *cwc_id;
int cwc_emm;
int cwc_emmex;
const char *cwc_errtxt;
@ -280,6 +290,8 @@ void cwc_emm_seca(cwc_t *cwc, uint8_t *data, int len);
void cwc_emm_viaccess(cwc_t *cwc, uint8_t *data, int len);
void cwc_emm_nagra(cwc_t *cwc, uint8_t *data, int len);
void cwc_emm_nds(cwc_t *cwc, uint8_t *data, int len);
void cwc_emm_cryptoworks(cwc_t *cwc, uint8_t *data, int len);
void cwc_emm_bulcrypt(cwc_t *cwc, uint8_t *data, int len);
/**
@ -469,7 +481,7 @@ cwc_send_msg(cwc_t *cwc, const uint8_t *msg, size_t len, int sid, int enq)
buf[4] = sid >> 8;
buf[5] = sid;
if((len = des_encrypt(buf, len, cwc)) < 0) {
if((len = des_encrypt(buf, len, cwc)) <= 0) {
free(buf);
free(cm);
return -1;
@ -581,10 +593,10 @@ cwc_decode_card_data_reply(cwc_t *cwc, uint8_t *msg, int len)
memcpy(cwc->cwc_ua, &msg[6], 8);
tvhlog(LOG_INFO, "cwc", "%s: Connected as user 0x%02x "
tvhlog(LOG_INFO, "cwc", "%s:%i: Connected as user 0x%02x "
"to a %s-card [0x%04x : %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x] "
"with %d providers",
cwc->cwc_hostname,
cwc->cwc_hostname, cwc->cwc_port,
msg[3], n, cwc->cwc_caid,
cwc->cwc_ua[0], cwc->cwc_ua[1], cwc->cwc_ua[2], cwc->cwc_ua[3], cwc->cwc_ua[4], cwc->cwc_ua[5], cwc->cwc_ua[6], cwc->cwc_ua[7],
nprov);
@ -607,8 +619,8 @@ cwc_decode_card_data_reply(cwc_t *cwc, uint8_t *msg, int len)
cwc->cwc_providers[i].sa[6] = msg[9];
cwc->cwc_providers[i].sa[7] = msg[10];
tvhlog(LOG_INFO, "cwc", "%s: Provider ID #%d: 0x%06x %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x",
cwc->cwc_hostname, i + 1,
tvhlog(LOG_INFO, "cwc", "%s:%i: Provider ID #%d: 0x%06x %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x",
cwc->cwc_hostname, cwc->cwc_port, i + 1,
cwc->cwc_providers[i].id,
cwc->cwc_providers[i].sa[0],
cwc->cwc_providers[i].sa[1],
@ -631,16 +643,16 @@ cwc_decode_card_data_reply(cwc_t *cwc, uint8_t *msg, int len)
if (!emm_allowed) {
tvhlog(LOG_INFO, "cwc",
"%s: Will not forward EMMs (not allowed by server)",
cwc->cwc_hostname);
"%s:%i: Will not forward EMMs (not allowed by server)",
cwc->cwc_hostname, cwc->cwc_port);
} else if (cwc->cwc_card_type != CARD_UNKNOWN) {
tvhlog(LOG_INFO, "cwc", "%s: Will forward EMMs",
cwc->cwc_hostname);
tvhlog(LOG_INFO, "cwc", "%s:%i: Will forward EMMs",
cwc->cwc_hostname, cwc->cwc_port);
cwc->cwc_forward_emm = 1;
} else {
tvhlog(LOG_INFO, "cwc",
"%s: Will not forward EMMs (unsupported CA system)",
cwc->cwc_hostname);
"%s:%i: Will not forward EMMs (unsupported CA system)",
cwc->cwc_hostname, cwc->cwc_port);
}
}
@ -658,43 +670,57 @@ static void
cwc_detect_card_type(cwc_t *cwc)
{
uint8_t c_sys = cwc->cwc_caid >> 8;
switch(cwc->cwc_caid) {
case 0x5581:
case 0x4aee:
cwc->cwc_card_type = CARD_BULCRYPT;
tvhlog(LOG_INFO, "cwc", "%s:%i: bulcrypt card",
cwc->cwc_hostname, cwc->cwc_port);
return;
}
switch(c_sys) {
case 0x17:
case 0x06:
cwc->cwc_card_type = CARD_IRDETO;
tvhlog(LOG_INFO, "cwc", "%s: irdeto card",
cwc->cwc_hostname);
tvhlog(LOG_INFO, "cwc", "%s:%i: irdeto card",
cwc->cwc_hostname, cwc->cwc_port);
break;
case 0x05:
cwc->cwc_card_type = CARD_VIACCESS;
tvhlog(LOG_INFO, "cwc", "%s: viaccess card",
cwc->cwc_hostname);
tvhlog(LOG_INFO, "cwc", "%s:%i: viaccess card",
cwc->cwc_hostname, cwc->cwc_port);
break;
case 0x0b:
cwc->cwc_card_type = CARD_CONAX;
tvhlog(LOG_INFO, "cwc", "%s: conax card",
cwc->cwc_hostname);
tvhlog(LOG_INFO, "cwc", "%s:%i: conax card",
cwc->cwc_hostname, cwc->cwc_port);
break;
case 0x01:
cwc->cwc_card_type = CARD_SECA;
tvhlog(LOG_INFO, "cwc", "%s: seca card",
cwc->cwc_hostname);
tvhlog(LOG_INFO, "cwc", "%s:%i: seca card",
cwc->cwc_hostname, cwc->cwc_port);
break;
case 0x4a:
cwc->cwc_card_type = CARD_DRE;
tvhlog(LOG_INFO, "cwc", "%s: dre card",
cwc->cwc_hostname);
tvhlog(LOG_INFO, "cwc", "%s:%i: dre card",
cwc->cwc_hostname, cwc->cwc_port);
break;
case 0x18:
cwc->cwc_card_type = CARD_NAGRA;
tvhlog(LOG_INFO, "cwc", "%s: nagra card",
cwc->cwc_hostname);
tvhlog(LOG_INFO, "cwc", "%s:%i: nagra card",
cwc->cwc_hostname, cwc->cwc_port);
break;
case 0x09:
cwc->cwc_card_type = CARD_NDS;
tvhlog(LOG_INFO, "cwc", "%s: nds card",
cwc->cwc_hostname);
tvhlog(LOG_INFO, "cwc", "%s:%i: nds card",
cwc->cwc_hostname, cwc->cwc_port);
break;
case 0x0d:
cwc->cwc_card_type = CARD_CRYPTOWORKS;
tvhlog(LOG_INFO, "cwc", "%s:%i: cryptoworks card",
cwc->cwc_hostname, cwc->cwc_port);
break;
default:
cwc->cwc_card_type = CARD_UNKNOWN;
@ -728,6 +754,8 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
int len, int seq)
{
service_t *t = ct->cs_service;
cwc_service_t *ct2;
cwc_t *cwc2;
ecm_pid_t *ep;
char chaninfo[32];
int i;
@ -748,20 +776,48 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
if(ct->cs_okchannel == es->es_channel)
ct->cs_okchannel = -1;
if (es->es_nok < 3)
es->es_nok++;
if(ct->cs_keystate == CS_FORBIDDEN)
return; // We already know it's bad
es->es_nok = 1;
if (es->es_nok > 2) {
tvhlog(LOG_DEBUG, "cwc",
"Too many NOKs for service \"%s\"%s from %s:%i",
t->s_svcname, chaninfo, ct->cs_cwc->cwc_hostname,
ct->cs_cwc->cwc_port);
goto forbid;
}
TAILQ_FOREACH(cwc2, &cwcs, cwc_link) {
LIST_FOREACH(ct2, &cwc2->cwc_services, cs_link) {
if (ct != ct2 && ct2->cs_service == t &&
ct2->cs_keystate == CS_RESOLVED) {
tvhlog(LOG_DEBUG, "cwc",
"NOK from %s:%i: Already has a key for service \"%s\", from %s:%i",
ct->cs_cwc->cwc_hostname, ct->cs_cwc->cwc_port,
t->s_svcname, ct2->cs_cwc->cwc_hostname, ct2->cs_cwc->cwc_port);
es->es_nok = 3; /* do not send more ECM requests */
goto forbid;
}
}
}
tvhlog(LOG_DEBUG, "cwc", "Received NOK for service \"%s\"%s (seqno: %d "
"Req delay: %lld ms)", t->s_svcname, chaninfo, seq, delay);
forbid:
LIST_FOREACH(ep, &ct->cs_pids, ep_link) {
for(i = 0; i <= ep->ep_last_section; i++)
if(ep->ep_sections[i] == NULL ||
ep->ep_sections[i]->es_pending ||
ep->ep_sections[i]->es_nok == 0)
return;
if(ep->ep_sections[i] == NULL) {
if(es->es_nok < 2) /* only first hit is allowed */
return;
} else {
if(ep->ep_sections[i]->es_pending ||
ep->ep_sections[i]->es_nok == 0)
return;
}
}
tvhlog(LOG_ERR, "cwc",
"Can not descramble service \"%s\", access denied (seqno: %d "
@ -786,12 +842,26 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
msg[3 + 5], msg[3 + 6], msg[3 + 7], msg[3 + 8], msg[3 + 9],
msg[3 + 10],msg[3 + 11],msg[3 + 12],msg[3 + 13],msg[3 + 14],
msg[3 + 15], seq, delay);
TAILQ_FOREACH(cwc2, &cwcs, cwc_link) {
LIST_FOREACH(ct2, &cwc2->cwc_services, cs_link) {
if (ct != ct2 && ct2->cs_service == t &&
ct2->cs_keystate == CS_RESOLVED) {
ct->cs_keystate = CS_IDLE;
tvhlog(LOG_DEBUG, "cwc",
"Already has a key for service \"%s\", from %s:%i",
t->s_svcname, ct2->cs_cwc->cwc_hostname, ct2->cs_cwc->cwc_port);
return;
}
}
}
if(ct->cs_keystate != CS_RESOLVED)
tvhlog(LOG_INFO, "cwc",
"Obtained key for for service \"%s\" in %lld ms, from %s",
t->s_svcname, delay, ct->cs_cwc->cwc_hostname);
"Obtained key for service \"%s\" in %lld ms, from %s:%i",
t->s_svcname, delay, ct->cs_cwc->cwc_hostname,
ct->cs_cwc->cwc_port);
ct->cs_keystate = CS_RESOLVED;
memcpy(ct->cs_cw, msg + 3, 16);
ct->cs_pending_cw_update = 1;
@ -877,15 +947,15 @@ cwc_read_message(cwc_t *cwc, const char *state, int timeout)
int msglen, r;
if((r = cwc_read(cwc, buf, 2, timeout))) {
tvhlog(LOG_INFO, "cwc", "%s: %s: Read error (header): %s",
cwc->cwc_hostname, state, strerror(r));
tvhlog(LOG_INFO, "cwc", "%s:%i: %s: Read error (header): %s",
cwc->cwc_hostname, cwc->cwc_port, state, strerror(r));
return -1;
}
msglen = (buf[0] << 8) | buf[1];
if(msglen >= CWS_NETMSGSIZE) {
tvhlog(LOG_INFO, "cwc", "%s: %s: Invalid message size: %d",
cwc->cwc_hostname, state, msglen);
tvhlog(LOG_INFO, "cwc", "%s:%i: %s: Invalid message size: %d",
cwc->cwc_hostname, cwc->cwc_port, state, msglen);
return -1;
}
@ -893,14 +963,14 @@ cwc_read_message(cwc_t *cwc, const char *state, int timeout)
so just wait 1 second here */
if((r = cwc_read(cwc, cwc->cwc_buf + 2, msglen, 1000))) {
tvhlog(LOG_INFO, "cwc", "%s: %s: Read error: %s",
cwc->cwc_hostname, state, strerror(r));
tvhlog(LOG_INFO, "cwc", "%s:%i: %s: Read error: %s",
cwc->cwc_hostname, cwc->cwc_port, state, strerror(r));
return -1;
}
if((msglen = des_decrypt(cwc->cwc_buf, msglen + 2, cwc)) < 15) {
tvhlog(LOG_INFO, "cwc", "%s: %s: Decrypt failed",
state, cwc->cwc_hostname);
tvhlog(LOG_INFO, "cwc", "%s:%i: %s: Decrypt failed",
cwc->cwc_hostname, cwc->cwc_port, state);
return -1;
}
return msglen;
@ -962,8 +1032,8 @@ cwc_session(cwc_t *cwc)
* Get login key
*/
if((r = cwc_read(cwc, cwc->cwc_buf, 14, 5000))) {
tvhlog(LOG_INFO, "cwc", "%s: No login key received: %s",
cwc->cwc_hostname, strerror(r));
tvhlog(LOG_INFO, "cwc", "%s:%i: No login key received: %s",
cwc->cwc_hostname, cwc->cwc_port, strerror(r));
return;
}
@ -978,7 +1048,8 @@ cwc_session(cwc_t *cwc)
return;
if(cwc->cwc_buf[12] != MSG_CLIENT_2_SERVER_LOGIN_ACK) {
tvhlog(LOG_INFO, "cwc", "%s: Login failed", cwc->cwc_hostname);
tvhlog(LOG_INFO, "cwc", "%s:%i: Login failed",
cwc->cwc_hostname, cwc->cwc_port);
return;
}
@ -992,7 +1063,8 @@ cwc_session(cwc_t *cwc)
return;
if(cwc->cwc_buf[12] != MSG_CARD_DATA) {
tvhlog(LOG_INFO, "cwc", "%s: Card data request failed", cwc->cwc_hostname);
tvhlog(LOG_INFO, "cwc", "%s:%i: Card data request failed",
cwc->cwc_hostname, cwc->cwc_port);
return;
}
@ -1094,7 +1166,8 @@ cwc_thread(void *aux)
cwc->cwc_caid = 0;
cwc->cwc_connected = 0;
cwc_comet_status_update(cwc);
tvhlog(LOG_INFO, "cwc", "Disconnected from %s", cwc->cwc_hostname);
tvhlog(LOG_INFO, "cwc", "Disconnected from %s:%i",
cwc->cwc_hostname, cwc->cwc_port);
}
if(subscriptions_active()) {
@ -1109,13 +1182,14 @@ cwc_thread(void *aux)
ts.tv_nsec = 0;
tvhlog(LOG_INFO, "cwc",
"%s: Automatic connection attempt in in %d seconds",
cwc->cwc_hostname, d);
"%s:%i: Automatic connection attempt in in %d seconds",
cwc->cwc_hostname, cwc->cwc_port, d);
pthread_cond_timedwait(&cwc_config_changed, &cwc_mutex, &ts);
}
tvhlog(LOG_INFO, "cwc", "%s destroyed", cwc->cwc_hostname);
tvhlog(LOG_INFO, "cwc", "%s:%i destroyed",
cwc->cwc_hostname, cwc->cwc_port);
while((ct = LIST_FIRST(&cwc->cwc_services)) != NULL) {
t = ct->cs_service;
@ -1180,14 +1254,24 @@ cwc_emm_cache_lookup(cwc_t *cwc, uint32_t crc)
*
*/
void
cwc_emm(uint8_t *data, int len)
cwc_emm(uint8_t *data, int len, uint16_t caid, void *ca_update_id)
{
cwc_t *cwc;
pthread_mutex_lock(&cwc_mutex);
TAILQ_FOREACH(cwc, &cwcs, cwc_link) {
if(cwc->cwc_forward_emm && cwc->cwc_writer_running) {
if(cwc->cwc_caid == caid &&
cwc->cwc_forward_emm && cwc->cwc_writer_running) {
if (cwc->cwc_emmex) {
if (cwc->cwc_update_id != ca_update_id) {
int64_t delta = getmonoclock() - cwc->cwc_update_time;
if (delta < 25000000UL) /* 25 seconds */
continue;
}
cwc->cwc_update_time = getmonoclock();
}
cwc->cwc_update_id = ca_update_id;
switch (cwc->cwc_card_type) {
case CARD_CONAX:
cwc_emm_conax(cwc, data, len);
@ -1210,6 +1294,12 @@ cwc_emm(uint8_t *data, int len)
case CARD_NDS:
cwc_emm_nds(cwc, data, len);
break;
case CARD_CRYPTOWORKS:
cwc_emm_cryptoworks(cwc, data, len);
break;
case CARD_BULCRYPT:
cwc_emm_bulcrypt(cwc, data, len);
break;
case CARD_UNKNOWN:
break;
}
@ -1402,13 +1492,15 @@ cwc_emm_viaccess(cwc_t *cwc, uint8_t *data, int mlen)
if (cwc->cwc_viaccess_emm.shared_emm) {
cwc->cwc_viaccess_emm.shared_len = len;
memcpy(cwc->cwc_viaccess_emm.shared_emm, data, len);
cwc->cwc_viaccess_emm.ca_update_id = cwc->cwc_update_id;
}
cwc->cwc_viaccess_emm.shared_toggle = data[0];
}
}
break;
case 0x8e:
if (cwc->cwc_viaccess_emm.shared_emm) {
if (cwc->cwc_viaccess_emm.shared_emm &&
cwc->cwc_viaccess_emm.ca_update_id == cwc->cwc_update_id) {
int match = 0;
int i;
/* Match SA and provider in shared */
@ -1490,6 +1582,9 @@ cwc_table_input(struct th_descrambler *td, struct service *t,
char chaninfo[32];
caid_t *c;
if (ct->cs_keystate == CS_IDLE)
return;
if(len > 4096)
return;
@ -1541,6 +1636,9 @@ cwc_table_input(struct th_descrambler *td, struct service *t,
es = ep->ep_sections[section];
if (es->es_nok > 2)
break; /* too many NOK responses in a row */
if(es->es_ecmsize == len && !memcmp(es->es_ecm, data, len))
break; /* key already sent */
@ -1654,6 +1752,90 @@ cwc_emm_nds(cwc_t *cwc, uint8_t *data, int len)
cwc_send_msg(cwc, data, len, 0, 1);
}
void
cwc_emm_cryptoworks(cwc_t *cwc, uint8_t *data, int len)
{
int match = 0;
switch (data[0]) {
case 0x82: /* unique */
match = len >= 10 && memcmp(data + 5, cwc->cwc_ua + 3, 5) == 0;
break;
case 0x84: /* emm-sh */
if (len >= 9 && memcmp(data + 5, cwc->cwc_ua + 3, 4) == 0) {
if (cwc->cwc_cryptoworks_emm.shared_emm) {
free(cwc->cwc_cryptoworks_emm.shared_emm);
cwc->cwc_cryptoworks_emm.shared_len = 0;
cwc->cwc_cryptoworks_emm.shared_emm = (uint8_t *)malloc(len);
}
cwc->cwc_cryptoworks_emm.shared_emm = malloc(len);
if (cwc->cwc_cryptoworks_emm.shared_emm) {
cwc->cwc_cryptoworks_emm.shared_len = len;
memcpy(cwc->cwc_cryptoworks_emm.shared_emm, data, len);
cwc->cwc_cryptoworks_emm.ca_update_id = cwc->cwc_update_id;
}
}
break;
case 0x86: /* emm-sb */
if (cwc->cwc_cryptoworks_emm.shared_emm &&
cwc->cwc_cryptoworks_emm.ca_update_id == cwc->cwc_update_id) {
/* python: EMM_SH[0:12] + EMM_SB[5:-1] + EMM_SH[12:-1] */
uint32_t elen = len - 5 + cwc->cwc_cryptoworks_emm.shared_len - 12;
uint8_t *tmp = malloc(elen);
uint8_t *composed = tmp ? malloc(elen + 12) : NULL;
if (composed) {
memcpy(tmp, data + 5, len - 5);
memcpy(tmp + len - 5, cwc->cwc_cryptoworks_emm.shared_emm + 12,
cwc->cwc_cryptoworks_emm.shared_len - 12);
memcpy(composed, cwc->cwc_cryptoworks_emm.shared_emm, 12);
sort_nanos(composed + 12, tmp, elen);
composed[1] = ((elen + 9) >> 8) | 0x70;
composed[2] = (elen + 9) & 0xff;
cwc_send_msg(cwc, composed, elen + 12, 0, 1);
free(composed);
free(tmp);
}
cwc->cwc_cryptoworks_emm.shared_emm = NULL;
cwc->cwc_cryptoworks_emm.shared_len = 0;
}
break;
case 0x88: /* global */
case 0x89: /* global */
match = 1;
break;
default:
break;
}
if (match)
cwc_send_msg(cwc, data, len, 0, 1);
}
void
cwc_emm_bulcrypt(cwc_t *cwc, uint8_t *data, int len)
{
int match = 0;
switch (data[0]) {
case 0x82: /* unique */
case 0x85: /* unique */
match = len >= 10 && memcmp(data + 3, cwc->cwc_ua + 2, 3) == 0;
break;
case 0x84: /* shared */
match = len >= 10 && memcmp(data + 3, cwc->cwc_ua + 2, 2) == 0;
break;
case 0x8b: /* shared-unknown */
match = len >= 10 && memcmp(data + 4, cwc->cwc_ua + 2, 2) == 0;
break;
case 0x8a: /* global */
match = len >= 10 && memcmp(data + 4, cwc->cwc_ua + 2, 1) == 0;
break;
}
if (match)
cwc_send_msg(cwc, data, len, 0, 1);
}
/**
*
*/
@ -1924,6 +2106,7 @@ cwc_record_build(cwc_t *cwc)
htsmsg_add_str(e, "deskey", buf);
htsmsg_add_u32(e, "emm", cwc->cwc_emm);
htsmsg_add_u32(e, "emmex", cwc->cwc_emmex);
htsmsg_add_str(e, "comment", cwc->cwc_comment ?: "");
return e;
@ -2010,6 +2193,9 @@ cwc_entry_update(void *opaque, const char *id, htsmsg_t *values, int maycreate)
if(!htsmsg_get_u32(values, "emm", &u32))
cwc->cwc_emm = u32;
if(!htsmsg_get_u32(values, "emmex", &u32))
cwc->cwc_emmex = u32;
cwc->cwc_reconfigure = 1;
if(cwc->cwc_fd != -1)

View file

@ -23,6 +23,6 @@ void cwc_init(void);
void cwc_service_start(struct service *t);
void cwc_emm(uint8_t *data, int len);
void cwc_emm(uint8_t *data, int len, uint16_t caid, void *ca_update_id);
#endif /* CWC_H_ */

View file

@ -265,7 +265,8 @@ th_dvb_mux_instance_t *dvb_mux_create(th_dvb_adapter_t *tda,
const struct dvb_mux_conf *dmc,
uint16_t tsid, const char *network,
const char *logprefix, int enabled,
int initialscan, const char *identifier);
int initialscan, const char *identifier,
dvb_satconf_t *satconf);
void dvb_mux_set_networkname(th_dvb_mux_instance_t *tdmi, const char *name);
@ -295,7 +296,8 @@ const char *dvb_mux_add_by_params(th_dvb_adapter_t *tda,
int polarisation,
const char *satconf);
int dvb_mux_copy(th_dvb_adapter_t *dst, th_dvb_mux_instance_t *tdmi_src);
int dvb_mux_copy(th_dvb_adapter_t *dst, th_dvb_mux_instance_t *tdmi_src,
dvb_satconf_t *satconf);
/**
* DVB Transport (aka DVB service)

View file

@ -458,7 +458,7 @@ dvb_adapter_clone(th_dvb_adapter_t *dst, th_dvb_adapter_t *src)
dvb_mux_destroy(tdmi_dst);
LIST_FOREACH(tdmi_src, &src->tda_muxes, tdmi_adapter_link)
dvb_mux_copy(dst, tdmi_src);
dvb_mux_copy(dst, tdmi_src, NULL);
tda_save(dst);
}

View file

@ -150,7 +150,8 @@ tdmi_compare_conf(int adapter_type,
th_dvb_mux_instance_t *
dvb_mux_create(th_dvb_adapter_t *tda, const struct dvb_mux_conf *dmc,
uint16_t tsid, const char *network, const char *source,
int enabled, int initialscan, const char *identifier)
int enabled, int initialscan, const char *identifier,
dvb_satconf_t *satconf)
{
th_dvb_mux_instance_t *tdmi, *c;
unsigned int hash;
@ -225,8 +226,9 @@ dvb_mux_create(th_dvb_adapter_t *tda, const struct dvb_mux_conf *dmc,
snprintf(buf, sizeof(buf), "%s%d%s%s%s",
tda->tda_identifier, dmc->dmc_fe_params.frequency, qpsktxt,
dmc->dmc_satconf ? "_satconf_" : "",
dmc->dmc_satconf ? dmc->dmc_satconf->sc_id : "");
(satconf || dmc->dmc_satconf) ? "_satconf_" : "",
(satconf ? satconf->sc_id :
(dmc->dmc_satconf ? dmc->dmc_satconf->sc_id : "")));
tdmi->tdmi_identifier = strdup(buf);
} else {
@ -259,6 +261,8 @@ dvb_mux_create(th_dvb_adapter_t *tda, const struct dvb_mux_conf *dmc,
memcpy(&tdmi->tdmi_conf, dmc, sizeof(struct dvb_mux_conf));
if(satconf)
tdmi->tdmi_conf.dmc_satconf = satconf;
if(tdmi->tdmi_conf.dmc_satconf != NULL) {
LIST_INSERT_HEAD(&tdmi->tdmi_conf.dmc_satconf->sc_tdmis,
tdmi, tdmi_satconf_link);
@ -708,7 +712,7 @@ tdmi_create_by_msg(th_dvb_adapter_t *tda, htsmsg_t *m, const char *identifier)
tdmi = dvb_mux_create(tda, &dmc,
tsid, htsmsg_get_str(m, "network"), NULL, enabled, 1,
identifier);
identifier, NULL);
if(tdmi != NULL) {
if((s = htsmsg_get_str(m, "status")) != NULL)
@ -1058,7 +1062,7 @@ dvb_mux_add_by_params(th_dvb_adapter_t *tda,
}
dmc.dmc_polarisation = polarisation;
tdmi = dvb_mux_create(tda, &dmc, 0xffff, NULL, NULL, 1, 1, NULL);
tdmi = dvb_mux_create(tda, &dmc, 0xffff, NULL, NULL, 1, 1, NULL, NULL);
if(tdmi == NULL)
return "Mux already exist";
@ -1071,7 +1075,8 @@ dvb_mux_add_by_params(th_dvb_adapter_t *tda,
*
*/
int
dvb_mux_copy(th_dvb_adapter_t *dst, th_dvb_mux_instance_t *tdmi_src)
dvb_mux_copy(th_dvb_adapter_t *dst, th_dvb_mux_instance_t *tdmi_src,
dvb_satconf_t *satconf)
{
th_dvb_mux_instance_t *tdmi_dst;
service_t *t_src, *t_dst;
@ -1083,7 +1088,7 @@ dvb_mux_copy(th_dvb_adapter_t *dst, th_dvb_mux_instance_t *tdmi_src)
tdmi_src->tdmi_transport_stream_id,
tdmi_src->tdmi_network,
"copy operation", tdmi_src->tdmi_enabled,
1, NULL);
1, NULL, satconf);
if(tdmi_dst == NULL)
return -1; // Already exist

View file

@ -64,9 +64,7 @@ dvb_mux_preconf_add(th_dvb_adapter_t *tda, const struct mux *m, int num,
break;
case FE_QPSK:
#ifdef SYS_DVBS
dmc.dmc_fe_delsys = SYS_DVBS;
#endif
dmc.dmc_fe_delsys = SYS_DVBS;
dmc.dmc_fe_params.u.qpsk.symbol_rate = m->symrate;
dmc.dmc_fe_params.u.qpsk.fec_inner = m->fec;
@ -102,7 +100,7 @@ dvb_mux_preconf_add(th_dvb_adapter_t *tda, const struct mux *m, int num,
dmc.dmc_satconf = dvb_satconf_entry_find(tda, satconf, 0);
dvb_mux_create(tda, &dmc, 0xffff, NULL, source, 1, 1, NULL);
dvb_mux_create(tda, &dmc, 0xffff, NULL, source, 1, 1, NULL, NULL);
m++;
}
}

View file

@ -44,7 +44,7 @@
#define TDT_CRC 0x1
#define TDT_QUICKREQ 0x2
#define TDT_INC_TABLE_HDR 0x4
#define TDT_CA 0x4
static void dvb_table_add_pmt(th_dvb_mux_instance_t *tdmi, int pmt_pid);
@ -214,8 +214,9 @@ dvb_proc_table(th_dvb_mux_instance_t *tdmi, th_dvb_table_t *tdt, uint8_t *sec,
ptr = &sec[3];
if(chkcrc) len -= 4; /* Strip trailing CRC */
if(tdt->tdt_flags & TDT_INC_TABLE_HDR)
ret = tdt->tdt_callback(tdmi, sec, len + 3, tableid, tdt->tdt_opaque);
if(tdt->tdt_flags & TDT_CA)
ret = tdt->tdt_callback((th_dvb_mux_instance_t *)tdt,
sec, len + 3, tableid, tdt->tdt_opaque);
else
ret = tdt->tdt_callback(tdmi, ptr, len, tableid, tdt->tdt_opaque);
@ -412,9 +413,13 @@ dvb_desc_extended_event(uint8_t *ptr, int len,
if ((desclen - strlen(desc)) > 2)
{
/* get description -> append to desc if space left */
strncat(desc, "\n", 1);
strncat(desc, (char*)(items+1),
items[0] > (desclen - strlen(desc)) ? (desclen - strlen(desc)) : items[0]);
if (desc[0] != '\0')
strncat(desc, "\n", 1);
if((r = dvb_get_string_with_len(desc + strlen(desc),
desclen - strlen(desc),
items, (localptr + count) - items,
dvb_default_charset)) < 0)
return -1;
}
items += 1 + items[0];
@ -423,9 +428,13 @@ dvb_desc_extended_event(uint8_t *ptr, int len,
if ((itemlen - strlen(item)) > 2)
{
/* get item -> append to item if space left */
strncat(item, "\n", 1);
strncat(item, (char*)(items+1),
items[0] > (itemlen - strlen(item)) ? (itemlen - strlen(item)) : items[0]);
if (item[0] != '\0')
strncat(item, "\n", 1);
if((r = dvb_get_string_with_len(item + strlen(item),
itemlen - strlen(item),
items, (localptr + count) - items,
dvb_default_charset)) < 0)
return -1;
}
/* go to next item */
@ -824,7 +833,7 @@ static int
dvb_ca_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
uint8_t tableid, void *opaque)
{
cwc_emm(ptr, len);
cwc_emm(ptr, len, (uintptr_t)opaque, (void *)tdmi);
return 0;
}
@ -837,6 +846,7 @@ dvb_cat_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
{
int tag, tlen;
uint16_t pid;
uintptr_t caid;
if((ptr[2] & 1) == 0) {
/* current_next_indicator == next, skip this */
@ -852,14 +862,14 @@ dvb_cat_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
len -= 2;
switch(tag) {
case DVB_DESC_CA:
// caid = ( ptr[0] << 8) | ptr[1];
caid = ( ptr[0] << 8) | ptr[1];
pid = ((ptr[2] & 0x1f) << 8) | ptr[3];
if(pid == 0)
break;
tdt_add(tdmi, NULL, dvb_ca_callback, NULL, "CA",
TDT_INC_TABLE_HDR, pid, NULL);
tdt_add(tdmi, NULL, dvb_ca_callback, (void *)caid, "CA",
TDT_CA, pid, NULL);
break;
default:
@ -942,7 +952,7 @@ dvb_table_cable_delivery(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
dmc.dmc_fe_params.u.qam.fec_inner = fec_tab[ptr[10] & 0x07];
dvb_mux_create(tdmi->tdmi_adapter, &dmc, tsid, NULL,
"automatic mux discovery", 1, 1, NULL);
"automatic mux discovery", 1, 1, NULL, NULL);
return 0;
}
@ -1027,7 +1037,7 @@ dvb_table_sat_delivery(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
#endif
dvb_mux_create(tdmi->tdmi_adapter, &dmc, tsid, NULL,
"automatic mux discovery", 1, 1, NULL);
"automatic mux discovery", 1, 1, NULL, NULL);
return 0;
}

View file

@ -143,14 +143,13 @@ static htsbuf_queue_t *
mk_build_segment_info(mk_mux_t *mkm)
{
htsbuf_queue_t *q = htsbuf_queue_alloc(0);
extern char *htsversion_full;
char app[128];
snprintf(app, sizeof(app), "HTS Tvheadend %s", htsversion_full);
snprintf(app, sizeof(app), "Tvheadend %s", tvheadend_version);
ebml_append_bin(q, 0x73a4, mkm->uuid, sizeof(mkm->uuid));
ebml_append_string(q, 0x7ba9, mkm->title);
ebml_append_string(q, 0x4d80, "HTS Tvheadend Matroska muxer");
ebml_append_string(q, 0x4d80, "Tvheadend Matroska muxer");
ebml_append_string(q, 0x5741, app);
ebml_append_uint(q, 0x2ad7b1, MATROSKA_TIMESCALE);
@ -822,10 +821,13 @@ mk_write_frame_i(mk_mux_t *mkm, mk_track *t, th_pkt_t *pkt)
int skippable = pkt->pkt_frametype == PKT_B_FRAME;
int vkeyframe = SCT_ISVIDEO(t->type) && keyframe;
uint8_t *data;
size_t len;
uint8_t *data = pktbuf_ptr(pkt->pkt_payload);
size_t len = pktbuf_len(pkt->pkt_payload);
const int clusersizemax = 2000000;
if(!data || len <= 0)
return;
if(pts == PTS_UNSET)
// This is our best guess, it might be wrong but... oh well
pts = t->nextpts;
@ -875,10 +877,6 @@ mk_write_frame_i(mk_mux_t *mkm, mk_track *t, th_pkt_t *pkt)
addcue(mkm, pts, t->tracknum);
}
data = pktbuf_ptr(pkt->pkt_payload);
len = pktbuf_len(pkt->pkt_payload);
if(t->type == SCT_AAC || t->type == SCT_MP4A) {
// Skip ADTS header
if(len < 7)

View file

@ -50,7 +50,6 @@ static void *htsp_server;
#define HTSP_PRIV_MASK (ACCESS_STREAMING)
extern const char *htsversion;
extern char *dvr_storage;
LIST_HEAD(htsp_connection_list, htsp_connection);
@ -1047,7 +1046,7 @@ htsp_method_hello(htsp_connection_t *htsp, htsmsg_t *in)
htsmsg_add_u32(r, "htspversion", HTSP_PROTO_VERSION);
htsmsg_add_str(r, "servername", "HTS Tvheadend");
htsmsg_add_str(r, "serverversion", htsversion);
htsmsg_add_str(r, "serverversion", tvheadend_version);
htsmsg_add_bin(r, "challenge", htsp->htsp_challenge, 32);
htsp_update_logname(htsp);
@ -1541,7 +1540,7 @@ const static char frametypearray[PKT_NTYPES] = {
static void
htsp_stream_deliver(htsp_subscription_t *hs, th_pkt_t *pkt)
{
htsmsg_t *m = htsmsg_create_map(), *n;
htsmsg_t *m, *n;
htsp_msg_t *hm;
htsp_connection_t *htsp = hs->hs_htsp;
int64_t ts;
@ -1557,6 +1556,8 @@ htsp_stream_deliver(htsp_subscription_t *hs, th_pkt_t *pkt)
pkt_ref_dec(pkt);
return;
}
m = htsmsg_create_map();
htsmsg_add_str(m, "method", "muxpkt");
htsmsg_add_u32(m, "subscriptionId", hs->hs_sid);

View file

@ -60,8 +60,6 @@
#include "ffdecsa/FFdecsa.h"
int running;
extern const char *htsversion;
extern const char *htsversion_full;
time_t dispatch_clock;
static LIST_HEAD(, gtimer) gtimers;
pthread_mutex_t global_lock;
@ -150,7 +148,7 @@ gtimer_disarm(gtimer_t *gti)
static void
usage(const char *argv0)
{
printf("HTS Tvheadend %s\n", htsversion_full);
printf("HTS Tvheadend %s\n", tvheadend_version);
printf("usage: %s [options]\n", argv0);
printf("\n");
printf(" -a <adapters> Use only DVB adapters specified (csv)\n");
@ -386,7 +384,7 @@ main(int argc, char **argv)
#endif
http_server_init();
webui_init(TVHEADEND_CONTENT_PATH);
webui_init(tvheadend_dataroot());
serviceprobe_init();
@ -433,9 +431,11 @@ main(int argc, char **argv)
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
tvhlog(LOG_NOTICE, "START", "HTS Tvheadend version %s started, "
"running as PID:%d UID:%d GID:%d, settings located in '%s'",
htsversion_full,
getpid(), getuid(), getgid(), hts_settings_get_root());
"running as PID:%d UID:%d GID:%d, settings located in '%s', "
"dataroot: %s",
tvheadend_version,
getpid(), getuid(), getgid(), hts_settings_get_root(),
tvheadend_dataroot() ?: "<Embedded file system>");
if(crash)
abort();

View file

@ -71,6 +71,9 @@ read_audio_specific_config(elementary_stream_t *st, latm_private_t *latm,
else
sr = sri_to_rate(latm->sample_rate_index);
if(sr == 0)
return;
st->es_frame_duration = 1024 * 90000 / sr;
latm->channel_config = read_bits(bs, 4);

View file

@ -307,8 +307,10 @@ psi_desc_ca(service_t *t, const uint8_t *buffer, int size)
}
break;
case 0x4a00://DRECrypt
provid = size < 4 ? 0 : buffer[4];
break;
if (caid != 0x4aee) { // Bulcrypt
provid = size < 4 ? 0 : buffer[4];
break;
}
default:
provid = 0;
break;
@ -834,13 +836,23 @@ static struct strtab caidnametab[] = {
{ "Irdeto", 0x0600 },
{ "Irdeto", 0x0602 },
{ "Irdeto", 0x0604 },
{ "Irdeto", 0x0624 },
{ "Irdeto", 0x0666 },
{ "Jerroldgi", 0x0700 },
{ "Matra", 0x0800 },
{ "NDS", 0x0900 },
{ "Nokia", 0x0A00 },
{ "Conax", 0x0B00 },
{ "NTL", 0x0C00 },
{ "CryptoWorks", 0x0D00 },
{ "CryptoWorks", 0x0D00 },
{ "CryptoWorks", 0x0D01 },
{ "CryptoWorks", 0x0D02 },
{ "CryptoWorks", 0x0D03 },
{ "CryptoWorks", 0x0D05 },
{ "CryptoWorks", 0x0D0F },
{ "CryptoWorks", 0x0D70 },
{ "CryptoWorks ICE", 0x0D96 },
{ "CryptoWorks ICE", 0x0D97 },
{ "PowerVu", 0x0E00 },
{ "Sony", 0x0F00 },
{ "Tandberg", 0x1000 },
@ -866,7 +878,9 @@ static struct strtab caidnametab[] = {
{ "GI", 0x4700 },
{ "Telemann", 0x4800 },
{ "DRECrypt", 0x4ae0 },
{ "DRECrypt2", 0x4ae1 }
{ "DRECrypt2", 0x4ae1 },
{ "Bulcrypt", 0x4aee },
{ "Bulcrypt", 0x5581 },
};
const char *

View file

@ -184,7 +184,7 @@ got_pat(const uint8_t *ptr, size_t len, void *opaque)
len -= 8;
ptr += 8;
if(len < 0)
if(len <= 0)
return;
pthread_mutex_lock(&global_lock);

View file

@ -40,7 +40,6 @@
*/
typedef struct tt_mag {
int ttm_curpage;
int ttm_inactive;
int64_t ttm_current_pts;
uint8_t ttm_lang;
uint8_t ttm_page[23*40 + 1];
@ -397,8 +396,7 @@ tt_decode_line(service_t *t, elementary_stream_t *st, uint8_t *buf)
case 0:
if(ttm->ttm_curpage != 0) {
if(ttm->ttm_inactive == 0)
tt_subtitle_deliver(t, st, ttm);
tt_subtitle_deliver(t, st, ttm);
if(ttm->ttm_curpage == 192)
teletext_rundown_copy(ttp, ttm);
@ -429,11 +427,9 @@ tt_decode_line(service_t *t, elementary_stream_t *st, uint8_t *buf)
teletext_rundown_scan(t, ttp);
ttm->ttm_current_pts = t->s_current_pts;
ttm->ttm_inactive = 0;
break;
case 1 ... 23:
ttm->ttm_inactive = 0;
for(i = 0; i < 40; i++) {
c = buf[i + 2] & 0x7f;
ttm->ttm_page[i + 40 * (line - 1)] = c;
@ -446,30 +442,6 @@ tt_decode_line(service_t *t, elementary_stream_t *st, uint8_t *buf)
}
/**
*
*/
static void
teletext_scan_stream(service_t *t, elementary_stream_t *st)
{
tt_private_t *ttp = st->es_priv;
tt_mag_t *ttm;
int i;
if(ttp == NULL)
return;
for(i = 0; i < 8; i++) {
ttm = &ttp->ttp_mags[i];
ttm->ttm_inactive++;
if(ttm->ttm_inactive == 2) {
tt_subtitle_deliver(t, st, ttm);
}
}
}
/**
*
*/
@ -489,7 +461,6 @@ teletext_input(service_t *t, elementary_stream_t *st, const uint8_t *tsb)
}
x += 46;
}
teletext_scan_stream(t, st);
}

View file

@ -220,9 +220,6 @@ callback(struct dl_phdr_info *info, size_t size, void *data)
}
extern const char *htsversion_full;
void
trap_init(const char *ver)
{
@ -259,7 +256,7 @@ trap_init(const char *ver)
"PRG: %s (%s) "
"[%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x] "
"CWD: %s ", ver, htsversion_full,
"CWD: %s ", ver, tvheadend_version,
digest[0],
digest[1],
digest[2],

View file

@ -142,8 +142,6 @@ ts_extract_pcr(service_t *t, elementary_stream_t *st, const uint8_t *tsb,
pcr |= (uint64_t)tsb[9] << 1;
pcr |= ((uint64_t)tsb[10] >> 7) & 0x01;
pcr = pcr;
if(pcrp != NULL)
*pcrp = pcr;

View file

@ -15,7 +15,6 @@
* 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 TVHEADEND_H
#define TVHEADEND_H
@ -34,6 +33,9 @@
#include "redblack.h"
extern const char *tvheadend_version;
extern const char *tvheadend_dataroot();
#define PTS_UNSET INT64_C(0x8000000000000000)
extern pthread_mutex_t global_lock;
@ -400,7 +402,7 @@ extern void scopedunlock(pthread_mutex_t **mtxp);
#define scopedlock(mtx) \
pthread_mutex_t *scopedlock ## __LINE__ \
__attribute__((cleanup(scopedunlock))) = mtx; \
pthread_mutex_lock(mtx);
pthread_mutex_lock(scopedlock ## __LINE__);
#define scopedgloballock() scopedlock(&global_lock)

View file

@ -1,9 +1,4 @@
#include "buildversion.h"
#include "config.h"
#ifdef HTS_RELEASE_TAG
const char *htsversion=HTS_RELEASE_TAG;
const char *htsversion_full=HTS_RELEASE_TAG " (" HTS_VERSION ")";
#else
const char *htsversion=HTS_VERSION;
const char *htsversion_full=HTS_VERSION;
#endif
const char *tvheadend_version = BUILD_VERSION;

View file

@ -43,9 +43,6 @@
#include "epg.h"
#include "iptv_input.h"
extern const char *htsversion;
extern const char *htsversion_full;
static void
extjs_load(htsbuf_queue_t *hq, const char *script)
{
@ -166,7 +163,7 @@ extjs_root(http_connection_t *hc, const char *remain, void *opaque)
"<body>\n"
"<div id=\"systemlog\"></div>\n"
"</body></html>\n",
htsversion);
tvheadend_version);
http_output_html(hc);
return 0;
}
@ -185,7 +182,7 @@ page_about(http_connection_t *hc, const char *remain, void *opaque)
"<div class=\"about-title\">"
"HTS Tvheadend %s"
"</div><br>"
"&copy; 2006 - 2010 Andreas \303\226man, et al.<br><br>"
"&copy; 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>"
@ -197,8 +194,8 @@ page_about(http_connection_t *hc, const char *remain, void *opaque)
"<br><br>"
"Build: %s"
"</center>",
htsversion,
htsversion_full);
tvheadend_version,
tvheadend_version);
http_output_html(hc);
return 0;
@ -634,6 +631,9 @@ extjs_confignames(http_connection_t *hc, const char *remain, void *opaque)
out = htsmsg_create_map();
array = htsmsg_create_list();
if (http_access_verify(hc, ACCESS_RECORDER_ALL))
goto skip;
LIST_FOREACH(cfg, &dvrconfigs, config_link) {
e = htsmsg_create_map();
htsmsg_add_str(e, "identifier", cfg->dvr_config_name);
@ -644,6 +644,7 @@ extjs_confignames(http_connection_t *hc, const char *remain, void *opaque)
htsmsg_add_msg(array, NULL, e);
}
skip:
htsmsg_add_msg(out, "entries", array);
} else {
@ -890,6 +891,19 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
return HTTP_STATUS_BAD_REQUEST;
}
if (http_access_verify(hc, ACCESS_RECORDER_ALL)) {
config_name = NULL;
LIST_FOREACH(cfg, &dvrconfigs, config_link) {
if (cfg->dvr_config_name && hc->hc_username &&
strcmp(cfg->dvr_config_name, hc->hc_username) == 0) {
config_name = cfg->dvr_config_name;
break;
}
}
if (config_name == NULL && hc->hc_username)
tvhlog(LOG_INFO,"dvr","User '%s' has no dvr config with identical name, using default...", hc->hc_username);
}
dvr_entry_create_by_event(config_name,
e, hc->hc_representative, NULL, DVR_PRIO_NORMAL);
#endif
@ -961,6 +975,19 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
if(stop < start)
stop += 86400;
if (http_access_verify(hc, ACCESS_RECORDER_ALL)) {
config_name = NULL;
LIST_FOREACH(cfg, &dvrconfigs, config_link) {
if (cfg->dvr_config_name && hc->hc_username &&
strcmp(cfg->dvr_config_name, hc->hc_username) == 0) {
config_name = cfg->dvr_config_name;
break;
}
}
if (config_name == NULL && hc->hc_username)
tvhlog(LOG_INFO,"dvr","User '%s' has no dvr config with identical name, using default...", hc->hc_username);
}
dvr_entry_create(config_name,
ch, start, stop, title, NULL, hc->hc_representative,
NULL, NULL, 0, dvr_pri2val(pri));

View file

@ -454,11 +454,14 @@ extjs_dvbsatconf(http_connection_t *hc, const char *remain, void *opaque)
htsbuf_queue_t *hq = &hc->hc_reply;
th_dvb_adapter_t *tda;
htsmsg_t *out;
const char *adapter = http_arg_get(&hc->hc_req_args, "adapter");
pthread_mutex_lock(&global_lock);
if(remain == NULL ||
(tda = dvb_adapter_find_by_identifier(remain)) == NULL) {
if((remain == NULL ||
(tda = dvb_adapter_find_by_identifier(remain)) == NULL) &&
(adapter == NULL ||
(tda = dvb_adapter_find_by_identifier(adapter)) == NULL)) {
pthread_mutex_unlock(&global_lock);
return 404;
}
@ -582,9 +585,11 @@ extjs_dvb_copymux(http_connection_t *hc, const char *remain, void *opaque)
th_dvb_adapter_t *tda;
htsmsg_t *in;
const char *entries = http_arg_get(&hc->hc_req_args, "entries");
const char *satconf = http_arg_get(&hc->hc_req_args, "satconf");
const char *id;
htsmsg_field_t *f;
th_dvb_mux_instance_t *tdmi;
dvb_satconf_t *sc = NULL;
in = entries != NULL ? htsmsg_json_deserialize(entries) : NULL;
@ -599,13 +604,20 @@ extjs_dvb_copymux(http_connection_t *hc, const char *remain, void *opaque)
return 404;
}
if (satconf) {
sc = dvb_satconf_entry_find(tda, satconf, 0);
if (sc == NULL) {
pthread_mutex_unlock(&global_lock);
return 404;
}
}
TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
if((id = htsmsg_field_get_string(f)) != NULL &&
(tdmi = dvb_mux_find_by_identifier(id)) != NULL &&
tda != tdmi->tdmi_adapter) {
if(dvb_mux_copy(tda, tdmi)) {
if(dvb_mux_copy(tda, tdmi, sc)) {
char buf[100];
dvb_mux_nicename(buf, sizeof(buf), tdmi);

View file

@ -36,7 +36,6 @@
#endif
extern char tvh_binshasum[20];
extern char *htsversion_full;
int page_statedump(http_connection_t *hc, const char *remain, void *opaque);
@ -159,7 +158,7 @@ page_statedump(http_connection_t *hc, const char *remain, void *opaque)
htsbuf_qprintf(hq, "Tvheadend %s Binary SHA1: "
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
htsversion_full,
tvheadend_version,
tvh_binshasum[0],
tvh_binshasum[1],
tvh_binshasum[2],

View file

@ -20,6 +20,12 @@ tvheadend.acleditor = function() {
width: 100
});
var dvrallcfgColumn = new Ext.grid.CheckColumn({
header: "All Configs (VR)",
dataIndex: 'dvrallcfg',
width: 100
});
var webuiColumn = new Ext.grid.CheckColumn({
header: "Web Interface",
dataIndex: 'webui',
@ -52,6 +58,7 @@ tvheadend.acleditor = function() {
},
streamingColumn,
dvrColumn,
dvrallcfgColumn,
webuiColumn,
adminColumn,
{
@ -63,14 +70,14 @@ tvheadend.acleditor = function() {
]);
var UserRecord = Ext.data.Record.create([
'enabled','streaming','dvr','admin','webui','username',
'enabled','streaming','dvr','dvrallcfg','admin','webui','username',
'prefix','password','comment'
]);
return new tvheadend.tableEditor('Access control', 'accesscontrol', cm,
UserRecord,
[enabledColumn, streamingColumn,
dvrColumn, webuiColumn,
dvrColumn, dvrallcfgColumn, webuiColumn,
adminColumn],
null,
'config_access.html', 'group');

View file

@ -14,6 +14,12 @@ tvheadend.cwceditor = function() {
width: 100
});
var emmexColumn = new Ext.grid.CheckColumn({
header: "Update One",
dataIndex: 'emmex',
width: 100
});
function setMetaAttr(meta, record){
var enabled = record.get('enabled');
if(!enabled) return;
@ -72,6 +78,7 @@ tvheadend.cwceditor = function() {
editor: new fm.TextField({allowBlank: false})
},
emmColumn,
emmexColumn,
{
header: "Comment",
dataIndex: 'comment',
@ -86,7 +93,7 @@ tvheadend.cwceditor = function() {
var rec = Ext.data.Record.create([
'enabled', 'connected', 'hostname', 'port', 'username',
'password', 'deskey', 'emm', 'comment'
'password', 'deskey', 'emm', 'emmex', 'comment'
]);
var store = new Ext.data.JsonStore({
@ -99,7 +106,7 @@ tvheadend.cwceditor = function() {
});
var grid = new tvheadend.tableEditor('Code Word Client', 'cwc', cm, rec,
[enabledColumn, emmColumn], store,
[enabledColumn, emmColumn, emmexColumn], store,
'config_cwc.html', 'key');
tvheadend.comet.on('cwcStatus', function(msg) {

View file

@ -169,14 +169,24 @@ tvheadend.dvb_muxes = function(adapterData, satConfStore) {
var selectedKeys = grid.selModel.selections.keys;
var target = panel.getForm().getValues('targetID').targetID;
if(adapterData.satConf) {
var satconf = panel.getForm().getValues('targetSatConfID').targetSatConfID;
var mparams = {
entries:Ext.encode(selectedKeys),
satconf:satconf
};
} else {
var mparams = {
entries:Ext.encode(selectedKeys)
};
}
Ext.Ajax.request({
url: "dvb/copymux/" + target,
params: {
entries:Ext.encode(selectedKeys)
},
failure:function(response,options) {
params: mparams,
failure:function(response,options) {
Ext.MessageBox.alert('Server Error','Unable to copy');
},
},
success: function() {
win.close();
}
@ -191,30 +201,71 @@ tvheadend.dvb_muxes = function(adapterData, satConfStore) {
'name'],
baseParams: {sibling: adapterId}
});
if(adapterData.satConf) {
targetSatConfStore = new Ext.data.JsonStore({
root:'entries',
id: 'identifier',
url:'dvb/satconf',
fields: ['identifier',
'name'],
baseParams: {adapter: adapterId}
});
satConf = new Ext.form.ComboBox({
store: targetSatConfStore,
fieldLabel: 'Target Satellite config',
name: 'targetsatconf',
hiddenName: 'targetSatConfID',
editable: false,
allowBlank: false,
triggerAction: 'all',
mode: 'remote',
displayField:'name',
valueField:'identifier',
emptyText: 'Select target adapter first...'
});
} else {
satConf = null;
}
var mitems = [
new Ext.form.ComboBox({
store: targetStore,
fieldLabel: 'Target adapter',
name: 'targetadapter',
hiddenName: 'targetID',
editable: false,
allowBlank: false,
triggerAction: 'all',
mode: 'remote',
displayField:'name',
valueField:'identifier',
emptyText: 'Select target adapter...',
listeners: {
'select': function(combo, value) {
if (satConf) {
satConf.emptyText = 'Select satellite configuration...';
satConf.clearValue();
targetSatConfStore.baseParams = {adapter: combo.value};
targetSatConfStore.load();
satConf.focus();
satConf.expand();
}
}
}
}),
];
if (satConf)
mitems.push(satConf);
var panel = new Ext.FormPanel({
frame:true,
border:true,
bodyStyle:'padding:5px',
labelAlign: 'right',
labelWidth: 110,
labelWidth: 150,
defaultType: 'textfield',
items: [
new Ext.form.ComboBox({
store: targetStore,
fieldLabel: 'Target adapter',
name: 'targetadapter',
hiddenName: 'targetID',
editable: false,
allowBlank: false,
triggerAction: 'all',
mode: 'remote',
displayField:'name',
valueField:'identifier',
emptyText: 'Select target adapter...'
})
],
items: mitems,
buttons: [{
text: 'Copy',
handler: doCopy
@ -225,7 +276,7 @@ tvheadend.dvb_muxes = function(adapterData, satConfStore) {
title: 'Copy multiplex configuration',
layout: 'fit',
width: 500,
height: 120,
height: 150,
modal: true,
plain: true,
items: panel

View file

@ -156,10 +156,12 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq, th_subscription_t
//Check socket status
getsockopt(hc->hc_fd, SOL_SOCKET, SO_ERROR, (char *)&err, &errlen);
//Abort upon socket error, or after 20 seconds of silence
if(err || timeouts >= 20){
run = 0;
if(err) {
tvhlog(LOG_DEBUG, "webui", "Client hung up, exit streaming");
run = 0;
}else if(timeouts >= 20) {
tvhlog(LOG_WARNING, "webui", "Timeout waiting for packets");
run = 0;
}
}
pthread_mutex_unlock(&sq->sq_mutex);
@ -168,13 +170,13 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq, th_subscription_t
timeouts = 0; //Reset timeout counter
TAILQ_REMOVE(&sq->sq_queue, sm, sm_link);
pthread_mutex_unlock(&sq->sq_mutex);
switch(sm->sm_type) {
case SMT_PACKET: {
if(!mkm)
break;
pkt_ref_inc(sm->sm_data);
run = !mk_mux_write_pkt(mkm, sm->sm_data);
sm->sm_data = NULL;
@ -221,7 +223,6 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq, th_subscription_t
break;
}
streaming_msg_free(sm);
pthread_mutex_unlock(&sq->sq_mutex);
}
if(mkm)
@ -378,11 +379,12 @@ http_stream_service(http_connection_t *hc, service_t *service)
pthread_mutex_unlock(&global_lock);
http_stream_run(hc, &sq, s);
pthread_mutex_lock(&global_lock);
subscription_unsubscribe(s);
pthread_mutex_unlock(&global_lock);
if(s) {
http_stream_run(hc, &sq, s);
pthread_mutex_lock(&global_lock);
subscription_unsubscribe(s);
pthread_mutex_unlock(&global_lock);
}
globalheaders_destroy(gh);
tsfix_destroy(tsfix);
@ -413,11 +415,12 @@ http_stream_channel(http_connection_t *hc, channel_t *ch)
0);
pthread_mutex_unlock(&global_lock);
http_stream_run(hc, &sq, s);
pthread_mutex_lock(&global_lock);
subscription_unsubscribe(s);
pthread_mutex_unlock(&global_lock);
if(s) {
http_stream_run(hc, &sq, s);
pthread_mutex_lock(&global_lock);
subscription_unsubscribe(s);
pthread_mutex_unlock(&global_lock);
}
globalheaders_destroy(gh);
tsfix_destroy(tsfix);
@ -656,10 +659,9 @@ webui_static_content(const char *content_path, const char *http_path,
}
tvhlog(LOG_ERR, "webui",
"No source path providing HTTP content: \"%s\"."
"No source path providing HTTP content: \"%s\". "
"Checked in \"%s\" and in the binary's embedded file system. "
"If you need to move or install the binary, "
"reconfigure with --release", http_path, content_path);
, http_path, content_path);
}

View file

@ -17,8 +17,6 @@ BUILDDIR=build.${PLATFORM}
DEFAULT_THEME="new"
RELEASE=no
RELEASENAME=`head -n1 ${TOPDIR}/ChangeLog | awk '{print $2}' | sed s/\(// | sed s/\)//`
CONFIG_LIST="
cwc
avahi
@ -125,12 +123,6 @@ EOF
finalize() {
if [ ${RELEASE} = yes ]; then
echo Release build: ${RELEASENAME}
echo >>${CONFIG_H} "#define TVHEADEND_RELEASE_TAG \"${RELEASENAME}\""
fi
cat >> ${CONFIG_MAK} << EOF
OSENV=${OSENV}
LDFLAGS_cfg += -lm

View file

@ -0,0 +1,4 @@
const char *tvheadend_dataroot(void)
{
return (void *)0;
}

View file

@ -0,0 +1,7 @@
#include "config.h"
const char *tvheadend_dataroot(void)
{
return TVHEADEND_DATADIR;
}

4
support/dataroot/wd.c Normal file
View file

@ -0,0 +1,4 @@
const char *tvheadend_dataroot(void)
{
return "./";
}

8
support/getver.sh Executable file
View file

@ -0,0 +1,8 @@
#!/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

View file

@ -1,22 +1,19 @@
MAN = man/tvheadend.1
ICON = support/gnome/tvheadend.svg
INSTBIN= ${DESTDIR}${INSTALLPREFIX}/bin
INSTMAN= ${DESTDIR}${INSTALLPREFIX}/share/man/man1
INSTDBG= ${DESTDIR}${INSTALLPREFIX}/lib/debug/bin
MAN=man/tvheadend.1
INSTICON= ${DESTDIR}$(prefix)/share/icons/hicolor/scalable/apps
install: ${PROG} ${MAN}
mkdir -p ${INSTBIN}
install -T ${PROG} ${INSTBIN}/tvheadend
mkdir -p ${INSTMAN}
install ${MAN} ${INSTMAN}
install-debug: ${PROG}
mkdir -p ${INSTDBG}
objcopy --only-keep-debug ${INSTBIN}/tvheadend ${INSTDBG}/tvheadend.debug
strip -g ${INSTBIN}/tvheadend
objcopy --add-gnu-debuglink=${INSTDBG}/tvheadend.debug ${INSTBIN}/tvheadend
install: ${PROG}.datadir ${MAN}
install -D ${PROG}.datadir ${bindir}/tvheadend
install -D ${MAN} ${mandir}/tvheadend.1
for bundle in ${BUNDLES}; do \
mkdir -p ${datadir}/$$bundle ;\
cp -r $$bundle/* ${datadir}/$$bundle ;\
done
uninstall:
rm -f ${INSTBIN}/tvheadend
rm -f ${INSTDBG}/tvheadend.debug
rm -f ${INSTMAN}/tvheadend.1
rm -f ${bindir)/tvheadend
rm -f ${mandir)/tvheadend.1

View file

@ -1,23 +1,11 @@
#!/bin/sh
# check for SVN revision number
revision=`cd "$1" && LC_ALL=C svn info 2> /dev/null | grep Revision | cut -d' ' -f2`
test $revision || revision=`cd "$1" && grep revision .svn/entries 2>/dev/null | cut -d '"' -f2`
test $revision || revision=`cd "$1" && sed -n -e '/^dir$/{n;p;q}' .svn/entries 2>/dev/null`
test $revision && revision=SVN-r$revision
revision=`$1/support/getver.sh`
# check for git short hash
if ! test $revision; then
revision=`cd "$1" && git log -1 --pretty=format:%h`
test $revision && revision=git-$revision
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
# check for debian changelog
if ! test $revision; then
revision=`cd "$1" && cat debian/changelog |head -1|cut -f2 -d' '|sed s/\(//|sed s/\)//`
fi
# no version number found
test $revision || revision=UNKNOWN
echo $revision