mirror of
https://github.com/vdr-projects/vdr.git
synced 2025-03-01 10:50:46 +00:00
Version 1.7.1
- Adapted the tuning code to the new DVBFE_SET_DELSYS API (thanks to Reinhard Nissl). VDR now uses the driver from http://jusst.de/hg/multiproto_plus. - Updated the Italian OSD texts (thanks to Diego Pierotto). - Removed obsolete $(NCURSESLIB) from the Makefile. - Implemented handling the standard component descriptor for AC3 (stream=4), as it will soon be used by the German ARD channels (thanks to Michael Pennewiß for advance information about this change). The previously used "Premiere pseudo standard" (stream=2, type=5) still works, but has apparently been wrongfully used by broadcasters from the beginning. - Added missing description of the 'S' channel parameter to vdr.5 (reported by Reinhard Nissl). - The SVDRP signon message now indicates the character encoding in use, as in "220 video SVDRP VideoDiskRecorder 1.7.1; Fri May 2 16:17:10 2008; ISO-8859-1". This may be useful for instance for external tools that provide EPG data, so that they can correctly encode the strings. - No longer calling FcFini() to avoid problems with older (broken) versions of fontconfig (suggested by Edgar Toernig). - Removed the compile time option VFAT to allow users of precompiled binary distributions to have full control over whether or not to use the --vfat option at runtime (suggested by Michael Nork). - First step towards switching to TS (Transport Stream) as recording format: + The new function cDevice::PlayTs() is used to play TS packets. + The new functions cDevice::PlayTsVideo() and cDevice::PlayTsAudio() are used to play video and audio TS packets, respectively. + The new function cAudio::PlayTs() is used to play audio TS packets. + The new class cPatPmtGenerator is used to generate a PAT/PMT pair that precedes the TS data in Transfer Mode. + The new class cPatPmtParser is used by cDevice to parse the PAT/PMT data in a TS in order to find out which streams it contains. + The new class cTsToPes is used to convert TS packets to a PES packet. + cTransfer no longer uses cRemux, and doesn't run a separate thread any more. It just generates a PAT/PMT and sends all received TS packets to the primary device's PlayTs(). + Live subtitle display no longer uses a ring buffer and separate thread. + cPesAssembler has been removed. Old VDR recordings only contain complete PES packets. + Since a TS needs to have a PAT/PMT, which requires the video stream type to be explicitly given, the format of the VPID field in the channels.conf file and the SVDRP commands NEWC/MODC/LSTC has been extended. The video stream type now follows the VPID and optional PPID, separated by an '=' sign. - Updated the sources.conf file (thanks to Oleg Roitburd). - Fixed a possible integer overflow in GetAbsTime() (thanks to Alexander Rieger). - Fixed a problem with calling isyslog() from within the SignalHandler() (thanks to Udo Richter). - Replaced the Finnish language code "smi" with "suo" (thanks to Rolf Ahrenberg). - Fixed wrong value for TableIdBAT in libsi/si.h (thanks to Winfried Köhler). - Errors in config files no longer keep VDR from starting. - Removed unneeded include files <linux/dvb/dmx.h> und <time.h> from remux.h (reported by Tobias Grimm).
This commit is contained in:
parent
771986b89f
commit
c848ab793a
20
CONTRIBUTORS
20
CONTRIBUTORS
@ -1054,6 +1054,7 @@ Rolf Ahrenberg <rahrenbe@cc.hut.fi>
|
|||||||
for fixing displaying the free disk space when entering the recordings menu where
|
for fixing displaying the free disk space when entering the recordings menu where
|
||||||
the last replayed recording was in a subdirectory, and pressing Back
|
the last replayed recording was in a subdirectory, and pressing Back
|
||||||
for setting the thread name, so that it can be seen in 'top -H'
|
for setting the thread name, so that it can be seen in 'top -H'
|
||||||
|
for replacing the Finnish language code "smi" with "suo"
|
||||||
|
|
||||||
Ralf Klueber <ralf.klueber@vodafone.com>
|
Ralf Klueber <ralf.klueber@vodafone.com>
|
||||||
for reporting a bug in cutting a recording if there is only a single editing mark
|
for reporting a bug in cutting a recording if there is only a single editing mark
|
||||||
@ -1180,6 +1181,8 @@ Reinhard Nissl <rnissl@gmx.de>
|
|||||||
early stage of channel switching
|
early stage of channel switching
|
||||||
for fixing displaying transponder data when it is modified
|
for fixing displaying transponder data when it is modified
|
||||||
for fixing handling the counter in detection of pre 1.3.19 PS data
|
for fixing handling the counter in detection of pre 1.3.19 PS data
|
||||||
|
for adapting the tuning code to the new DVBFE_SET_DELSYS API
|
||||||
|
for reporting the missing description of the 'S' channel parameter in vdr.5
|
||||||
|
|
||||||
Richard Robson <richard_robson@beeb.net>
|
Richard Robson <richard_robson@beeb.net>
|
||||||
for reporting freezing replay if a timer starts while in Transfer Mode from the
|
for reporting freezing replay if a timer starts while in Transfer Mode from the
|
||||||
@ -1328,6 +1331,8 @@ Marc Hoppe <MarcHoppe@gmx.de>
|
|||||||
|
|
||||||
Michael Pennewiß <M.Pennewiss@ARD-Digital.de>
|
Michael Pennewiß <M.Pennewiss@ARD-Digital.de>
|
||||||
for pointing out that an empty EPG event means there is currently no running event
|
for pointing out that an empty EPG event means there is currently no running event
|
||||||
|
for advance information about the use of the standard component descriptor for AC3
|
||||||
|
(stream=4) on the German ARD channels
|
||||||
|
|
||||||
Marcus Mönnig <minibbjd@gmx.de>
|
Marcus Mönnig <minibbjd@gmx.de>
|
||||||
for adding some 3-letter language codes
|
for adding some 3-letter language codes
|
||||||
@ -1581,6 +1586,7 @@ Udo Richter <udo_richter@gmx.de>
|
|||||||
for making housekeeping wait for a while after a replay has ended
|
for making housekeeping wait for a while after a replay has ended
|
||||||
for fixing error handling in cCuttingThread::Action()
|
for fixing error handling in cCuttingThread::Action()
|
||||||
for suppressing the automatic shutdown if the remote control is currently disabled
|
for suppressing the automatic shutdown if the remote control is currently disabled
|
||||||
|
for fixing a problem with calling isyslog() from within the SignalHandler()
|
||||||
|
|
||||||
Sven Kreiensen <svenk@kammer.uni-hannover.de>
|
Sven Kreiensen <svenk@kammer.uni-hannover.de>
|
||||||
for his help in keeping 'channels.conf.terr' up to date
|
for his help in keeping 'channels.conf.terr' up to date
|
||||||
@ -1898,6 +1904,7 @@ Alexander Rieger <Alexander.Rieger@inka.de>
|
|||||||
for fixing cTimer::operator=() in case a cTimer variable is assigned to itself
|
for fixing cTimer::operator=() in case a cTimer variable is assigned to itself
|
||||||
for making the list of tracks given in cStatus::SetAudioTrack() NULL terminated
|
for making the list of tracks given in cStatus::SetAudioTrack() NULL terminated
|
||||||
for fixing handling kLeft in the calls to cStatus::MsgOsdTextItem()
|
for fixing handling kLeft in the calls to cStatus::MsgOsdTextItem()
|
||||||
|
for fixing a possible integer overflow in GetAbsTime()
|
||||||
|
|
||||||
Philip Prindeville <philipp_subx@redfish-solutions.com>
|
Philip Prindeville <philipp_subx@redfish-solutions.com>
|
||||||
for updates to 'sources.conf'
|
for updates to 'sources.conf'
|
||||||
@ -2119,6 +2126,7 @@ Tobias Grimm <tobias.grimm@e-tobi.net>
|
|||||||
for making the non-breaking space symbol be rendered as a blank
|
for making the non-breaking space symbol be rendered as a blank
|
||||||
for fixing a signed character used as index in cBase64Encoder::NextLine()
|
for fixing a signed character used as index in cBase64Encoder::NextLine()
|
||||||
for fixing formatting the name section in the VDR man pages
|
for fixing formatting the name section in the VDR man pages
|
||||||
|
for reporting unneeded include files <linux/dvb/dmx.h> und <time.h> in remux.h
|
||||||
|
|
||||||
Helge Lenz <h.lenz@gmx.de>
|
Helge Lenz <h.lenz@gmx.de>
|
||||||
for reporting a bug in setting the 'Delta' parameter when calling the shutdown
|
for reporting a bug in setting the 'Delta' parameter when calling the shutdown
|
||||||
@ -2355,3 +2363,15 @@ Adrian Caval <anrxc@sysphere.org>
|
|||||||
|
|
||||||
Nan Feng <nfgx@21cn.com>
|
Nan Feng <nfgx@21cn.com>
|
||||||
for translating OSD texts to the Chinese language
|
for translating OSD texts to the Chinese language
|
||||||
|
|
||||||
|
Edgar Toernig <froese@gmx.de>
|
||||||
|
for suggesting to not call FcFini() to avoid problems with older (broken) versions
|
||||||
|
of fontconfig
|
||||||
|
|
||||||
|
Michael Nork <mnork0@gmx.net>
|
||||||
|
for suggesting to remove the compile time option VFAT to allow users of precompiled
|
||||||
|
binary distributions to have full control over whether or not to use the --vfat
|
||||||
|
option at runtime
|
||||||
|
|
||||||
|
Winfried Köhler <w_koehl@gmx.de>
|
||||||
|
for fixing wrong value for TableIdBAT in libsi/si.h
|
||||||
|
70
HISTORY
70
HISTORY
@ -5761,3 +5761,73 @@ Video Disk Recorder Revision History
|
|||||||
Andreas Mair).
|
Andreas Mair).
|
||||||
- Increased the time between checking the CAM status to 500ms to avoid problems
|
- Increased the time between checking the CAM status to 500ms to avoid problems
|
||||||
with some CAMs (reported by Arthur Konovalov).
|
with some CAMs (reported by Arthur Konovalov).
|
||||||
|
|
||||||
|
2008-09-06: Version 1.7.1
|
||||||
|
|
||||||
|
- Adapted the tuning code to the new DVBFE_SET_DELSYS API (thanks to Reinhard Nissl).
|
||||||
|
VDR now uses the driver from http://jusst.de/hg/multiproto_plus.
|
||||||
|
- Updated the Italian OSD texts (thanks to Diego Pierotto).
|
||||||
|
- Removed obsolete $(NCURSESLIB) from the Makefile.
|
||||||
|
- Implemented handling the standard component descriptor for AC3 (stream=4), as it
|
||||||
|
will soon be used by the German ARD channels (thanks to Michael Pennewiß for
|
||||||
|
advance information about this change). The previously used "Premiere pseudo
|
||||||
|
standard" (stream=2, type=5) still works, but has apparently been wrongfully used
|
||||||
|
by broadcasters from the beginning.
|
||||||
|
- Added missing description of the 'S' channel parameter to vdr.5 (reported by
|
||||||
|
Reinhard Nissl).
|
||||||
|
- The SVDRP signon message now indicates the character encoding in use, as in
|
||||||
|
"220 video SVDRP VideoDiskRecorder 1.7.1; Fri May 2 16:17:10 2008; ISO-8859-1".
|
||||||
|
This may be useful for instance for external tools that provide EPG data, so that
|
||||||
|
they can correctly encode the strings.
|
||||||
|
- No longer calling FcFini() to avoid problems with older (broken) versions of
|
||||||
|
fontconfig (suggested by Edgar Toernig).
|
||||||
|
- Removed the compile time option VFAT to allow users of precompiled binary
|
||||||
|
distributions to have full control over whether or not to use the --vfat option
|
||||||
|
at runtime (suggested by Michael Nork).
|
||||||
|
- First step towards switching to TS (Transport Stream) as recording format:
|
||||||
|
+ The new function cDevice::PlayTs() is used to play TS packets.
|
||||||
|
+ The new functions cDevice::PlayTsVideo() and cDevice::PlayTsAudio()
|
||||||
|
are used to play video and audio TS packets, respectively.
|
||||||
|
+ The new function cAudio::PlayTs() is used to play audio TS packets.
|
||||||
|
+ The new class cPatPmtGenerator is used to generate a PAT/PMT pair that precedes
|
||||||
|
the TS data in Transfer Mode.
|
||||||
|
+ The new class cPatPmtParser is used by cDevice to parse the PAT/PMT data in a
|
||||||
|
TS in order to find out which streams it contains.
|
||||||
|
+ The new class cTsToPes is used to convert TS packets to a PES packet.
|
||||||
|
+ cTransfer no longer uses cRemux, and doesn't run a separate thread any more.
|
||||||
|
It just generates a PAT/PMT and sends all received TS packets to the primary
|
||||||
|
device's PlayTs().
|
||||||
|
+ Live subtitle display no longer uses a ring buffer and separate thread.
|
||||||
|
+ cPesAssembler has been removed. Old VDR recordings only contain complete PES
|
||||||
|
packets.
|
||||||
|
+ Since a TS needs to have a PAT/PMT, which requires the video stream type to
|
||||||
|
be explicitly given, the format of the VPID field in the channels.conf file
|
||||||
|
and the SVDRP commands NEWC/MODC/LSTC has been extended. The video stream type
|
||||||
|
now follows the VPID and optional PPID, separated by an '=' sign.
|
||||||
|
- Updated the sources.conf file (thanks to Oleg Roitburd).
|
||||||
|
- Fixed a possible integer overflow in GetAbsTime() (thanks to Alexander Rieger).
|
||||||
|
- Fixed a problem with calling isyslog() from within the SignalHandler() (thanks
|
||||||
|
to Udo Richter).
|
||||||
|
- Replaced the Finnish language code "smi" with "suo" (thanks to Rolf Ahrenberg).
|
||||||
|
- Fixed wrong value for TableIdBAT in libsi/si.h (thanks to Winfried Köhler).
|
||||||
|
- Errors in config files no longer keep VDR from starting.
|
||||||
|
- Removed unneeded include files <linux/dvb/dmx.h> und <time.h> from remux.h
|
||||||
|
(reported by Tobias Grimm).
|
||||||
|
|
||||||
|
2008-09-06: Version 1.6.0-2
|
||||||
|
|
||||||
|
- Updated the Italian OSD texts (thanks to Diego Pierotto).
|
||||||
|
- The SVDRP signon message now indicates the character encoding in use, as in
|
||||||
|
"220 video SVDRP VideoDiskRecorder 1.7.1; Fri May 2 16:17:10 2008; ISO-8859-1".
|
||||||
|
This may be useful for instance for external tools that provide EPG data, so that
|
||||||
|
they can correctly encode the strings.
|
||||||
|
- No longer calling FcFini() to avoid problems with older (broken) versions of
|
||||||
|
fontconfig (suggested by Edgar Toernig).
|
||||||
|
- Updated the sources.conf file (thanks to Oleg Roitburd).
|
||||||
|
- Fixed a possible integer overflow in GetAbsTime() (thanks to Alexander Rieger).
|
||||||
|
- Fixed a problem with calling isyslog() from within the SignalHandler() (thanks
|
||||||
|
to Udo Richter).
|
||||||
|
- Replaced the Finnish language code "smi" with "suo" (thanks to Rolf Ahrenberg).
|
||||||
|
- Fixed wrong value for TableIdBAT in libsi/si.h (thanks to Winfried Köhler).
|
||||||
|
- Removed unneeded include files <linux/dvb/dmx.h> und <time.h> from remux.h
|
||||||
|
(reported by Tobias Grimm).
|
||||||
|
11
INSTALL
11
INSTALL
@ -1,7 +1,7 @@
|
|||||||
Installation of the Video Disk Recorder
|
Installation of the Video Disk Recorder
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
Version 1.6
|
Version 1.7
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
Compiling and running the program:
|
Compiling and running the program:
|
||||||
@ -57,13 +57,8 @@ These options accept an optional path to the remote control device,
|
|||||||
the defaults of which can be set via the RCU_DEVICE and LIRC_DEVICE macros,
|
the defaults of which can be set via the RCU_DEVICE and LIRC_DEVICE macros,
|
||||||
respectively.
|
respectively.
|
||||||
|
|
||||||
If your video directory will be on a VFAT partition, add the compile
|
If your video directory will be on a VFAT partition, you can call VDR with
|
||||||
time switch
|
the command line option '--vfat'.
|
||||||
|
|
||||||
VFAT=1
|
|
||||||
|
|
||||||
to the 'make' command. Alternatively, you can call VDR with the command
|
|
||||||
line option '--vfat'.
|
|
||||||
|
|
||||||
When running, the 'vdr' program writes status information into the
|
When running, the 'vdr' program writes status information into the
|
||||||
system log file, which is usually /var/log/messages (or /var/log/user.log,
|
system log file, which is usually /var/log/messages (or /var/log/user.log,
|
||||||
|
9
Makefile
9
Makefile
@ -4,7 +4,7 @@
|
|||||||
# See the main source file 'vdr.c' for copyright information and
|
# See the main source file 'vdr.c' for copyright information and
|
||||||
# how to reach the author.
|
# how to reach the author.
|
||||||
#
|
#
|
||||||
# $Id: Makefile 2.0 2008/02/29 21:43:03 kls Exp $
|
# $Id: Makefile 2.2 2008/05/03 10:13:43 kls Exp $
|
||||||
|
|
||||||
.DELETE_ON_ERROR:
|
.DELETE_ON_ERROR:
|
||||||
|
|
||||||
@ -70,11 +70,6 @@ DEFINES += -DLOCDIR=\"$(LOCDIR)\"
|
|||||||
VDRVERSION = $(shell sed -ne '/define VDRVERSION/s/^.*"\(.*\)".*$$/\1/p' config.h)
|
VDRVERSION = $(shell sed -ne '/define VDRVERSION/s/^.*"\(.*\)".*$$/\1/p' config.h)
|
||||||
APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' config.h)
|
APIVERSION = $(shell sed -ne '/define APIVERSION/s/^.*"\(.*\)".*$$/\1/p' config.h)
|
||||||
|
|
||||||
ifdef VFAT
|
|
||||||
# for people who want their video directory on a VFAT partition
|
|
||||||
DEFINES += -DVFAT
|
|
||||||
endif
|
|
||||||
|
|
||||||
all: vdr i18n
|
all: vdr i18n
|
||||||
|
|
||||||
# Implicit rules:
|
# Implicit rules:
|
||||||
@ -94,7 +89,7 @@ $(DEPFILE): Makefile
|
|||||||
# The main program:
|
# The main program:
|
||||||
|
|
||||||
vdr: $(OBJS) $(SILIB)
|
vdr: $(OBJS) $(SILIB)
|
||||||
$(CXX) $(CXXFLAGS) -rdynamic $(OBJS) $(NCURSESLIB) $(LIBS) $(LIBDIRS) $(SILIB) -o vdr
|
$(CXX) $(CXXFLAGS) -rdynamic $(OBJS) $(LIBS) $(LIBDIRS) $(SILIB) -o vdr
|
||||||
|
|
||||||
# The libsi library:
|
# The libsi library:
|
||||||
|
|
||||||
|
@ -62,3 +62,7 @@ VDR Plugin 'hello' Revision History
|
|||||||
2008-03-18: Version 0.2.2
|
2008-03-18: Version 0.2.2
|
||||||
|
|
||||||
- Updated the Croatian language texts (thanks to Adrian Caval).
|
- Updated the Croatian language texts (thanks to Adrian Caval).
|
||||||
|
|
||||||
|
2008-009-06 Version 0.2.3
|
||||||
|
|
||||||
|
- Updated the Turkish language texts (thanks to Oktay Yolgeçen).
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* See the README file for copyright information and how to reach the author.
|
* See the README file for copyright information and how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: hello.c 2.0 2008/03/18 17:13:25 kls Exp $
|
* $Id: hello.c 2.1 2008/09/06 15:07:12 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
#include <vdr/interface.h>
|
#include <vdr/interface.h>
|
||||||
#include <vdr/plugin.h>
|
#include <vdr/plugin.h>
|
||||||
|
|
||||||
static const char *VERSION = "0.2.2";
|
static const char *VERSION = "0.2.3";
|
||||||
static const char *DESCRIPTION = trNOOP("A friendly greeting");
|
static const char *DESCRIPTION = trNOOP("A friendly greeting");
|
||||||
static const char *MAINMENUENTRY = trNOOP("Hello");
|
static const char *MAINMENUENTRY = trNOOP("Hello");
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ msgstr ""
|
|||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n"
|
"Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n"
|
||||||
"POT-Creation-Date: 2007-10-13 11:52+0200\n"
|
"POT-Creation-Date: 2007-10-13 11:52+0200\n"
|
||||||
"PO-Revision-Date: 2007-08-11 12:34+0200\n"
|
"PO-Revision-Date: 2008-05-12 22:34:4800\n"
|
||||||
"Last-Translator: Oktay Yolgeçen <oktay_73@yahoo.de>\n"
|
"Last-Translator: Oktay Yolgeçen <oktay_73@yahoo.de>\n"
|
||||||
"Language-Team: Turkish\n"
|
"Language-Team: Turkish\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
@ -16,19 +16,19 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
msgid "A friendly greeting"
|
msgid "A friendly greeting"
|
||||||
msgstr ""
|
msgstr "Dostça selam"
|
||||||
|
|
||||||
msgid "Hello"
|
msgid "Hello"
|
||||||
msgstr ""
|
msgstr "Merhaba"
|
||||||
|
|
||||||
msgid "Greeting time (s)"
|
msgid "Greeting time (s)"
|
||||||
msgstr ""
|
msgstr "Selam vakiti (s)"
|
||||||
|
|
||||||
msgid "Use alternate greeting"
|
msgid "Use alternate greeting"
|
||||||
msgstr ""
|
msgstr "Alternatif selam kullan"
|
||||||
|
|
||||||
msgid "Howdy folks!"
|
msgid "Howdy folks!"
|
||||||
msgstr ""
|
msgstr "Selam dostlar!"
|
||||||
|
|
||||||
msgid "Hello world!"
|
msgid "Hello world!"
|
||||||
msgstr ""
|
msgstr "Merhaba dünya!"
|
||||||
|
31
audio.c
31
audio.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: audio.c 2.0 2006/05/28 15:03:24 kls Exp $
|
* $Id: audio.c 2.1 2008/07/06 11:42:58 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
@ -32,6 +32,12 @@ void cAudios::PlayAudio(const uchar *Data, int Length, uchar Id)
|
|||||||
audio->Play(Data, Length, Id);
|
audio->Play(Data, Length, Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cAudios::PlayTsAudio(const uchar *Data, int Length)
|
||||||
|
{
|
||||||
|
for (cAudio *audio = First(); audio; audio = Next(audio))
|
||||||
|
audio->PlayTs(Data, Length);
|
||||||
|
}
|
||||||
|
|
||||||
void cAudios::MuteAudio(bool On)
|
void cAudios::MuteAudio(bool On)
|
||||||
{
|
{
|
||||||
for (cAudio *audio = First(); audio; audio = Next(audio))
|
for (cAudio *audio = First(); audio; audio = Next(audio))
|
||||||
@ -86,6 +92,29 @@ void cExternalAudio::Play(const uchar *Data, int Length, uchar Id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cExternalAudio::PlayTs(const uchar *Data, int Length)
|
||||||
|
{
|
||||||
|
if (command && !mute) {
|
||||||
|
if (pipe || pipe.Open(command, "w")) {
|
||||||
|
int written = 0;
|
||||||
|
while (Length > 0) {
|
||||||
|
int w = fwrite(Data + written, 1, Length, pipe);
|
||||||
|
if (w < 0) {
|
||||||
|
LOG_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Length -= w;
|
||||||
|
written += w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
esyslog("ERROR: can't open pipe to audio command '%s'", command);
|
||||||
|
free(command);
|
||||||
|
command = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void cExternalAudio::Mute(bool On)
|
void cExternalAudio::Mute(bool On)
|
||||||
{
|
{
|
||||||
mute = On;
|
mute = On;
|
||||||
|
9
audio.h
9
audio.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: audio.h 2.0 2005/02/12 12:20:19 kls Exp $
|
* $Id: audio.h 2.1 2008/07/06 11:39:21 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __AUDIO_H
|
#ifndef __AUDIO_H
|
||||||
@ -24,6 +24,11 @@ public:
|
|||||||
///< be copied and processed in a separate thread. The Data is always a
|
///< be copied and processed in a separate thread. The Data is always a
|
||||||
///< complete PES audio packet. Id indicates the type of audio data this
|
///< complete PES audio packet. Id indicates the type of audio data this
|
||||||
///< packet holds.
|
///< packet holds.
|
||||||
|
virtual void PlayTs(const uchar *Data, int Length) = 0;
|
||||||
|
///< Plays the given block of audio Data. Must return as soon as possible.
|
||||||
|
///< If the entire block of data can't be processed immediately, it must
|
||||||
|
///< be copied and processed in a separate thread. The Data is always a
|
||||||
|
///< complete TS audio packet.
|
||||||
virtual void Mute(bool On) = 0;
|
virtual void Mute(bool On) = 0;
|
||||||
///< Immediately sets the audio device to be silent (On==true) or to
|
///< Immediately sets the audio device to be silent (On==true) or to
|
||||||
///< normal replay (On==false).
|
///< normal replay (On==false).
|
||||||
@ -34,6 +39,7 @@ public:
|
|||||||
class cAudios : public cList<cAudio> {
|
class cAudios : public cList<cAudio> {
|
||||||
public:
|
public:
|
||||||
void PlayAudio(const uchar *Data, int Length, uchar Id);
|
void PlayAudio(const uchar *Data, int Length, uchar Id);
|
||||||
|
void PlayTsAudio(const uchar *Data, int Length);
|
||||||
void MuteAudio(bool On);
|
void MuteAudio(bool On);
|
||||||
void ClearAudio(void);
|
void ClearAudio(void);
|
||||||
};
|
};
|
||||||
@ -49,6 +55,7 @@ public:
|
|||||||
cExternalAudio(const char *Command);
|
cExternalAudio(const char *Command);
|
||||||
virtual ~cExternalAudio();
|
virtual ~cExternalAudio();
|
||||||
virtual void Play(const uchar *Data, int Length, uchar Id);
|
virtual void Play(const uchar *Data, int Length, uchar Id);
|
||||||
|
virtual void PlayTs(const uchar *Data, int Length);
|
||||||
virtual void Mute(bool On);
|
virtual void Mute(bool On);
|
||||||
virtual void Clear(void);
|
virtual void Clear(void);
|
||||||
};
|
};
|
||||||
|
28
channels.c
28
channels.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: channels.c 2.2 2008/04/12 13:49:12 kls Exp $
|
* $Id: channels.c 2.3 2008/07/06 12:59:41 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "channels.h"
|
#include "channels.h"
|
||||||
@ -505,10 +505,10 @@ static int IntArrayToString(char *s, const int *a, int Base = 10, const char n[]
|
|||||||
return q - s;
|
return q - s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cChannel::SetPids(int Vpid, int Ppid, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid)
|
void cChannel::SetPids(int Vpid, int Ppid, int Vtype, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid)
|
||||||
{
|
{
|
||||||
int mod = CHANNELMOD_NONE;
|
int mod = CHANNELMOD_NONE;
|
||||||
if (vpid != Vpid || ppid != Ppid || tpid != Tpid)
|
if (vpid != Vpid || ppid != Ppid || vtype != Vtype || tpid != Tpid)
|
||||||
mod |= CHANNELMOD_PIDS;
|
mod |= CHANNELMOD_PIDS;
|
||||||
int m = IntArraysDiffer(apids, Apids, alangs, ALangs) | IntArraysDiffer(dpids, Dpids, dlangs, DLangs) | IntArraysDiffer(spids, Spids, slangs, SLangs);
|
int m = IntArraysDiffer(apids, Apids, alangs, ALangs) | IntArraysDiffer(dpids, Dpids, dlangs, DLangs) | IntArraysDiffer(spids, Spids, slangs, SLangs);
|
||||||
if (m & STRDIFF)
|
if (m & STRDIFF)
|
||||||
@ -542,9 +542,10 @@ void cChannel::SetPids(int Vpid, int Ppid, int *Apids, char ALangs[][MAXLANGCODE
|
|||||||
q = NewSpidsBuf;
|
q = NewSpidsBuf;
|
||||||
q += IntArrayToString(q, Spids, 10, SLangs);
|
q += IntArrayToString(q, Spids, 10, SLangs);
|
||||||
*q = 0;
|
*q = 0;
|
||||||
dsyslog("changing pids of channel %d from %d+%d:%s:%s:%d to %d+%d:%s:%s:%d", Number(), vpid, ppid, OldApidsBuf, OldSpidsBuf, tpid, Vpid, Ppid, NewApidsBuf, NewSpidsBuf, Tpid);
|
dsyslog("changing pids of channel %d from %d+%d=%d:%s:%s:%d to %d+%d=%d:%s:%s:%d", Number(), vpid, ppid, vtype, OldApidsBuf, OldSpidsBuf, tpid, Vpid, Ppid, Vtype, NewApidsBuf, NewSpidsBuf, Tpid);
|
||||||
vpid = Vpid;
|
vpid = Vpid;
|
||||||
ppid = Ppid;
|
ppid = Ppid;
|
||||||
|
vtype = Vtype;
|
||||||
for (int i = 0; i < MAXAPIDS; i++) {
|
for (int i = 0; i < MAXAPIDS; i++) {
|
||||||
apids[i] = Apids[i];
|
apids[i] = Apids[i];
|
||||||
strn0cpy(alangs[i], ALangs[i], MAXLANGCODE2);
|
strn0cpy(alangs[i], ALangs[i], MAXLANGCODE2);
|
||||||
@ -752,6 +753,8 @@ cString cChannel::ToText(const cChannel *Channel)
|
|||||||
q += snprintf(q, sizeof(vpidbuf), "%d", Channel->vpid);
|
q += snprintf(q, sizeof(vpidbuf), "%d", Channel->vpid);
|
||||||
if (Channel->ppid && Channel->ppid != Channel->vpid)
|
if (Channel->ppid && Channel->ppid != Channel->vpid)
|
||||||
q += snprintf(q, sizeof(vpidbuf) - (q - vpidbuf), "+%d", Channel->ppid);
|
q += snprintf(q, sizeof(vpidbuf) - (q - vpidbuf), "+%d", Channel->ppid);
|
||||||
|
if (Channel->vtype)
|
||||||
|
q += snprintf(q, sizeof(vpidbuf) - (q - vpidbuf), "=%d", Channel->vtype);
|
||||||
*q = 0;
|
*q = 0;
|
||||||
const int BufferSize = (MAXAPIDS + MAXDPIDS) * (5 + 1 + MAXLANGCODE2) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod+cod', +10: paranoia
|
const int BufferSize = (MAXAPIDS + MAXDPIDS) * (5 + 1 + MAXLANGCODE2) + 10; // 5 digits plus delimiting ',' or ';' plus optional '=cod+cod', +10: paranoia
|
||||||
char apidbuf[BufferSize];
|
char apidbuf[BufferSize];
|
||||||
@ -813,22 +816,27 @@ bool cChannel::Parse(const char *s)
|
|||||||
tpid = 0;
|
tpid = 0;
|
||||||
}
|
}
|
||||||
vpid = ppid = 0;
|
vpid = ppid = 0;
|
||||||
|
vtype = 2; // default is MPEG-2
|
||||||
apids[0] = 0;
|
apids[0] = 0;
|
||||||
dpids[0] = 0;
|
dpids[0] = 0;
|
||||||
ok = false;
|
ok = false;
|
||||||
if (parambuf && sourcebuf && vpidbuf && apidbuf) {
|
if (parambuf && sourcebuf && vpidbuf && apidbuf) {
|
||||||
ok = StringToParameters(parambuf) && (source = cSource::FromString(sourcebuf)) >= 0;
|
ok = StringToParameters(parambuf) && (source = cSource::FromString(sourcebuf)) >= 0;
|
||||||
|
|
||||||
char *p = strchr(vpidbuf, '+');
|
char *p;
|
||||||
if (p)
|
if ((p = strchr(vpidbuf, '=')) != NULL) {
|
||||||
|
*p++ = 0;
|
||||||
|
if (sscanf(p, "%d", &vtype) != 1)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((p = strchr(vpidbuf, '+')) != NULL) {
|
||||||
*p++ = 0;
|
*p++ = 0;
|
||||||
if (sscanf(vpidbuf, "%d", &vpid) != 1)
|
|
||||||
return false;
|
|
||||||
if (p) {
|
|
||||||
if (sscanf(p, "%d", &ppid) != 1)
|
if (sscanf(p, "%d", &ppid) != 1)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
if (sscanf(vpidbuf, "%d", &vpid) != 1)
|
||||||
|
return false;
|
||||||
|
if (!ppid)
|
||||||
ppid = vpid;
|
ppid = vpid;
|
||||||
|
|
||||||
char *dpidbuf = strchr(apidbuf, ';');
|
char *dpidbuf = strchr(apidbuf, ';');
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: channels.h 2.2 2008/04/12 13:46:50 kls Exp $
|
* $Id: channels.h 2.3 2008/07/06 11:49:37 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CHANNELS_H
|
#ifndef __CHANNELS_H
|
||||||
@ -124,6 +124,7 @@ private:
|
|||||||
int srate;
|
int srate;
|
||||||
int vpid;
|
int vpid;
|
||||||
int ppid;
|
int ppid;
|
||||||
|
int vtype;
|
||||||
int apids[MAXAPIDS + 1]; // list is zero-terminated
|
int apids[MAXAPIDS + 1]; // list is zero-terminated
|
||||||
char alangs[MAXAPIDS][MAXLANGCODE2];
|
char alangs[MAXAPIDS][MAXLANGCODE2];
|
||||||
int dpids[MAXDPIDS + 1]; // list is zero-terminated
|
int dpids[MAXDPIDS + 1]; // list is zero-terminated
|
||||||
@ -178,6 +179,7 @@ public:
|
|||||||
int Srate(void) const { return srate; }
|
int Srate(void) const { return srate; }
|
||||||
int Vpid(void) const { return vpid; }
|
int Vpid(void) const { return vpid; }
|
||||||
int Ppid(void) const { return ppid; }
|
int Ppid(void) const { return ppid; }
|
||||||
|
int Vtype(void) const { return vtype; }
|
||||||
const int *Apids(void) const { return apids; }
|
const int *Apids(void) const { return apids; }
|
||||||
const int *Dpids(void) const { return dpids; }
|
const int *Dpids(void) const { return dpids; }
|
||||||
const int *Spids(void) const { return spids; }
|
const int *Spids(void) const { return spids; }
|
||||||
@ -225,7 +227,7 @@ public:
|
|||||||
void SetId(int Nid, int Tid, int Sid, int Rid = 0);
|
void SetId(int Nid, int Tid, int Sid, int Rid = 0);
|
||||||
void SetName(const char *Name, const char *ShortName, const char *Provider);
|
void SetName(const char *Name, const char *ShortName, const char *Provider);
|
||||||
void SetPortalName(const char *PortalName);
|
void SetPortalName(const char *PortalName);
|
||||||
void SetPids(int Vpid, int Ppid, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid);
|
void SetPids(int Vpid, int Ppid, int Vtype, int *Apids, char ALangs[][MAXLANGCODE2], int *Dpids, char DLangs[][MAXLANGCODE2], int *Spids, char SLangs[][MAXLANGCODE2], int Tpid);
|
||||||
void SetCaIds(const int *CaIds); // list must be zero-terminated
|
void SetCaIds(const int *CaIds); // list must be zero-terminated
|
||||||
void SetCaDescriptors(int Level);
|
void SetCaDescriptors(int Level);
|
||||||
void SetLinkChannels(cLinkChannels *LinkChannels);
|
void SetLinkChannels(cLinkChannels *LinkChannels);
|
||||||
|
7
config.h
7
config.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: config.h 2.1 2008/04/12 13:02:10 kls Exp $
|
* $Id: config.h 2.3 2008/09/06 14:06:56 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CONFIG_H
|
#ifndef __CONFIG_H
|
||||||
@ -22,8 +22,8 @@
|
|||||||
|
|
||||||
// VDR's own version number:
|
// VDR's own version number:
|
||||||
|
|
||||||
#define VDRVERSION "1.7.0"
|
#define VDRVERSION "1.7.1"
|
||||||
#define VDRVERSNUM 10700 // Version * 10000 + Major * 100 + Minor
|
#define VDRVERSNUM 10701 // Version * 10000 + Major * 100 + Minor
|
||||||
|
|
||||||
// The plugin API's version number:
|
// The plugin API's version number:
|
||||||
|
|
||||||
@ -122,7 +122,6 @@ public:
|
|||||||
esyslog("ERROR: error in %s, line %d", fileName, line);
|
esyslog("ERROR: error in %s, line %d", fileName, line);
|
||||||
delete l;
|
delete l;
|
||||||
result = false;
|
result = false;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
286
device.c
286
device.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: device.c 2.2 2008/04/12 14:12:14 kls Exp $
|
* $Id: device.c 2.3 2008/07/06 13:22:21 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
@ -21,16 +21,9 @@
|
|||||||
|
|
||||||
// --- cLiveSubtitle ---------------------------------------------------------
|
// --- cLiveSubtitle ---------------------------------------------------------
|
||||||
|
|
||||||
#define LIVESUBTITLEBUFSIZE KILOBYTE(100)
|
class cLiveSubtitle : public cReceiver {
|
||||||
|
|
||||||
class cLiveSubtitle : public cReceiver, public cThread {
|
|
||||||
private:
|
|
||||||
cRingBufferLinear *ringBuffer;
|
|
||||||
cRemux *remux;
|
|
||||||
protected:
|
protected:
|
||||||
virtual void Activate(bool On);
|
|
||||||
virtual void Receive(uchar *Data, int Length);
|
virtual void Receive(uchar *Data, int Length);
|
||||||
virtual void Action(void);
|
|
||||||
public:
|
public:
|
||||||
cLiveSubtitle(int SPid);
|
cLiveSubtitle(int SPid);
|
||||||
virtual ~cLiveSubtitle();
|
virtual ~cLiveSubtitle();
|
||||||
@ -38,170 +31,17 @@ public:
|
|||||||
|
|
||||||
cLiveSubtitle::cLiveSubtitle(int SPid)
|
cLiveSubtitle::cLiveSubtitle(int SPid)
|
||||||
:cReceiver(tChannelID(), -1, SPid)
|
:cReceiver(tChannelID(), -1, SPid)
|
||||||
,cThread("live subtitle")
|
|
||||||
{
|
{
|
||||||
ringBuffer = new cRingBufferLinear(LIVESUBTITLEBUFSIZE, TS_SIZE * 2, true, "Live Subtitle");
|
|
||||||
int NoPids = 0;
|
|
||||||
int SPids[] = { SPid, 0 };
|
|
||||||
remux = new cRemux(0, &NoPids, &NoPids, SPids);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cLiveSubtitle::~cLiveSubtitle()
|
cLiveSubtitle::~cLiveSubtitle()
|
||||||
{
|
{
|
||||||
cReceiver::Detach();
|
cReceiver::Detach();
|
||||||
delete remux;
|
|
||||||
delete ringBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cLiveSubtitle::Activate(bool On)
|
|
||||||
{
|
|
||||||
if (On)
|
|
||||||
Start();
|
|
||||||
else
|
|
||||||
Cancel(3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cLiveSubtitle::Receive(uchar *Data, int Length)
|
void cLiveSubtitle::Receive(uchar *Data, int Length)
|
||||||
{
|
{
|
||||||
if (Running()) {
|
cDevice::PrimaryDevice()->PlayTs(Data, Length);
|
||||||
int p = ringBuffer->Put(Data, Length);
|
|
||||||
if (p != Length && Running())
|
|
||||||
ringBuffer->ReportOverflow(Length - p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cLiveSubtitle::Action(void)
|
|
||||||
{
|
|
||||||
while (Running()) {
|
|
||||||
int Count;
|
|
||||||
uchar *b = ringBuffer->Get(Count);
|
|
||||||
if (b) {
|
|
||||||
Count = remux->Put(b, Count);
|
|
||||||
if (Count)
|
|
||||||
ringBuffer->Del(Count);
|
|
||||||
}
|
|
||||||
b = remux->Get(Count);
|
|
||||||
if (b) {
|
|
||||||
Count = cDevice::PrimaryDevice()->PlaySubtitle(b, Count);
|
|
||||||
remux->Del(Count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- cPesAssembler ---------------------------------------------------------
|
|
||||||
|
|
||||||
class cPesAssembler {
|
|
||||||
private:
|
|
||||||
uchar *data;
|
|
||||||
uint32_t tag;
|
|
||||||
int length;
|
|
||||||
int size;
|
|
||||||
bool Realloc(int Size);
|
|
||||||
public:
|
|
||||||
cPesAssembler(void);
|
|
||||||
~cPesAssembler();
|
|
||||||
int ExpectedLength(void) { return PacketSize(data); }
|
|
||||||
static int PacketSize(const uchar *data);
|
|
||||||
int Length(void) { return length; }
|
|
||||||
const uchar *Data(void) { return data; } // only valid if Length() >= 4
|
|
||||||
void Reset(void);
|
|
||||||
void Put(uchar c);
|
|
||||||
void Put(const uchar *Data, int Length);
|
|
||||||
bool IsPes(void);
|
|
||||||
};
|
|
||||||
|
|
||||||
cPesAssembler::cPesAssembler(void)
|
|
||||||
{
|
|
||||||
data = NULL;
|
|
||||||
size = 0;
|
|
||||||
Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
cPesAssembler::~cPesAssembler()
|
|
||||||
{
|
|
||||||
free(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cPesAssembler::Reset(void)
|
|
||||||
{
|
|
||||||
tag = 0xFFFFFFFF;
|
|
||||||
length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cPesAssembler::Realloc(int Size)
|
|
||||||
{
|
|
||||||
if (Size > size) {
|
|
||||||
size = max(Size, 2048);
|
|
||||||
data = (uchar *)realloc(data, size);
|
|
||||||
if (!data) {
|
|
||||||
esyslog("ERROR: can't allocate memory for PES assembler");
|
|
||||||
length = 0;
|
|
||||||
size = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cPesAssembler::Put(uchar c)
|
|
||||||
{
|
|
||||||
if (length < 4) {
|
|
||||||
tag = (tag << 8) | c;
|
|
||||||
if ((tag & 0xFFFFFF00) == 0x00000100) {
|
|
||||||
if (Realloc(4)) {
|
|
||||||
*(uint32_t *)data = htonl(tag);
|
|
||||||
length = 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (length < 3)
|
|
||||||
length++;
|
|
||||||
}
|
|
||||||
else if (Realloc(length + 1))
|
|
||||||
data[length++] = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cPesAssembler::Put(const uchar *Data, int Length)
|
|
||||||
{
|
|
||||||
while (length < 4 && Length > 0) {
|
|
||||||
Put(*Data++);
|
|
||||||
Length--;
|
|
||||||
}
|
|
||||||
if (Length && Realloc(length + Length)) {
|
|
||||||
memcpy(data + length, Data, Length);
|
|
||||||
length += Length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int cPesAssembler::PacketSize(const uchar *data)
|
|
||||||
{
|
|
||||||
// we need atleast 6 bytes of data here !!!
|
|
||||||
switch (data[3]) {
|
|
||||||
default:
|
|
||||||
case 0x00 ... 0xB8: // video stream start codes
|
|
||||||
case 0xB9: // Program end
|
|
||||||
case 0xBC: // Programm stream map
|
|
||||||
case 0xF0 ... 0xFF: // reserved
|
|
||||||
return 6;
|
|
||||||
|
|
||||||
case 0xBA: // Pack header
|
|
||||||
if ((data[4] & 0xC0) == 0x40) // MPEG2
|
|
||||||
return 14;
|
|
||||||
// to be absolutely correct we would have to add the stuffing bytes
|
|
||||||
// as well, but at this point we only may have 6 bytes of data avail-
|
|
||||||
// able. So it's up to the higher level to resync...
|
|
||||||
//return 14 + (data[13] & 0x07); // add stuffing bytes
|
|
||||||
else // MPEG1
|
|
||||||
return 12;
|
|
||||||
|
|
||||||
case 0xBB: // System header
|
|
||||||
case 0xBD: // Private stream1
|
|
||||||
case 0xBE: // Padding stream
|
|
||||||
case 0xBF: // Private stream2 (navigation data)
|
|
||||||
case 0xC0 ... 0xCF: // all the rest (the real packets)
|
|
||||||
case 0xD0 ... 0xDF:
|
|
||||||
case 0xE0 ... 0xEF:
|
|
||||||
return 6 + data[4] * 256 + data[5];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- cDevice ---------------------------------------------------------------
|
// --- cDevice ---------------------------------------------------------------
|
||||||
@ -241,7 +81,6 @@ cDevice::cDevice(void)
|
|||||||
startScrambleDetection = 0;
|
startScrambleDetection = 0;
|
||||||
|
|
||||||
player = NULL;
|
player = NULL;
|
||||||
pesAssembler = new cPesAssembler;
|
|
||||||
ClrAvailableTracks();
|
ClrAvailableTracks();
|
||||||
currentAudioTrack = ttNone;
|
currentAudioTrack = ttNone;
|
||||||
currentAudioTrackMissingCount = 0;
|
currentAudioTrackMissingCount = 0;
|
||||||
@ -265,7 +104,6 @@ cDevice::~cDevice()
|
|||||||
DetachAllReceivers();
|
DetachAllReceivers();
|
||||||
delete liveSubtitle;
|
delete liveSubtitle;
|
||||||
delete dvbSubtitleConverter;
|
delete dvbSubtitleConverter;
|
||||||
delete pesAssembler;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cDevice::WaitForAllDevicesReady(int Timeout)
|
bool cDevice::WaitForAllDevicesReady(int Timeout)
|
||||||
@ -1195,7 +1033,6 @@ bool cDevice::AttachPlayer(cPlayer *Player)
|
|||||||
Detach(player);
|
Detach(player);
|
||||||
DELETENULL(liveSubtitle);
|
DELETENULL(liveSubtitle);
|
||||||
DELETENULL(dvbSubtitleConverter);
|
DELETENULL(dvbSubtitleConverter);
|
||||||
pesAssembler->Reset();
|
|
||||||
player = Player;
|
player = Player;
|
||||||
if (!Transferring())
|
if (!Transferring())
|
||||||
ClrAvailableTracks(false, true);
|
ClrAvailableTracks(false, true);
|
||||||
@ -1256,7 +1093,7 @@ int cDevice::PlaySubtitle(const uchar *Data, int Length)
|
|||||||
{
|
{
|
||||||
if (!dvbSubtitleConverter)
|
if (!dvbSubtitleConverter)
|
||||||
dvbSubtitleConverter = new cDvbSubtitleConverter;
|
dvbSubtitleConverter = new cDvbSubtitleConverter;
|
||||||
return dvbSubtitleConverter->Convert(Data, Length);
|
return dvbSubtitleConverter->ConvertFragments(Data, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly)
|
int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly)
|
||||||
@ -1360,42 +1197,16 @@ pre_1_3_19_PrivateStreamDetected:
|
|||||||
int cDevice::PlayPes(const uchar *Data, int Length, bool VideoOnly)
|
int cDevice::PlayPes(const uchar *Data, int Length, bool VideoOnly)
|
||||||
{
|
{
|
||||||
if (!Data) {
|
if (!Data) {
|
||||||
pesAssembler->Reset();
|
|
||||||
if (dvbSubtitleConverter)
|
if (dvbSubtitleConverter)
|
||||||
dvbSubtitleConverter->Reset();
|
dvbSubtitleConverter->Reset();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int Result = 0;
|
|
||||||
if (pesAssembler->Length()) {
|
|
||||||
// Make sure we have a complete PES header:
|
|
||||||
while (pesAssembler->Length() < 6 && Length > 0) {
|
|
||||||
pesAssembler->Put(*Data++);
|
|
||||||
Length--;
|
|
||||||
Result++;
|
|
||||||
}
|
|
||||||
if (pesAssembler->Length() < 6)
|
|
||||||
return Result; // Still no complete PES header - wait for more
|
|
||||||
int l = pesAssembler->ExpectedLength();
|
|
||||||
int Rest = min(l - pesAssembler->Length(), Length);
|
|
||||||
pesAssembler->Put(Data, Rest);
|
|
||||||
Data += Rest;
|
|
||||||
Length -= Rest;
|
|
||||||
Result += Rest;
|
|
||||||
if (pesAssembler->Length() < l)
|
|
||||||
return Result; // Still no complete PES packet - wait for more
|
|
||||||
// Now pesAssembler contains one complete PES packet.
|
|
||||||
int w = PlayPesPacket(pesAssembler->Data(), pesAssembler->Length(), VideoOnly);
|
|
||||||
if (w > 0)
|
|
||||||
pesAssembler->Reset();
|
|
||||||
return Result > 0 ? Result : w < 0 ? w : 0;
|
|
||||||
}
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (i <= Length - 6) {
|
while (i <= Length - 6) {
|
||||||
if (Data[i] == 0x00 && Data[i + 1] == 0x00 && Data[i + 2] == 0x01) {
|
if (Data[i] == 0x00 && Data[i + 1] == 0x00 && Data[i + 2] == 0x01) {
|
||||||
int l = cPesAssembler::PacketSize(&Data[i]);
|
int l = PesLength(Data + i);
|
||||||
if (i + l > Length) {
|
if (i + l > Length) {
|
||||||
// Store incomplete PES packet for later completion:
|
esyslog("ERROR: incomplete PES packet!");
|
||||||
pesAssembler->Put(Data + i, Length - i);
|
|
||||||
return Length;
|
return Length;
|
||||||
}
|
}
|
||||||
int w = PlayPesPacket(Data + i, l, VideoOnly);
|
int w = PlayPesPacket(Data + i, l, VideoOnly);
|
||||||
@ -1408,10 +1219,91 @@ int cDevice::PlayPes(const uchar *Data, int Length, bool VideoOnly)
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (i < Length)
|
if (i < Length)
|
||||||
pesAssembler->Put(Data + i, Length - i);
|
esyslog("ERROR: leftover PES data!");
|
||||||
return Length;
|
return Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cDevice::PlayTsVideo(const uchar *Data, int Length)
|
||||||
|
{
|
||||||
|
// Video PES has no explicit length, so we can only determine the end of
|
||||||
|
// a PES packet when the next TS packet that starts a payload comes in:
|
||||||
|
if (TsPayloadStart(Data)) {
|
||||||
|
if (const uchar *p = tsToPesVideo.GetPes(Length)) {
|
||||||
|
int w = PlayVideo(p, Length);
|
||||||
|
if (w > 0)
|
||||||
|
tsToPesVideo.Reset();
|
||||||
|
else
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tsToPesVideo.PutTs(Data, Length);
|
||||||
|
return Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cDevice::PlayTsAudio(const uchar *Data, int Length)
|
||||||
|
{
|
||||||
|
bool PayloadStart = TsPayloadStart(Data);
|
||||||
|
for (int Pass = 0; Pass < 2; Pass++) {
|
||||||
|
if (Pass == 0 && !PayloadStart) // if no new payload is started, we can always put the packet into the converter
|
||||||
|
tsToPesAudio.PutTs(Data, Length);
|
||||||
|
if (const uchar *p = tsToPesAudio.GetPes(Length)) {
|
||||||
|
int w = PlayAudio(p, Length, 0);
|
||||||
|
if (w > 0)
|
||||||
|
tsToPesAudio.Reset();
|
||||||
|
else if (PayloadStart)
|
||||||
|
return w; // must get out the old packet before starting a new one
|
||||||
|
}
|
||||||
|
if (Pass == 0 && PayloadStart)
|
||||||
|
tsToPesAudio.PutTs(Data, Length);
|
||||||
|
}
|
||||||
|
return Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cDevice::PlayTsSubtitle(const uchar *Data, int Length)
|
||||||
|
{
|
||||||
|
if (!dvbSubtitleConverter)
|
||||||
|
dvbSubtitleConverter = new cDvbSubtitleConverter;
|
||||||
|
tsToPesSubtitle.PutTs(Data, Length);
|
||||||
|
if (const uchar *p = tsToPesSubtitle.GetPes(Length)) {
|
||||||
|
dvbSubtitleConverter->Convert(p, Length);
|
||||||
|
tsToPesSubtitle.Reset();
|
||||||
|
}
|
||||||
|
return Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO detect and report continuity errors?
|
||||||
|
int cDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly)
|
||||||
|
{
|
||||||
|
if (Length == TS_SIZE) {
|
||||||
|
if (!TsHasPayload(Data))
|
||||||
|
return Length; // silently ignore TS packets w/o payload
|
||||||
|
int PayloadOffset = TsPayloadOffset(Data);
|
||||||
|
if (PayloadOffset < Length) {
|
||||||
|
int Pid = TsPid(Data);
|
||||||
|
if (Pid == 0)
|
||||||
|
patPmtParser.ParsePat(Data + PayloadOffset, Length - PayloadOffset);
|
||||||
|
else if (Pid == patPmtParser.PmtPid())
|
||||||
|
patPmtParser.ParsePmt(Data + PayloadOffset, Length - PayloadOffset);
|
||||||
|
else if (Pid == patPmtParser.Vpid())
|
||||||
|
return PlayTsVideo(Data, Length);
|
||||||
|
else if (Pid == availableTracks[currentAudioTrack].id) {
|
||||||
|
if (!VideoOnly || HasIBPTrickSpeed()) {
|
||||||
|
int w = PlayTsAudio(Data, Length);
|
||||||
|
if (w > 0)
|
||||||
|
Audios.PlayTsAudio(Data, Length);
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Pid == availableTracks[currentSubtitleTrack].id) {
|
||||||
|
if (!VideoOnly || HasIBPTrickSpeed())
|
||||||
|
return PlayTsSubtitle(Data, Length);
|
||||||
|
}
|
||||||
|
return Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int cDevice::Priority(void) const
|
int cDevice::Priority(void) const
|
||||||
{
|
{
|
||||||
int priority = IsPrimaryDevice() ? Setup.PrimaryLimit - 1 : DEFAULTPRIORITY;
|
int priority = IsPrimaryDevice() ? Setup.PrimaryLimit - 1 : DEFAULTPRIORITY;
|
||||||
@ -1448,7 +1340,7 @@ void cDevice::Action(void)
|
|||||||
uchar *b = NULL;
|
uchar *b = NULL;
|
||||||
if (GetTSPacket(b)) {
|
if (GetTSPacket(b)) {
|
||||||
if (b) {
|
if (b) {
|
||||||
int Pid = (((uint16_t)b[1] & PID_MASK_HI) << 8) | b[2];
|
int Pid = TsPid(b);
|
||||||
// Check whether the TS packets are scrambled:
|
// Check whether the TS packets are scrambled:
|
||||||
bool DetachReceivers = false;
|
bool DetachReceivers = false;
|
||||||
bool DescramblingOk = false;
|
bool DescramblingOk = false;
|
||||||
|
55
device.h
55
device.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: device.h 2.1 2008/04/12 11:11:23 kls Exp $
|
* $Id: device.h 2.2 2008/07/06 11:25:42 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DEVICE_H
|
#ifndef __DEVICE_H
|
||||||
@ -17,6 +17,7 @@
|
|||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
#include "nit.h"
|
#include "nit.h"
|
||||||
#include "pat.h"
|
#include "pat.h"
|
||||||
|
#include "remux.h"
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
#include "sdt.h"
|
#include "sdt.h"
|
||||||
#include "sections.h"
|
#include "sections.h"
|
||||||
@ -30,10 +31,6 @@
|
|||||||
#define MAXVOLUME 255
|
#define MAXVOLUME 255
|
||||||
#define VOLUMEDELTA 5 // used to increase/decrease the volume
|
#define VOLUMEDELTA 5 // used to increase/decrease the volume
|
||||||
|
|
||||||
#define TS_SIZE 188
|
|
||||||
#define TS_SYNC_BYTE 0x47
|
|
||||||
#define PID_MASK_HI 0x1F
|
|
||||||
|
|
||||||
enum eSetChannelResult { scrOk, scrNotAvailable, scrNoTransfer, scrFailed };
|
enum eSetChannelResult { scrOk, scrNotAvailable, scrNoTransfer, scrFailed };
|
||||||
|
|
||||||
enum ePlayMode { pmNone, // audio/video from decoder
|
enum ePlayMode { pmNone, // audio/video from decoder
|
||||||
@ -89,7 +86,6 @@ struct tTrackId {
|
|||||||
|
|
||||||
class cPlayer;
|
class cPlayer;
|
||||||
class cReceiver;
|
class cReceiver;
|
||||||
class cPesAssembler;
|
|
||||||
class cLiveSubtitle;
|
class cLiveSubtitle;
|
||||||
|
|
||||||
/// The cDevice class is the base from which actual devices can be derived.
|
/// The cDevice class is the base from which actual devices can be derived.
|
||||||
@ -477,7 +473,10 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
cPlayer *player;
|
cPlayer *player;
|
||||||
cPesAssembler *pesAssembler;
|
cPatPmtParser patPmtParser;
|
||||||
|
cTsToPes tsToPesVideo;
|
||||||
|
cTsToPes tsToPesAudio;
|
||||||
|
cTsToPes tsToPesSubtitle;
|
||||||
protected:
|
protected:
|
||||||
virtual bool CanReplay(void) const;
|
virtual bool CanReplay(void) const;
|
||||||
///< Returns true if this device can currently start a replay session.
|
///< Returns true if this device can currently start a replay session.
|
||||||
@ -511,6 +510,33 @@ protected:
|
|||||||
///< If VideoOnly is true, only the video will be displayed,
|
///< If VideoOnly is true, only the video will be displayed,
|
||||||
///< which is necessary for trick modes like 'fast forward'.
|
///< which is necessary for trick modes like 'fast forward'.
|
||||||
///< Data must point to one single, complete PES packet.
|
///< Data must point to one single, complete PES packet.
|
||||||
|
virtual int PlayTsVideo(const uchar *Data, int Length);
|
||||||
|
///< Plays the given data block as video.
|
||||||
|
///< Data points to exactly one complete TS packet of the given Length
|
||||||
|
///< (which is always TS_SIZE).
|
||||||
|
///< PlayTsVideo() shall process the packet either as a whole (returning
|
||||||
|
///< a positive number, which needs not necessarily be Length) or not at all
|
||||||
|
///< (returning 0 or -1 and setting 'errno' to EAGAIN).
|
||||||
|
///< The default implementation collects all incoming TS payload belonging
|
||||||
|
///< to one PES packet and calls PlayVideo() with the resulting packet.
|
||||||
|
virtual int PlayTsAudio(const uchar *Data, int Length);
|
||||||
|
///< Plays the given data block as audio.
|
||||||
|
///< Data points to exactly one complete TS packet of the given Length
|
||||||
|
///< (which is always TS_SIZE).
|
||||||
|
///< PlayTsAudio() shall process the packet either as a whole (returning
|
||||||
|
///< a positive number, which needs not necessarily be Length) or not at all
|
||||||
|
///< (returning 0 or -1 and setting 'errno' to EAGAIN).
|
||||||
|
///< The default implementation collects all incoming TS payload belonging
|
||||||
|
///< to one PES packet and calls PlayAudio() with the resulting packet.
|
||||||
|
virtual int PlayTsSubtitle(const uchar *Data, int Length);
|
||||||
|
///< Plays the given data block as a subtitle.
|
||||||
|
///< Data points to exactly one complete TS packet of the given Length
|
||||||
|
///< (which is always TS_SIZE).
|
||||||
|
///< PlayTsSubtitle() shall process the packet either as a whole (returning
|
||||||
|
///< a positive number, which needs not necessarily be Length) or not at all
|
||||||
|
///< (returning 0 or -1 and setting 'errno' to EAGAIN).
|
||||||
|
///< The default implementation collects all incoming TS payload belonging
|
||||||
|
///< to one PES packet and displays the resulting subtitle via the OSD.
|
||||||
public:
|
public:
|
||||||
virtual int64_t GetSTC(void);
|
virtual int64_t GetSTC(void);
|
||||||
///< Gets the current System Time Counter, which can be used to
|
///< Gets the current System Time Counter, which can be used to
|
||||||
@ -565,6 +591,21 @@ public:
|
|||||||
///< to a complete packet with data from the next call to PlayPes().
|
///< to a complete packet with data from the next call to PlayPes().
|
||||||
///< That way any functions called from within PlayPes() will be
|
///< That way any functions called from within PlayPes() will be
|
||||||
///< guaranteed to always receive complete PES packets.
|
///< guaranteed to always receive complete PES packets.
|
||||||
|
virtual int PlayTs(const uchar *Data, int Length, bool VideoOnly = false);
|
||||||
|
///< Plays the given TS packet.
|
||||||
|
///< If VideoOnly is true, only the video will be displayed,
|
||||||
|
///< which is necessary for trick modes like 'fast forward'.
|
||||||
|
///< Data points to a single TS packet, Length is always TS_SIZE (the total
|
||||||
|
///< size of a single TS packet).
|
||||||
|
///< A derived device can reimplement this function to handle the
|
||||||
|
///< TS packets itself. Any packets the derived function can't handle
|
||||||
|
///< must be sent to the base class function. This applies especially
|
||||||
|
///< to the PAT/PMT packets.
|
||||||
|
///< Returns -1 in case of error, otherwise the number of actually
|
||||||
|
///< processed bytes is returned, which may be less than Length.
|
||||||
|
///< PlayTs() shall process the packet either as a whole (returning
|
||||||
|
///< a positive number, which needs not necessarily be Length) or not at all
|
||||||
|
///< (returning 0 or -1 and setting 'errno' to EAGAIN).
|
||||||
bool Replaying(void) const;
|
bool Replaying(void) const;
|
||||||
///< Returns true if we are currently replaying.
|
///< Returns true if we are currently replaying.
|
||||||
bool Transferring(void) const;
|
bool Transferring(void) const;
|
||||||
|
27
dvbdevice.c
27
dvbdevice.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: dvbdevice.c 2.2 2008/04/13 14:15:35 kls Exp $
|
* $Id: dvbdevice.c 2.4 2008/07/06 13:58:56 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dvbdevice.h"
|
#include "dvbdevice.h"
|
||||||
@ -266,10 +266,6 @@ bool cDvbTuner::SetFrontend(void)
|
|||||||
|
|
||||||
tuneTimeout = DVBS_TUNE_TIMEOUT;
|
tuneTimeout = DVBS_TUNE_TIMEOUT;
|
||||||
lockTimeout = DVBS_LOCK_TIMEOUT;
|
lockTimeout = DVBS_LOCK_TIMEOUT;
|
||||||
|
|
||||||
dvbfe_info feinfo;
|
|
||||||
feinfo.delivery = Frontend.delivery;
|
|
||||||
CHECK(ioctl(fd_frontend, DVBFE_GET_INFO, &feinfo)); //switch system
|
|
||||||
}
|
}
|
||||||
else if (frontendType & DVBFE_DELSYS_DVBC) {
|
else if (frontendType & DVBFE_DELSYS_DVBC) {
|
||||||
Frontend.delivery = DVBFE_DELSYS_DVBC;
|
Frontend.delivery = DVBFE_DELSYS_DVBC;
|
||||||
@ -281,10 +277,6 @@ bool cDvbTuner::SetFrontend(void)
|
|||||||
|
|
||||||
tuneTimeout = DVBC_TUNE_TIMEOUT;
|
tuneTimeout = DVBC_TUNE_TIMEOUT;
|
||||||
lockTimeout = DVBC_LOCK_TIMEOUT;
|
lockTimeout = DVBC_LOCK_TIMEOUT;
|
||||||
|
|
||||||
dvbfe_info feinfo;
|
|
||||||
feinfo.delivery = Frontend.delivery;
|
|
||||||
CHECK(ioctl(fd_frontend, DVBFE_GET_INFO, &feinfo)); //switch system
|
|
||||||
}
|
}
|
||||||
else if (frontendType & DVBFE_DELSYS_DVBT) {
|
else if (frontendType & DVBFE_DELSYS_DVBT) {
|
||||||
Frontend.delivery = DVBFE_DELSYS_DVBT;
|
Frontend.delivery = DVBFE_DELSYS_DVBT;
|
||||||
@ -302,15 +294,12 @@ bool cDvbTuner::SetFrontend(void)
|
|||||||
|
|
||||||
tuneTimeout = DVBT_TUNE_TIMEOUT;
|
tuneTimeout = DVBT_TUNE_TIMEOUT;
|
||||||
lockTimeout = DVBT_LOCK_TIMEOUT;
|
lockTimeout = DVBT_LOCK_TIMEOUT;
|
||||||
|
|
||||||
dvbfe_info feinfo;
|
|
||||||
feinfo.delivery = Frontend.delivery;
|
|
||||||
CHECK(ioctl(fd_frontend, DVBFE_GET_INFO, &feinfo)); //switch system
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
|
esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
CHECK(ioctl(fd_frontend, DVBFE_SET_DELSYS, &Frontend.delivery));
|
||||||
if (ioctl(fd_frontend, DVBFE_SET_PARAMS, &Frontend) < 0) {
|
if (ioctl(fd_frontend, DVBFE_SET_PARAMS, &Frontend) < 0) {
|
||||||
esyslog("ERROR: frontend %d: %m", cardIndex);
|
esyslog("ERROR: frontend %d: %m", cardIndex);
|
||||||
return false;
|
return false;
|
||||||
@ -1247,6 +1236,18 @@ int cDvbDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
|
|||||||
return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10);
|
return WriteAllOrNothing(fd_audio, Data, Length, 1000, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cDvbDevice::PlayTsVideo(const uchar *Data, int Length)
|
||||||
|
{
|
||||||
|
Length = TsGetPayload(&Data);
|
||||||
|
return PlayVideo(Data, Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cDvbDevice::PlayTsAudio(const uchar *Data, int Length)
|
||||||
|
{
|
||||||
|
Length = TsGetPayload(&Data);
|
||||||
|
return PlayAudio(Data, Length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
bool cDvbDevice::OpenDvr(void)
|
bool cDvbDevice::OpenDvr(void)
|
||||||
{
|
{
|
||||||
CloseDvr();
|
CloseDvr();
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: dvbdevice.h 2.1 2008/04/12 11:20:48 kls Exp $
|
* $Id: dvbdevice.h 2.2 2008/06/01 09:48:04 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DVBDEVICE_H
|
#ifndef __DVBDEVICE_H
|
||||||
@ -138,6 +138,8 @@ protected:
|
|||||||
virtual bool SetPlayMode(ePlayMode PlayMode);
|
virtual bool SetPlayMode(ePlayMode PlayMode);
|
||||||
virtual int PlayVideo(const uchar *Data, int Length);
|
virtual int PlayVideo(const uchar *Data, int Length);
|
||||||
virtual int PlayAudio(const uchar *Data, int Length, uchar Id);
|
virtual int PlayAudio(const uchar *Data, int Length, uchar Id);
|
||||||
|
virtual int PlayTsVideo(const uchar *Data, int Length);
|
||||||
|
virtual int PlayTsAudio(const uchar *Data, int Length);
|
||||||
public:
|
public:
|
||||||
virtual int64_t GetSTC(void);
|
virtual int64_t GetSTC(void);
|
||||||
virtual void TrickSpeed(int Speed);
|
virtual void TrickSpeed(int Speed);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Original author: Marco Schlüßler <marco@lordzodiac.de>
|
* Original author: Marco Schlüßler <marco@lordzodiac.de>
|
||||||
* With some input from the "subtitle plugin" by Pekka Virtanen <pekka.virtanen@sci.fi>
|
* With some input from the "subtitle plugin" by Pekka Virtanen <pekka.virtanen@sci.fi>
|
||||||
*
|
*
|
||||||
* $Id: dvbsubtitle.c 2.0 2007/11/25 13:33:08 kls Exp $
|
* $Id: dvbsubtitle.c 2.1 2008/05/25 14:36:24 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dvbsubtitle.h"
|
#include "dvbsubtitle.h"
|
||||||
@ -580,12 +580,12 @@ bool cDvbSubtitleAssembler::Realloc(int Size)
|
|||||||
unsigned char *cDvbSubtitleAssembler::Get(int &Length)
|
unsigned char *cDvbSubtitleAssembler::Get(int &Length)
|
||||||
{
|
{
|
||||||
if (length > pos + 5) {
|
if (length > pos + 5) {
|
||||||
Length = (data[pos + 4] << 8) + data[pos + 5] + 6;
|
Length = (data[pos + 4] << 8) + data[pos + 5] + 6;
|
||||||
if (length >= pos + Length) {
|
if (length >= pos + Length) {
|
||||||
unsigned char *result = data + pos;
|
unsigned char *result = data + pos;
|
||||||
pos += Length;
|
pos += Length;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -684,10 +684,10 @@ void cDvbSubtitleConverter::Reset(void)
|
|||||||
Unlock();
|
Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
int cDvbSubtitleConverter::Convert(const uchar *Data, int Length)
|
int cDvbSubtitleConverter::ConvertFragments(const uchar *Data, int Length)
|
||||||
{
|
{
|
||||||
if (Data && Length > 8) {
|
if (Data && Length > 8) {
|
||||||
int PayloadOffset = Data[8] + 9;
|
int PayloadOffset = PesPayloadOffset(Data);
|
||||||
int SubstreamHeaderLength = 4;
|
int SubstreamHeaderLength = 4;
|
||||||
bool ResetSubtitleAssembler = Data[PayloadOffset + 3] == 0x00;
|
bool ResetSubtitleAssembler = Data[PayloadOffset + 3] == 0x00;
|
||||||
|
|
||||||
@ -699,15 +699,9 @@ int cDvbSubtitleConverter::Convert(const uchar *Data, int Length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Length > PayloadOffset + SubstreamHeaderLength) {
|
if (Length > PayloadOffset + SubstreamHeaderLength) {
|
||||||
int64_t pts = 0;
|
int64_t pts = PesGetPts(Data);
|
||||||
if ((Data[7] & 0x80) && Data[8] >= 5) {
|
if (pts)
|
||||||
pts = (((int64_t)Data[ 9]) & 0x0E) << 29;
|
|
||||||
pts |= ( (int64_t)Data[10]) << 22;
|
|
||||||
pts |= (((int64_t)Data[11]) & 0xFE) << 14;
|
|
||||||
pts |= ( (int64_t)Data[12]) << 7;
|
|
||||||
pts |= (((int64_t)Data[13]) & 0xFE) >> 1;
|
|
||||||
dbgconverter("Converter PTS: %lld\n", pts);
|
dbgconverter("Converter PTS: %lld\n", pts);
|
||||||
}
|
|
||||||
const uchar *data = Data + PayloadOffset + SubstreamHeaderLength; // skip substream header
|
const uchar *data = Data + PayloadOffset + SubstreamHeaderLength; // skip substream header
|
||||||
int length = Length - PayloadOffset - SubstreamHeaderLength; // skip substream header
|
int length = Length - PayloadOffset - SubstreamHeaderLength; // skip substream header
|
||||||
if (ResetSubtitleAssembler)
|
if (ResetSubtitleAssembler)
|
||||||
@ -736,6 +730,40 @@ int cDvbSubtitleConverter::Convert(const uchar *Data, int Length)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cDvbSubtitleConverter::Convert(const uchar *Data, int Length)
|
||||||
|
{
|
||||||
|
if (Data && Length > 8) {
|
||||||
|
int PayloadOffset = PesPayloadOffset(Data);
|
||||||
|
if (Length > PayloadOffset) {
|
||||||
|
int64_t pts = PesGetPts(Data);
|
||||||
|
if (pts)
|
||||||
|
dbgconverter("Converter PTS: %lld\n", pts);
|
||||||
|
const uchar *data = Data + PayloadOffset;
|
||||||
|
int length = Length - PayloadOffset;
|
||||||
|
if (length > 3) {
|
||||||
|
if (data[0] == 0x20 && data[1] == 0x00 && data[2] == 0x0F) {
|
||||||
|
data += 2;
|
||||||
|
length -= 2;
|
||||||
|
}
|
||||||
|
const uchar *b = data;
|
||||||
|
while (length > 0) {
|
||||||
|
if (b[0] == 0x0F) {
|
||||||
|
int n = ExtractSegment(b, length, pts);
|
||||||
|
if (n < 0)
|
||||||
|
break;
|
||||||
|
b += n;
|
||||||
|
length -= n;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Length;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#define LimitTo32Bit(n) (n & 0x00000000FFFFFFFFL)
|
#define LimitTo32Bit(n) (n & 0x00000000FFFFFFFFL)
|
||||||
#define MAXDELTA 40000 // max. reasonable PTS/STC delta in ms
|
#define MAXDELTA 40000 // max. reasonable PTS/STC delta in ms
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Original author: Marco Schlüßler <marco@lordzodiac.de>
|
* Original author: Marco Schlüßler <marco@lordzodiac.de>
|
||||||
*
|
*
|
||||||
* $Id: dvbsubtitle.h 2.0 2007/10/14 14:02:46 kls Exp $
|
* $Id: dvbsubtitle.h 2.1 2008/05/25 14:36:52 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DVBSUBTITLE_H
|
#ifndef __DVBSUBTITLE_H
|
||||||
@ -17,7 +17,7 @@
|
|||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
class cDvbSubtitlePage;
|
class cDvbSubtitlePage;
|
||||||
class cDvbSubtitleAssembler;
|
class cDvbSubtitleAssembler; // for legacy PES recordings
|
||||||
class cDvbSubtitleBitmaps;
|
class cDvbSubtitleBitmaps;
|
||||||
|
|
||||||
class cDvbSubtitleConverter : public cThread {
|
class cDvbSubtitleConverter : public cThread {
|
||||||
@ -36,6 +36,7 @@ public:
|
|||||||
virtual ~cDvbSubtitleConverter();
|
virtual ~cDvbSubtitleConverter();
|
||||||
void Action(void);
|
void Action(void);
|
||||||
void Reset(void);
|
void Reset(void);
|
||||||
|
int ConvertFragments(const uchar *Data, int Length); // for legacy PES recordings
|
||||||
int Convert(const uchar *Data, int Length);
|
int Convert(const uchar *Data, int Length);
|
||||||
static void SetupChanged(void);
|
static void SetupChanged(void);
|
||||||
};
|
};
|
||||||
|
4
eit.c
4
eit.c
@ -8,7 +8,7 @@
|
|||||||
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
|
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
|
||||||
* Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>.
|
* Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>.
|
||||||
*
|
*
|
||||||
* $Id: eit.c 2.1 2008/04/13 11:27:06 kls Exp $
|
* $Id: eit.c 2.2 2008/05/01 15:33:27 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "eit.h"
|
#include "eit.h"
|
||||||
@ -219,7 +219,7 @@ cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data, bo
|
|||||||
SI::ComponentDescriptor *cd = (SI::ComponentDescriptor *)d;
|
SI::ComponentDescriptor *cd = (SI::ComponentDescriptor *)d;
|
||||||
uchar Stream = cd->getStreamContent();
|
uchar Stream = cd->getStreamContent();
|
||||||
uchar Type = cd->getComponentType();
|
uchar Type = cd->getComponentType();
|
||||||
if (1 <= Stream && Stream <= 3 && Type != 0) { // 1=video, 2=audio, 3=subtitles
|
if (1 <= Stream && Stream <= 4 && Type != 0) { // 1=video, 2=audio, 3=subtitles, 4=AC3
|
||||||
if (!Components)
|
if (!Components)
|
||||||
Components = new cComponents;
|
Components = new cComponents;
|
||||||
char buffer[Utf8BufSize(256)];
|
char buffer[Utf8BufSize(256)];
|
||||||
|
8
epg.c
8
epg.c
@ -7,7 +7,7 @@
|
|||||||
* Original version (as used in VDR before 1.3.0) written by
|
* Original version (as used in VDR before 1.3.0) written by
|
||||||
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
|
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
|
||||||
*
|
*
|
||||||
* $Id: epg.c 2.0 2008/02/16 16:09:12 kls Exp $
|
* $Id: epg.c 2.1 2008/05/01 14:53:55 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "epg.h"
|
#include "epg.h"
|
||||||
@ -88,8 +88,10 @@ void cComponents::SetComponent(int Index, uchar Stream, uchar Type, const char *
|
|||||||
tComponent *cComponents::GetComponent(int Index, uchar Stream, uchar Type)
|
tComponent *cComponents::GetComponent(int Index, uchar Stream, uchar Type)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < numComponents; i++) {
|
for (int i = 0; i < numComponents; i++) {
|
||||||
// In case of an audio stream the 'type' check actually just distinguishes between "normal" and "Dolby Digital":
|
if (components[i].stream == Stream && (
|
||||||
if (components[i].stream == Stream && (Stream != 2 || (components[i].type < 5) == (Type < 5))) {
|
Type == 0 || // don't care about the actual Type
|
||||||
|
Stream == 2 && (components[i].type < 5) == (Type < 5) // fallback "Dolby" component according to the "Premiere pseudo standard"
|
||||||
|
)) {
|
||||||
if (!Index--)
|
if (!Index--)
|
||||||
return &components[i];
|
return &components[i];
|
||||||
}
|
}
|
||||||
|
6
font.c
6
font.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: font.c 2.0 2008/03/01 10:19:41 kls Exp $
|
* $Id: font.c 2.1 2008/05/02 16:16:51 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
@ -395,7 +395,7 @@ bool cFont::GetAvailableFontNames(cStringList *FontNames, bool Monospaced)
|
|||||||
FcFontSetDestroy(fontset);
|
FcFontSetDestroy(fontset);
|
||||||
FcPatternDestroy(pat);
|
FcPatternDestroy(pat);
|
||||||
FcObjectSetDestroy(os);
|
FcObjectSetDestroy(os);
|
||||||
FcFini();
|
//FcFini(); // older versions of fontconfig are broken - and FcInit() can be called more than once
|
||||||
FontNames->Sort();
|
FontNames->Sort();
|
||||||
}
|
}
|
||||||
return FontNames->Size() > 0;
|
return FontNames->Size() > 0;
|
||||||
@ -431,7 +431,7 @@ cString cFont::GetFontFileName(const char *FontName)
|
|||||||
esyslog("ERROR: no usable font found for '%s'", FontName);
|
esyslog("ERROR: no usable font found for '%s'", FontName);
|
||||||
FcPatternDestroy(pat);
|
FcPatternDestroy(pat);
|
||||||
free(fn);
|
free(fn);
|
||||||
FcFini();
|
//FcFini(); // older versions of fontconfig are broken - and FcInit() can be called more than once
|
||||||
}
|
}
|
||||||
return FontFileName;
|
return FontFileName;
|
||||||
}
|
}
|
||||||
|
4
i18n.c
4
i18n.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: i18n.c 2.0 2008/01/19 12:07:11 kls Exp $
|
* $Id: i18n.c 2.1 2008/09/06 12:24:43 kls Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -45,7 +45,7 @@ const char *LanguageCodeList[] = {
|
|||||||
"por",
|
"por",
|
||||||
"fra,fre",
|
"fra,fre",
|
||||||
"nor",
|
"nor",
|
||||||
"fin,smi",
|
"fin,suo",
|
||||||
"pol",
|
"pol",
|
||||||
"esl,spa",
|
"esl,spa",
|
||||||
"ell,gre",
|
"ell,gre",
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* the Free Software Foundation; either version 2 of the License, or *
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
* (at your option) any later version. *
|
* (at your option) any later version. *
|
||||||
* *
|
* *
|
||||||
* $Id: si.h 2.0 2007/04/22 13:32:09 kls Exp $
|
* $Id: si.h 2.1 2008/09/06 12:44:06 kls Exp $
|
||||||
* *
|
* *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ enum TableId { TableIdPAT = 0x00, //program association section
|
|||||||
TableIdNIT_other = 0x41, //network information section, other network
|
TableIdNIT_other = 0x41, //network information section, other network
|
||||||
TableIdSDT = 0x42, //service description section
|
TableIdSDT = 0x42, //service description section
|
||||||
TableIdSDT_other = 0x46,
|
TableIdSDT_other = 0x46,
|
||||||
TableIdBAT = 0x46, //bouquet association section
|
TableIdBAT = 0x4A, //bouquet association section
|
||||||
TableIdEIT_presentFollowing = 0x4E, //event information section
|
TableIdEIT_presentFollowing = 0x4E, //event information section
|
||||||
TableIdEIT_presentFollowing_other = 0x4F,
|
TableIdEIT_presentFollowing_other = 0x4F,
|
||||||
//range from 0x50 to 0x5F
|
//range from 0x50 to 0x5F
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* the Free Software Foundation; either version 2 of the License, or *
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
* (at your option) any later version. *
|
* (at your option) any later version. *
|
||||||
* *
|
* *
|
||||||
* $Id: util.h 2.0 2006/02/25 10:13:28 kls Exp $
|
* $Id: util.h 2.1 2008/05/22 10:49:08 kls Exp $
|
||||||
* *
|
* *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
@ -148,9 +148,9 @@ public:
|
|||||||
CRC32(const char *d, int len, u_int32_t CRCvalue=0xFFFFFFFF);
|
CRC32(const char *d, int len, u_int32_t CRCvalue=0xFFFFFFFF);
|
||||||
bool isValid() { return crc32(data, length, value) == 0; }
|
bool isValid() { return crc32(data, length, value) == 0; }
|
||||||
static bool isValid(const char *d, int len, u_int32_t CRCvalue=0xFFFFFFFF) { return crc32(d, len, CRCvalue) == 0; }
|
static bool isValid(const char *d, int len, u_int32_t CRCvalue=0xFFFFFFFF) { return crc32(d, len, CRCvalue) == 0; }
|
||||||
|
static u_int32_t crc32(const char *d, int len, u_int32_t CRCvalue);
|
||||||
protected:
|
protected:
|
||||||
static u_int32_t crc_table[256];
|
static u_int32_t crc_table[256];
|
||||||
static u_int32_t crc32 (const char *d, int len, u_int32_t CRCvalue);
|
|
||||||
|
|
||||||
const char *data;
|
const char *data;
|
||||||
int length;
|
int length;
|
||||||
|
4
menu.c
4
menu.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: menu.c 2.1 2008/04/12 11:37:17 kls Exp $
|
* $Id: menu.c 2.2 2008/05/01 14:37:24 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
@ -3147,6 +3147,8 @@ static void SetTrackDescriptions(int LiveChannel)
|
|||||||
break;
|
break;
|
||||||
case 3: cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, indexSubtitle++, 0, LiveChannel ? NULL : p->language, p->description);
|
case 3: cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, indexSubtitle++, 0, LiveChannel ? NULL : p->language, p->description);
|
||||||
break;
|
break;
|
||||||
|
case 4: cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, indexDolby++, 0, LiveChannel ? NULL : p->language, p->description);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
pat.c
11
pat.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: pat.c 2.1 2008/04/12 13:34:50 kls Exp $
|
* $Id: pat.c 2.2 2008/07/06 14:01:32 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pat.h"
|
#include "pat.h"
|
||||||
@ -328,7 +328,8 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
|
|||||||
// Scan the stream-specific loop:
|
// Scan the stream-specific loop:
|
||||||
SI::PMT::Stream stream;
|
SI::PMT::Stream stream;
|
||||||
int Vpid = 0;
|
int Vpid = 0;
|
||||||
int Ppid = pmt.getPCRPid();
|
int Ppid = 0;
|
||||||
|
int Vtype = 0;
|
||||||
int Apids[MAXAPIDS + 1] = { 0 }; // these lists are zero-terminated
|
int Apids[MAXAPIDS + 1] = { 0 }; // these lists are zero-terminated
|
||||||
int Dpids[MAXDPIDS + 1] = { 0 };
|
int Dpids[MAXDPIDS + 1] = { 0 };
|
||||||
int Spids[MAXSPIDS + 1] = { 0 };
|
int Spids[MAXSPIDS + 1] = { 0 };
|
||||||
@ -343,8 +344,10 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
|
|||||||
switch (stream.getStreamType()) {
|
switch (stream.getStreamType()) {
|
||||||
case 1: // STREAMTYPE_11172_VIDEO
|
case 1: // STREAMTYPE_11172_VIDEO
|
||||||
case 2: // STREAMTYPE_13818_VIDEO
|
case 2: // STREAMTYPE_13818_VIDEO
|
||||||
//TODO case 0x1B: // MPEG4
|
case 0x1B: // MPEG4
|
||||||
Vpid = stream.getPid();
|
Vpid = stream.getPid();
|
||||||
|
Ppid = pmt.getPCRPid();
|
||||||
|
Vtype = stream.getStreamType();
|
||||||
break;
|
break;
|
||||||
case 3: // STREAMTYPE_11172_AUDIO
|
case 3: // STREAMTYPE_11172_AUDIO
|
||||||
case 4: // STREAMTYPE_13818_AUDIO
|
case 4: // STREAMTYPE_13818_AUDIO
|
||||||
@ -440,7 +443,7 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Setup.UpdateChannels >= 2) {
|
if (Setup.UpdateChannels >= 2) {
|
||||||
Channel->SetPids(Vpid, Vpid ? Ppid : 0, Apids, ALangs, Dpids, DLangs, Spids, SLangs, Tpid);
|
Channel->SetPids(Vpid, Ppid, Vtype, Apids, ALangs, Dpids, DLangs, Spids, SLangs, Tpid);
|
||||||
Channel->SetCaIds(CaDescriptors->CaIds());
|
Channel->SetCaIds(CaDescriptors->CaIds());
|
||||||
}
|
}
|
||||||
Channel->SetCaDescriptors(CaDescriptorHandler.AddCaDescriptors(CaDescriptors));
|
Channel->SetCaDescriptors(CaDescriptorHandler.AddCaDescriptors(CaDescriptors));
|
||||||
|
6
player.h
6
player.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: player.h 2.0 2008/02/16 13:50:11 kls Exp $
|
* $Id: player.h 2.1 2008/08/15 14:07:48 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __PLAYER_H
|
#ifndef __PLAYER_H
|
||||||
@ -42,6 +42,10 @@ protected:
|
|||||||
// Sends the given PES Data to the device and returns the number of
|
// Sends the given PES Data to the device and returns the number of
|
||||||
// bytes that have actually been accepted by the device (or a
|
// bytes that have actually been accepted by the device (or a
|
||||||
// negative value in case of an error).
|
// negative value in case of an error).
|
||||||
|
int PlayTs(const uchar *Data, int Length, bool VideoOnly = false) { return device ? device->PlayTs(Data, Length, VideoOnly) : -1; }
|
||||||
|
// Sends the given TS packet to the device and returns a positive number
|
||||||
|
// if the packet has been accepted by the device, or a negative value in
|
||||||
|
// case of an error.
|
||||||
public:
|
public:
|
||||||
cPlayer(ePlayMode PlayMode = pmAudioVideo);
|
cPlayer(ePlayMode PlayMode = pmAudioVideo);
|
||||||
virtual ~cPlayer();
|
virtual ~cPlayer();
|
||||||
|
32
po/it_IT.po
32
po/it_IT.po
@ -12,9 +12,9 @@ msgstr ""
|
|||||||
"Project-Id-Version: VDR 1.6.0\n"
|
"Project-Id-Version: VDR 1.6.0\n"
|
||||||
"Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n"
|
"Report-Msgid-Bugs-To: <vdr-bugs@cadsoft.de>\n"
|
||||||
"POT-Creation-Date: 2008-04-12 14:19+0200\n"
|
"POT-Creation-Date: 2008-04-12 14:19+0200\n"
|
||||||
"PO-Revision-Date: 2008-03-08 21:06+0100\n"
|
"PO-Revision-Date: 2008-08-25 02:36+0100\n"
|
||||||
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
|
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
|
||||||
"Language-Team: Italian\n"
|
"Language-Team: Italian\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=ISO-8859-15\n"
|
"Content-Type: text/plain; charset=ISO-8859-15\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
@ -236,7 +236,7 @@ msgid "Disk"
|
|||||||
msgstr "Disco"
|
msgstr "Disco"
|
||||||
|
|
||||||
msgid "free"
|
msgid "free"
|
||||||
msgstr "liberi"
|
msgstr "disponibili"
|
||||||
|
|
||||||
msgid "Free To Air"
|
msgid "Free To Air"
|
||||||
msgstr "in chiaro"
|
msgstr "in chiaro"
|
||||||
@ -377,7 +377,7 @@ msgid "VPS"
|
|||||||
msgstr "VPS"
|
msgstr "VPS"
|
||||||
|
|
||||||
msgid "Lifetime"
|
msgid "Lifetime"
|
||||||
msgstr "Durata"
|
msgstr "Scadenza"
|
||||||
|
|
||||||
msgid "File"
|
msgid "File"
|
||||||
msgstr "Nome"
|
msgstr "Nome"
|
||||||
@ -419,20 +419,20 @@ msgid "What's on next?"
|
|||||||
msgstr "Prossimi programmi"
|
msgstr "Prossimi programmi"
|
||||||
|
|
||||||
msgid "Button$Next"
|
msgid "Button$Next"
|
||||||
msgstr "Prossimo"
|
msgstr "Prossimi"
|
||||||
|
|
||||||
msgid "Button$Now"
|
msgid "Button$Now"
|
||||||
msgstr "Adesso"
|
msgstr "Adesso"
|
||||||
|
|
||||||
msgid "Button$Schedule"
|
msgid "Button$Schedule"
|
||||||
msgstr "Programma"
|
msgstr "Programmi"
|
||||||
|
|
||||||
msgid "Can't switch channel!"
|
msgid "Can't switch channel!"
|
||||||
msgstr "Impossibile cambiare canale!"
|
msgstr "Impossibile cambiare canale!"
|
||||||
|
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Schedule - %s"
|
msgid "Schedule - %s"
|
||||||
msgstr "Programma - %s"
|
msgstr "Programmi - %s"
|
||||||
|
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "This event - %s"
|
msgid "This event - %s"
|
||||||
@ -515,7 +515,7 @@ msgid "Setup.OSD$Height"
|
|||||||
msgstr "Altezza OSD"
|
msgstr "Altezza OSD"
|
||||||
|
|
||||||
msgid "Setup.OSD$Message time (s)"
|
msgid "Setup.OSD$Message time (s)"
|
||||||
msgstr "Tempo del messaggio (s)"
|
msgstr "Durata del messaggio (s)"
|
||||||
|
|
||||||
msgid "Setup.OSD$Use small font"
|
msgid "Setup.OSD$Use small font"
|
||||||
msgstr "Utilizza caratteri piccoli"
|
msgstr "Utilizza caratteri piccoli"
|
||||||
@ -587,7 +587,7 @@ msgid "Setup.EPG$EPG linger time (min)"
|
|||||||
msgstr "Mostra vecchi dati EPG (min)"
|
msgstr "Mostra vecchi dati EPG (min)"
|
||||||
|
|
||||||
msgid "Setup.EPG$Set system time"
|
msgid "Setup.EPG$Set system time"
|
||||||
msgstr "Imposta orario automatico"
|
msgstr "Imposta orario di sistema"
|
||||||
|
|
||||||
msgid "Setup.EPG$Use time from transponder"
|
msgid "Setup.EPG$Use time from transponder"
|
||||||
msgstr "Utilizza orario da transponder"
|
msgstr "Utilizza orario da transponder"
|
||||||
@ -637,13 +637,13 @@ msgid "Setup.DVB$Video format"
|
|||||||
msgstr "Formato video"
|
msgstr "Formato video"
|
||||||
|
|
||||||
msgid "Setup.DVB$Video display format"
|
msgid "Setup.DVB$Video display format"
|
||||||
msgstr "Formato di visualizz. video"
|
msgstr "Formato visualizzazione video"
|
||||||
|
|
||||||
msgid "Setup.DVB$Use Dolby Digital"
|
msgid "Setup.DVB$Use Dolby Digital"
|
||||||
msgstr "Dolby Digital"
|
msgstr "Dolby Digital"
|
||||||
|
|
||||||
msgid "Setup.DVB$Update channels"
|
msgid "Setup.DVB$Update channels"
|
||||||
msgstr "Aggiorna i canali"
|
msgstr "Aggiornamento canali"
|
||||||
|
|
||||||
msgid "Setup.DVB$Audio languages"
|
msgid "Setup.DVB$Audio languages"
|
||||||
msgstr "Lingue audio"
|
msgstr "Lingue audio"
|
||||||
@ -730,13 +730,13 @@ msgid "Setup.Recording$Default priority"
|
|||||||
msgstr "Priorità predefinita"
|
msgstr "Priorità predefinita"
|
||||||
|
|
||||||
msgid "Setup.Recording$Default lifetime (d)"
|
msgid "Setup.Recording$Default lifetime (d)"
|
||||||
msgstr "Durata predefinita (gg)"
|
msgstr "Scadenza predefinita (gg)"
|
||||||
|
|
||||||
msgid "Setup.Recording$Pause priority"
|
msgid "Setup.Recording$Pause priority"
|
||||||
msgstr "Priorità di pausa"
|
msgstr "Priorità di pausa"
|
||||||
|
|
||||||
msgid "Setup.Recording$Pause lifetime (d)"
|
msgid "Setup.Recording$Pause lifetime (d)"
|
||||||
msgstr "Durata pausa (gg)"
|
msgstr "Scadenza pausa (gg)"
|
||||||
|
|
||||||
msgid "Setup.Recording$Use episode name"
|
msgid "Setup.Recording$Use episode name"
|
||||||
msgstr "Utilizza nome episodio"
|
msgstr "Utilizza nome episodio"
|
||||||
@ -754,7 +754,7 @@ msgid "Setup.Recording$Name instant recording"
|
|||||||
msgstr "Nome reg. immediata"
|
msgstr "Nome reg. immediata"
|
||||||
|
|
||||||
msgid "Setup.Recording$Instant rec. time (min)"
|
msgid "Setup.Recording$Instant rec. time (min)"
|
||||||
msgstr "Tempo reg. immediata (min)"
|
msgstr "Durata reg. immediata (min)"
|
||||||
|
|
||||||
msgid "Setup.Recording$Max. video file size (MB)"
|
msgid "Setup.Recording$Max. video file size (MB)"
|
||||||
msgstr "Dim. massima file video (MB)"
|
msgstr "Dim. massima file video (MB)"
|
||||||
@ -917,7 +917,7 @@ msgid "Plugin"
|
|||||||
msgstr "Plugin"
|
msgstr "Plugin"
|
||||||
|
|
||||||
msgid "Up/Dn for new location - OK to move"
|
msgid "Up/Dn for new location - OK to move"
|
||||||
msgstr "Su/Giù per nuova posizione - OK per muovere"
|
msgstr "Su/Giù per nuova posizione - OK per spostare"
|
||||||
|
|
||||||
msgid "Channel locked (recording)!"
|
msgid "Channel locked (recording)!"
|
||||||
msgstr "Canale bloccato (in registrazione)!"
|
msgstr "Canale bloccato (in registrazione)!"
|
||||||
@ -936,7 +936,7 @@ msgstr "Registrazione in corso - spegnere comunque?"
|
|||||||
|
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Recording in %ld minutes, shut down anyway?"
|
msgid "Recording in %ld minutes, shut down anyway?"
|
||||||
msgstr "Registrazione fra %ld minuti - spegnere comunque?"
|
msgstr "Registrazione tra %ld minuti - spegnere comunque?"
|
||||||
|
|
||||||
msgid "shut down anyway?"
|
msgid "shut down anyway?"
|
||||||
msgstr "spegnere comunque?"
|
msgstr "spegnere comunque?"
|
||||||
|
14
recording.c
14
recording.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: recording.c 2.0 2008/02/24 10:28:53 kls Exp $
|
* $Id: recording.c 2.3 2008/06/12 21:46:08 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "recording.h"
|
#include "recording.h"
|
||||||
@ -31,8 +31,8 @@
|
|||||||
/* This was the original code, which works fine in a Linux only environment.
|
/* This was the original code, which works fine in a Linux only environment.
|
||||||
Unfortunately, because of Windows and its brain dead file system, we have
|
Unfortunately, because of Windows and its brain dead file system, we have
|
||||||
to use a more complicated approach, in order to allow users who have enabled
|
to use a more complicated approach, in order to allow users who have enabled
|
||||||
the VFAT compile time option to see their recordings even if they forget to
|
the --vfat command line option to see their recordings even if they forget to
|
||||||
enable VFAT when compiling a new version of VDR... Gee, do I hate Windows.
|
enable --vfat when restarting VDR... Gee, do I hate Windows.
|
||||||
(kls 2002-07-27)
|
(kls 2002-07-27)
|
||||||
#define DATAFORMAT "%4d-%02d-%02d.%02d:%02d.%02d.%02d" RECEXT
|
#define DATAFORMAT "%4d-%02d-%02d.%02d:%02d.%02d.%02d" RECEXT
|
||||||
#define NAMEFORMAT "%s/%s/" DATAFORMAT
|
#define NAMEFORMAT "%s/%s/" DATAFORMAT
|
||||||
@ -297,7 +297,9 @@ cRecordingInfo::cRecordingInfo(const cChannel *Channel, const cEvent *Event)
|
|||||||
for (int i = 0; i < MAXDPIDS; i++) {
|
for (int i = 0; i < MAXDPIDS; i++) {
|
||||||
const char *s = Channel->Dlang(i);
|
const char *s = Channel->Dlang(i);
|
||||||
if (*s) {
|
if (*s) {
|
||||||
tComponent *Component = Components->GetComponent(i, 2, 5);
|
tComponent *Component = Components->GetComponent(i, 4, 0); // AC3 component according to the DVB standard
|
||||||
|
if (!Component)
|
||||||
|
Component = Components->GetComponent(i, 2, 5); // fallback "Dolby" component according to the "Premiere pseudo standard"
|
||||||
if (!Component)
|
if (!Component)
|
||||||
Components->SetComponent(Components->NumComponents(), 2, 5, s, NULL);
|
Components->SetComponent(Components->NumComponents(), 2, 5, s, NULL);
|
||||||
else if (strlen(s) > strlen(Component->language))
|
else if (strlen(s) > strlen(Component->language))
|
||||||
@ -1483,8 +1485,8 @@ cUnbufferedFile *cFileName::SetOffset(int Number, int Offset)
|
|||||||
return SetOffset(Number + 1); // file exists and has non zero size, let's try next suffix
|
return SetOffset(Number + 1); // file exists and has non zero size, let's try next suffix
|
||||||
else {
|
else {
|
||||||
// zero size file, remove it
|
// zero size file, remove it
|
||||||
dsyslog ("cFileName::SetOffset: removing zero-sized file %s", fileName);
|
dsyslog("cFileName::SetOffset: removing zero-sized file %s", fileName);
|
||||||
unlink (fileName);
|
unlink(fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
477
remux.c
477
remux.c
@ -11,15 +11,24 @@
|
|||||||
* The cRepacker family's code was originally written by Reinhard Nissl <rnissl@gmx.de>,
|
* The cRepacker family's code was originally written by Reinhard Nissl <rnissl@gmx.de>,
|
||||||
* and adapted to the VDR coding style by Klaus.Schmidinger@cadsoft.de.
|
* and adapted to the VDR coding style by Klaus.Schmidinger@cadsoft.de.
|
||||||
*
|
*
|
||||||
* $Id: remux.c 2.0 2007/11/25 13:56:03 kls Exp $
|
* $Id: remux.c 2.1 2008/08/15 14:49:34 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "remux.h"
|
#include "remux.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "channels.h"
|
#include "channels.h"
|
||||||
|
#include "device.h"
|
||||||
|
#include "libsi/si.h"
|
||||||
|
#include "libsi/section.h"
|
||||||
|
#include "libsi/descriptor.h"
|
||||||
#include "shutdown.h"
|
#include "shutdown.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
|
// Set this to 'true' for debug output:
|
||||||
|
static bool DebugPatPmt = false;
|
||||||
|
|
||||||
|
#define dbgpatpmt(a...) if (DebugPatPmt) fprintf(stderr, a)
|
||||||
|
|
||||||
ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
|
ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
|
||||||
{
|
{
|
||||||
if (Count < 7)
|
if (Count < 7)
|
||||||
@ -1413,7 +1422,6 @@ int cDolbyRepacker::BreakAt(const uchar *Data, int Count)
|
|||||||
//pts_dts flags
|
//pts_dts flags
|
||||||
#define PTS_ONLY 0x80
|
#define PTS_ONLY 0x80
|
||||||
|
|
||||||
#define TS_SIZE 188
|
|
||||||
#define PID_MASK_HI 0x1F
|
#define PID_MASK_HI 0x1F
|
||||||
#define CONT_CNT_MASK 0x0F
|
#define CONT_CNT_MASK 0x0F
|
||||||
|
|
||||||
@ -2007,8 +2015,6 @@ int cRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &Pic
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TS_SYNC_BYTE 0x47
|
|
||||||
|
|
||||||
int cRemux::Put(const uchar *Data, int Count)
|
int cRemux::Put(const uchar *Data, int Count)
|
||||||
{
|
{
|
||||||
int used = 0;
|
int used = 0;
|
||||||
@ -2182,3 +2188,466 @@ void cRemux::SetBrokenLink(uchar *Data, int Length)
|
|||||||
else
|
else
|
||||||
dsyslog("SetBrokenLink: no video packet in frame");
|
dsyslog("SetBrokenLink: no video packet in frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- cPatPmtGenerator ------------------------------------------------------
|
||||||
|
|
||||||
|
cPatPmtGenerator::cPatPmtGenerator(void)
|
||||||
|
{
|
||||||
|
numPmtPackets = 0;
|
||||||
|
patCounter = pmtCounter = 0;
|
||||||
|
patVersion = pmtVersion = 0;
|
||||||
|
esInfoLength = NULL;
|
||||||
|
GeneratePat();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cPatPmtGenerator::IncCounter(int &Counter, uchar *TsPacket)
|
||||||
|
{
|
||||||
|
TsPacket[3] = (TsPacket[3] & 0xF0) | Counter;
|
||||||
|
if (++Counter > 0x0F)
|
||||||
|
Counter = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cPatPmtGenerator::IncVersion(int &Version)
|
||||||
|
{
|
||||||
|
if (++Version > 0x1F)
|
||||||
|
Version = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cPatPmtGenerator::IncEsInfoLength(int Length)
|
||||||
|
{
|
||||||
|
if (esInfoLength) {
|
||||||
|
Length += ((*esInfoLength & 0x0F) << 8) | *(esInfoLength + 1);
|
||||||
|
*esInfoLength = 0xF0 | (Length >> 8);
|
||||||
|
*(esInfoLength + 1) = Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int cPatPmtGenerator::MakeStream(uchar *Target, uchar Type, int Pid)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
Target[i++] = Type; // stream type
|
||||||
|
Target[i++] = 0xE0 | (Pid >> 8); // dummy (3), pid hi (5)
|
||||||
|
Target[i++] = Pid; // pid lo
|
||||||
|
esInfoLength = &Target[i];
|
||||||
|
Target[i++] = 0xF0; // dummy (4), ES info length hi
|
||||||
|
Target[i++] = 0x00; // ES info length lo
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cPatPmtGenerator::MakeAC3Descriptor(uchar *Target)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
Target[i++] = SI::AC3DescriptorTag;
|
||||||
|
Target[i++] = 0x01; // length
|
||||||
|
Target[i++] = 0x00;
|
||||||
|
IncEsInfoLength(i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cPatPmtGenerator::MakeSubtitlingDescriptor(uchar *Target, const char *Language)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
Target[i++] = SI::SubtitlingDescriptorTag;
|
||||||
|
Target[i++] = 0x08; // length
|
||||||
|
Target[i++] = *Language++;
|
||||||
|
Target[i++] = *Language++;
|
||||||
|
Target[i++] = *Language++;
|
||||||
|
Target[i++] = 0x00; // subtitling type
|
||||||
|
Target[i++] = 0x00; // composition page id hi
|
||||||
|
Target[i++] = 0x01; // composition page id lo
|
||||||
|
Target[i++] = 0x00; // ancillary page id hi
|
||||||
|
Target[i++] = 0x01; // ancillary page id lo
|
||||||
|
IncEsInfoLength(i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cPatPmtGenerator::MakeLanguageDescriptor(uchar *Target, const char *Language)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
Target[i++] = SI::ISO639LanguageDescriptorTag;
|
||||||
|
Target[i++] = 0x04; // length
|
||||||
|
Target[i++] = *Language++;
|
||||||
|
Target[i++] = *Language++;
|
||||||
|
Target[i++] = *Language++;
|
||||||
|
Target[i++] = 0x01; // audio type
|
||||||
|
IncEsInfoLength(i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cPatPmtGenerator::MakeCRC(uchar *Target, const uchar *Data, int Length)
|
||||||
|
{
|
||||||
|
int crc = SI::CRC32::crc32((const char *)Data, Length, 0xFFFFFFFF);
|
||||||
|
int i = 0;
|
||||||
|
Target[i++] = crc >> 24;
|
||||||
|
Target[i++] = crc >> 16;
|
||||||
|
Target[i++] = crc >> 8;
|
||||||
|
Target[i++] = crc;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define P_TSID 0x8008 // pseudo TS ID
|
||||||
|
#define P_PNR 0x0084 // pseudo Program Number
|
||||||
|
#define P_PMT_PID 0x0084 // pseudo PMT pid
|
||||||
|
|
||||||
|
void cPatPmtGenerator::GeneratePat(void)
|
||||||
|
{
|
||||||
|
memset(pat, 0xFF, sizeof(pat));
|
||||||
|
uchar *p = pat;
|
||||||
|
int i = 0;
|
||||||
|
p[i++] = 0x47; // TS indicator
|
||||||
|
p[i++] = 0x40; // flags (3), pid hi (5)
|
||||||
|
p[i++] = 0x00; // pid lo
|
||||||
|
p[i++] = 0x10; // flags (4), continuity counter (4)
|
||||||
|
int PayloadStart = i;
|
||||||
|
p[i++] = 0x00; // table id
|
||||||
|
p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
|
||||||
|
int SectionLength = i;
|
||||||
|
p[i++] = 0x00; // section length lo (filled in later)
|
||||||
|
p[i++] = P_TSID >> 8; // TS id hi
|
||||||
|
p[i++] = P_TSID & 0xFF; // TS id lo
|
||||||
|
p[i++] = 0xC1 | (patVersion << 1); // dummy (2), version number (5), current/next indicator (1)
|
||||||
|
p[i++] = 0x00; // section number
|
||||||
|
p[i++] = 0x00; // last section number
|
||||||
|
p[i++] = P_PNR >> 8; // program number hi
|
||||||
|
p[i++] = P_PNR & 0xFF; // program number lo
|
||||||
|
p[i++] = 0xE0 | (P_PMT_PID >> 8); // dummy (3), PMT pid hi (5)
|
||||||
|
p[i++] = P_PMT_PID & 0xFF; // PMT pid lo
|
||||||
|
pat[SectionLength] = i - SectionLength - 1 + 4; // -2 = SectionLength storage, +4 = length of CRC
|
||||||
|
MakeCRC(pat + i, pat + PayloadStart, i - PayloadStart);
|
||||||
|
IncVersion(patVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cPatPmtGenerator::GeneratePmt(tChannelID ChannelID)
|
||||||
|
{
|
||||||
|
// generate the complete PMT section:
|
||||||
|
uchar buf[MAX_SECTION_SIZE];
|
||||||
|
memset(buf, 0xFF, sizeof(buf));
|
||||||
|
numPmtPackets = 0;
|
||||||
|
cChannel *Channel = Channels.GetByChannelID(ChannelID);
|
||||||
|
if (Channel) {
|
||||||
|
int Vpid = Channel->Vpid();
|
||||||
|
uchar *p = buf;
|
||||||
|
int i = 0;
|
||||||
|
p[i++] = 0x02; // table id
|
||||||
|
int SectionLength = i;
|
||||||
|
p[i++] = 0xB0; // section syntax indicator (1), dummy (3), section length hi (4)
|
||||||
|
p[i++] = 0x00; // section length lo (filled in later)
|
||||||
|
p[i++] = P_PNR >> 8; // program number hi
|
||||||
|
p[i++] = P_PNR & 0xFF; // program number lo
|
||||||
|
p[i++] = 0xC1 | (pmtVersion << 1); // dummy (2), version number (5), current/next indicator (1)
|
||||||
|
p[i++] = 0x00; // section number
|
||||||
|
p[i++] = 0x00; // last section number
|
||||||
|
p[i++] = 0xE0 | (Vpid >> 8); // dummy (3), PCR pid hi (5)
|
||||||
|
p[i++] = Vpid; // PCR pid lo
|
||||||
|
p[i++] = 0xF0; // dummy (4), program info length hi (4)
|
||||||
|
p[i++] = 0x00; // program info length lo
|
||||||
|
|
||||||
|
if (Vpid)
|
||||||
|
i += MakeStream(buf + i, Channel->Vtype(), Vpid);
|
||||||
|
for (int n = 0; Channel->Apid(n); n++) {
|
||||||
|
i += MakeStream(buf + i, 0x04, Channel->Apid(n));
|
||||||
|
const char *Alang = Channel->Alang(n);
|
||||||
|
i += MakeLanguageDescriptor(buf + i, Alang);
|
||||||
|
if (Alang[3] == '+')
|
||||||
|
i += MakeLanguageDescriptor(buf + i, Alang + 3);
|
||||||
|
}
|
||||||
|
for (int n = 0; Channel->Dpid(n); n++) {
|
||||||
|
i += MakeStream(buf + i, 0x06, Channel->Dpid(n));
|
||||||
|
i += MakeAC3Descriptor(buf + i);
|
||||||
|
i += MakeLanguageDescriptor(buf + i, Channel->Dlang(n));
|
||||||
|
}
|
||||||
|
for (int n = 0; Channel->Spid(n); n++) {
|
||||||
|
i += MakeStream(buf + i, 0x06, Channel->Spid(n));
|
||||||
|
i += MakeSubtitlingDescriptor(buf + i, Channel->Slang(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
int sl = i - SectionLength - 2 + 4; // -2 = SectionLength storage, +4 = length of CRC
|
||||||
|
buf[SectionLength] |= (sl >> 8) & 0x0F;
|
||||||
|
buf[SectionLength + 1] = sl;
|
||||||
|
MakeCRC(buf + i, buf, i);
|
||||||
|
// split the PMT section into several TS packets:
|
||||||
|
uchar *q = buf;
|
||||||
|
while (i > 0) {
|
||||||
|
uchar *p = pmt[numPmtPackets++];
|
||||||
|
int j = 0;
|
||||||
|
p[j++] = 0x47; // TS indicator
|
||||||
|
p[j++] = 0x40 | (P_PNR >> 8); // flags (3), pid hi (5)
|
||||||
|
p[j++] = P_PNR & 0xFF; // pid lo
|
||||||
|
p[j++] = 0x10; // flags (4), continuity counter (4)
|
||||||
|
int l = TS_SIZE - j;
|
||||||
|
memcpy(p + j, q, l);
|
||||||
|
q += l;
|
||||||
|
i -= l;
|
||||||
|
}
|
||||||
|
IncVersion(pmtVersion);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esyslog("ERROR: can't find channel %s", *ChannelID.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
uchar *cPatPmtGenerator::GetPat(void)
|
||||||
|
{
|
||||||
|
IncCounter(patCounter, pat);
|
||||||
|
return pat;
|
||||||
|
}
|
||||||
|
|
||||||
|
uchar *cPatPmtGenerator::GetPmt(int &Index)
|
||||||
|
{
|
||||||
|
if (Index < numPmtPackets) {
|
||||||
|
IncCounter(patCounter, pmt[Index]);
|
||||||
|
return pmt[Index++];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- cPatPmtParser ---------------------------------------------------------
|
||||||
|
|
||||||
|
cPatPmtParser::cPatPmtParser(void)
|
||||||
|
{
|
||||||
|
pmtSize = 0;
|
||||||
|
pmtPid = -1;
|
||||||
|
vpid = vtype = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cPatPmtParser::ParsePat(const uchar *Data, int Length)
|
||||||
|
{
|
||||||
|
// The PAT is always assumed to fit into a single TS packet
|
||||||
|
SI::PAT Pat(Data, false);
|
||||||
|
if (Pat.CheckCRCAndParse()) {
|
||||||
|
dbgpatpmt("PAT: TSid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pat.getTransportStreamId(), Pat.getCurrentNextIndicator(), Pat.getVersionNumber(), Pat.getSectionNumber(), Pat.getLastSectionNumber());
|
||||||
|
SI::PAT::Association assoc;
|
||||||
|
for (SI::Loop::Iterator it; Pat.associationLoop.getNext(assoc, it); ) {
|
||||||
|
dbgpatpmt(" isNITPid = %d\n", assoc.isNITPid());
|
||||||
|
if (!assoc.isNITPid()) {
|
||||||
|
pmtPid = assoc.getPid();
|
||||||
|
dbgpatpmt(" service id = %d, pid = %d\n", assoc.getServiceId(), assoc.getPid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esyslog("ERROR: can't parse PAT");
|
||||||
|
}
|
||||||
|
|
||||||
|
void cPatPmtParser::ParsePmt(const uchar *Data, int Length)
|
||||||
|
{
|
||||||
|
// The PMT may extend over several TS packets, so we need to assemble them
|
||||||
|
if (pmtSize == 0) {
|
||||||
|
// this is the first packet
|
||||||
|
if (SectionLength(Data, Length) > Length) {
|
||||||
|
if (Length <= int(sizeof(pmt))) {
|
||||||
|
memcpy(pmt, Data, Length);
|
||||||
|
pmtSize = Length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esyslog("ERROR: PMT packet length too big (%d byte)!", Length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// the packet contains the entire PMT section, so we run into the actual parsing
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// this is a following packet, so we add it to the pmt storage
|
||||||
|
if (Length <= int(sizeof(pmt)) - pmtSize) {
|
||||||
|
memcpy(pmt + pmtSize, Data, Length);
|
||||||
|
pmtSize += Length;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
esyslog("ERROR: PMT section length too big (%d byte)!", pmtSize + Length);
|
||||||
|
pmtSize = 0;
|
||||||
|
}
|
||||||
|
if (SectionLength(pmt, pmtSize) > pmtSize)
|
||||||
|
return; // more packets to come
|
||||||
|
// the PMT section is now complete, so we run into the actual parsing
|
||||||
|
Data = pmt;
|
||||||
|
}
|
||||||
|
SI::PMT Pmt(Data, false);
|
||||||
|
if (Pmt.CheckCRCAndParse()) {
|
||||||
|
dbgpatpmt("PMT: sid = %d, c/n = %d, v = %d, s = %d, ls = %d\n", Pmt.getServiceId(), Pmt.getCurrentNextIndicator(), Pmt.getVersionNumber(), Pmt.getSectionNumber(), Pmt.getLastSectionNumber());
|
||||||
|
dbgpatpmt(" pcr = %d\n", Pmt.getPCRPid());
|
||||||
|
cDevice::PrimaryDevice()->ClrAvailableTracks(false, true);
|
||||||
|
int NumApids = 0;
|
||||||
|
int NumDpids = 0;
|
||||||
|
int NumSpids = 0;
|
||||||
|
SI::PMT::Stream stream;
|
||||||
|
for (SI::Loop::Iterator it; Pmt.streamLoop.getNext(stream, it); ) {
|
||||||
|
dbgpatpmt(" stream type = %02X, pid = %d", stream.getStreamType(), stream.getPid());
|
||||||
|
switch (stream.getStreamType()) {
|
||||||
|
case 0x02: // STREAMTYPE_13818_VIDEO
|
||||||
|
case 0x1B: // MPEG4
|
||||||
|
vpid = stream.getPid();
|
||||||
|
vtype = stream.getStreamType();
|
||||||
|
break;
|
||||||
|
case 0x04: // STREAMTYPE_13818_AUDIO
|
||||||
|
{
|
||||||
|
if (NumApids < MAXAPIDS) {
|
||||||
|
char ALangs[MAXLANGCODE2] = "";
|
||||||
|
SI::Descriptor *d;
|
||||||
|
for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
|
||||||
|
switch (d->getDescriptorTag()) {
|
||||||
|
case SI::ISO639LanguageDescriptorTag: {
|
||||||
|
SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d;
|
||||||
|
SI::ISO639LanguageDescriptor::Language l;
|
||||||
|
char *s = ALangs;
|
||||||
|
int n = 0;
|
||||||
|
for (SI::Loop::Iterator it; ld->languageLoop.getNext(l, it); ) {
|
||||||
|
if (*ld->languageCode != '-') { // some use "---" to indicate "none"
|
||||||
|
dbgpatpmt(" '%s'", l.languageCode);
|
||||||
|
if (n > 0)
|
||||||
|
*s++ = '+';
|
||||||
|
strn0cpy(s, I18nNormalizeLanguageCode(l.languageCode), MAXLANGCODE1);
|
||||||
|
s += strlen(s);
|
||||||
|
if (n++ > 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
cDevice::PrimaryDevice()->SetAvailableTrack(ttAudio, NumApids, stream.getPid(), ALangs);
|
||||||
|
NumApids++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x06: // STREAMTYPE_13818_PES_PRIVATE
|
||||||
|
{
|
||||||
|
int dpid = 0;
|
||||||
|
char lang[MAXLANGCODE1] = "";
|
||||||
|
SI::Descriptor *d;
|
||||||
|
for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
|
||||||
|
switch (d->getDescriptorTag()) {
|
||||||
|
case SI::AC3DescriptorTag:
|
||||||
|
dbgpatpmt(" AC3");
|
||||||
|
dpid = stream.getPid();
|
||||||
|
break;
|
||||||
|
case SI::SubtitlingDescriptorTag:
|
||||||
|
dbgpatpmt(" subtitling");
|
||||||
|
if (NumSpids < MAXSPIDS) {
|
||||||
|
SI::SubtitlingDescriptor *sd = (SI::SubtitlingDescriptor *)d;
|
||||||
|
SI::SubtitlingDescriptor::Subtitling sub;
|
||||||
|
char SLangs[MAXLANGCODE2] = "";
|
||||||
|
char *s = SLangs;
|
||||||
|
int n = 0;
|
||||||
|
for (SI::Loop::Iterator it; sd->subtitlingLoop.getNext(sub, it); ) {
|
||||||
|
if (sub.languageCode[0]) {
|
||||||
|
dbgpatpmt(" '%s'", sub.languageCode);
|
||||||
|
if (n > 0)
|
||||||
|
*s++ = '+';
|
||||||
|
strn0cpy(s, I18nNormalizeLanguageCode(sub.languageCode), MAXLANGCODE1);
|
||||||
|
s += strlen(s);
|
||||||
|
if (n++ > 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cDevice::PrimaryDevice()->SetAvailableTrack(ttSubtitle, NumSpids, stream.getPid(), SLangs);
|
||||||
|
NumSpids++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SI::ISO639LanguageDescriptorTag: {
|
||||||
|
SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d;
|
||||||
|
dbgpatpmt(" '%s'", ld->languageCode);
|
||||||
|
strn0cpy(lang, I18nNormalizeLanguageCode(ld->languageCode), MAXLANGCODE1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
if (dpid) {
|
||||||
|
if (NumDpids < MAXDPIDS) {
|
||||||
|
cDevice::PrimaryDevice()->SetAvailableTrack(ttDolby, NumDpids, dpid, lang);
|
||||||
|
NumDpids++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dbgpatpmt("\n");
|
||||||
|
cDevice::PrimaryDevice()->EnsureAudioTrack(true);
|
||||||
|
cDevice::PrimaryDevice()->EnsureSubtitleTrack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esyslog("ERROR: can't parse PMT");
|
||||||
|
pmtSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- cTsToPes --------------------------------------------------------------
|
||||||
|
|
||||||
|
cTsToPes::cTsToPes(void)
|
||||||
|
{
|
||||||
|
data = NULL;
|
||||||
|
size = length = 0;
|
||||||
|
synced = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cTsToPes::~cTsToPes()
|
||||||
|
{
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTsToPes::PutTs(const uchar *Data, int Length)
|
||||||
|
{
|
||||||
|
if (TsPayloadStart(Data))
|
||||||
|
Reset();
|
||||||
|
else if (!size)
|
||||||
|
return; // skip everything before the first payload start
|
||||||
|
Length = TsGetPayload(&Data);
|
||||||
|
if (length + Length > size) {
|
||||||
|
size = max(KILOBYTE(2), length + Length);
|
||||||
|
data = (uchar *)realloc(data, size);
|
||||||
|
}
|
||||||
|
memcpy(data + length, Data, Length);
|
||||||
|
length += Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uchar *cTsToPes::GetPes(int &Length)
|
||||||
|
{
|
||||||
|
if (PesLongEnough(length)) {
|
||||||
|
Length = PesLength(data);
|
||||||
|
if (Length <= length) {
|
||||||
|
Length = length; // in case the PES packet has no explicit length, as is the case for video PES
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTsToPes::Reset(void)
|
||||||
|
{
|
||||||
|
length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Some helper functions for debugging -----------------------------------
|
||||||
|
|
||||||
|
void BlockDump(const char *Name, const u_char *Data, int Length)
|
||||||
|
{
|
||||||
|
printf("--- %s\n", Name);
|
||||||
|
for (int i = 0; i < Length; i++) {
|
||||||
|
if (i && (i % 16) == 0)
|
||||||
|
printf("\n");
|
||||||
|
printf(" %02X", Data[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TsDump(const char *Name, const u_char *Data, int Length)
|
||||||
|
{
|
||||||
|
printf("%s: %04X", Name, Length);
|
||||||
|
int n = min(Length, 20);
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
printf(" %02X", Data[i]);
|
||||||
|
if (n < Length) {
|
||||||
|
printf(" ...");
|
||||||
|
n = max(n, Length - 10);
|
||||||
|
for (n = max(n, Length - 10); n < Length; n++)
|
||||||
|
printf(" %02X", Data[n]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PesDump(const char *Name, const u_char *Data, int Length)
|
||||||
|
{
|
||||||
|
TsDump(Name, Data, Length);
|
||||||
|
}
|
||||||
|
193
remux.h
193
remux.h
@ -4,14 +4,13 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: remux.h 2.0 2007/09/02 10:19:06 kls Exp $
|
* $Id: remux.h 2.2 2008/09/06 14:48:28 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __REMUX_H
|
#ifndef __REMUX_H
|
||||||
#define __REMUX_H
|
#define __REMUX_H
|
||||||
|
|
||||||
#include <time.h> //XXX FIXME: DVB/linux/dvb/dmx.h should include <time.h> itself!!!
|
#include "channels.h"
|
||||||
#include <linux/dvb/dmx.h>
|
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
@ -81,4 +80,192 @@ public:
|
|||||||
static int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType);
|
static int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Some TS handling tools.
|
||||||
|
// The following functions all take a pointer to one complete TS packet.
|
||||||
|
|
||||||
|
#define TS_SYNC_BYTE 0x47
|
||||||
|
#define TS_SIZE 188
|
||||||
|
#define TS_ADAPT_FIELD_EXISTS 0x20
|
||||||
|
#define TS_PAYLOAD_EXISTS 0x10
|
||||||
|
#define TS_CONT_CNT_MASK 0x0F
|
||||||
|
#define TS_PAYLOAD_START 0x40
|
||||||
|
#define TS_ERROR 0x80
|
||||||
|
#define TS_PID_MASK_HI 0x1F
|
||||||
|
|
||||||
|
inline int TsHasPayload(const uchar *p)
|
||||||
|
{
|
||||||
|
return p[3] & TS_PAYLOAD_EXISTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int TsPayloadStart(const uchar *p)
|
||||||
|
{
|
||||||
|
return p[1] & TS_PAYLOAD_START;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int TsError(const uchar *p)
|
||||||
|
{
|
||||||
|
return p[1] & TS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int TsPid(const uchar *p)
|
||||||
|
{
|
||||||
|
return (p[1] & TS_PID_MASK_HI) * 256 + p[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int TsPayloadOffset(const uchar *p)
|
||||||
|
{
|
||||||
|
return (p[3] & TS_ADAPT_FIELD_EXISTS) ? p[4] + 5 : 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int TsGetPayload(const uchar **p)
|
||||||
|
{
|
||||||
|
int o = TsPayloadOffset(*p);
|
||||||
|
*p += o;
|
||||||
|
return TS_SIZE - o;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int TsContinuityCounter(const uchar *p)
|
||||||
|
{
|
||||||
|
return p[3] & TS_CONT_CNT_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some PES handling tools:
|
||||||
|
// The following functions that take a pointer to PES data all assume that
|
||||||
|
// there is enough data so that PesLongEnough() returns true.
|
||||||
|
|
||||||
|
inline bool PesLongEnough(int Length)
|
||||||
|
{
|
||||||
|
return Length >= 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int PesLength(const uchar *p)
|
||||||
|
{
|
||||||
|
return 6 + p[4] * 256 + p[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int PesPayloadOffset(const uchar *p)
|
||||||
|
{
|
||||||
|
return 9 + p[8];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int64_t PesGetPts(const uchar *p)
|
||||||
|
{
|
||||||
|
if ((p[7] & 0x80) && p[8] >= 5) {
|
||||||
|
return ((((int64_t)p[ 9]) & 0x0E) << 29) |
|
||||||
|
(( (int64_t)p[10]) << 22) |
|
||||||
|
((((int64_t)p[11]) & 0xFE) << 14) |
|
||||||
|
(( (int64_t)p[12]) << 7) |
|
||||||
|
((((int64_t)p[13]) & 0xFE) >> 1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PAT/PMT Generator:
|
||||||
|
|
||||||
|
#define MAX_SECTION_SIZE 4096 // maximum size of an SI section
|
||||||
|
#define MAX_PMT_TS (MAX_SECTION_SIZE / TS_SIZE + 1)
|
||||||
|
|
||||||
|
class cPatPmtGenerator {
|
||||||
|
private:
|
||||||
|
uchar pat[TS_SIZE]; // the PAT always fits into a single TS packet
|
||||||
|
uchar pmt[MAX_PMT_TS][TS_SIZE]; // the PMT may well extend over several TS packets
|
||||||
|
int numPmtPackets;
|
||||||
|
int patCounter;
|
||||||
|
int pmtCounter;
|
||||||
|
int patVersion;
|
||||||
|
int pmtVersion;
|
||||||
|
uchar *esInfoLength;
|
||||||
|
void IncCounter(int &Counter, uchar *TsPacket);
|
||||||
|
void IncVersion(int &Version);
|
||||||
|
void IncEsInfoLength(int Length);
|
||||||
|
protected:
|
||||||
|
int MakeStream(uchar *Target, uchar Type, int Pid);
|
||||||
|
int MakeAC3Descriptor(uchar *Target);
|
||||||
|
int MakeSubtitlingDescriptor(uchar *Target, const char *Language);
|
||||||
|
int MakeLanguageDescriptor(uchar *Target, const char *Language);
|
||||||
|
int MakeCRC(uchar *Target, const uchar *Data, int Length);
|
||||||
|
public:
|
||||||
|
cPatPmtGenerator(void);
|
||||||
|
void GeneratePat(void);
|
||||||
|
///< Generates a PAT section for later use with GetPat().
|
||||||
|
///< This function is called by default from the constructor.
|
||||||
|
void GeneratePmt(tChannelID ChannelID);
|
||||||
|
///< Generates a PMT section for the given ChannelId, for later use
|
||||||
|
///< with GetPmt().
|
||||||
|
uchar *GetPat(void);
|
||||||
|
///< Returns a pointer to the PAT section, which consist of exactly
|
||||||
|
///< one TS packet.
|
||||||
|
uchar *GetPmt(int &Index);
|
||||||
|
///< Returns a pointer to the Index'th TS packet of the PMT section.
|
||||||
|
///< Index must be initialized to 0 and will be incremented by each
|
||||||
|
///< call to GetPmt(). Returns NULL is all packets of the PMT section
|
||||||
|
///< have been fetched..
|
||||||
|
};
|
||||||
|
|
||||||
|
// PAT/PMT Parser:
|
||||||
|
|
||||||
|
class cPatPmtParser {
|
||||||
|
private:
|
||||||
|
uchar pmt[MAX_SECTION_SIZE];
|
||||||
|
int pmtSize;
|
||||||
|
int pmtPid;
|
||||||
|
int vpid;
|
||||||
|
int vtype;
|
||||||
|
protected:
|
||||||
|
int SectionLength(const uchar *Data, int Length) { return (Length >= 3) ? ((int(Data[1]) & 0x0F) << 8)| Data[2] : 0; }
|
||||||
|
public:
|
||||||
|
cPatPmtParser(void);
|
||||||
|
void ParsePat(const uchar *Data, int Length);
|
||||||
|
///< Parses the given PAT Data, which is the payload of a single TS packet
|
||||||
|
///< from the PAT stream. The PAT may consist only of a single TS packet.
|
||||||
|
void ParsePmt(const uchar *Data, int Length);
|
||||||
|
///< Parses the given PMT Data, which is the payload of a single TS packet
|
||||||
|
///< from the PMT stream. The PMT may consist of several TS packets, which
|
||||||
|
///< are delivered to the parser through several subsequent calls to
|
||||||
|
///< ParsePmt(). The whole PMT data will be processed once the last packet
|
||||||
|
///< has been received.
|
||||||
|
int PmtPid(void) { return pmtPid; }
|
||||||
|
///< Returns the PMT pid as defined by the current PAT.
|
||||||
|
///< If no PAT has been received yet, -1 will be returned.
|
||||||
|
int Vpid(void) { return vpid; }
|
||||||
|
///< Returns the video pid as defined by the current PMT.
|
||||||
|
int Vtype(void) { return vtype; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// TS to PES converter:
|
||||||
|
// Puts together the payload of several TS packets that form one PES
|
||||||
|
// packet.
|
||||||
|
|
||||||
|
class cTsToPes {
|
||||||
|
private:
|
||||||
|
uchar *data;
|
||||||
|
int size;
|
||||||
|
int length;
|
||||||
|
bool synced;
|
||||||
|
public:
|
||||||
|
cTsToPes(void);
|
||||||
|
~cTsToPes();
|
||||||
|
void PutTs(const uchar *Data, int Length);
|
||||||
|
///< Puts the payload data of the single TS packet at Data into the converter.
|
||||||
|
///< Length is always 188.
|
||||||
|
///< If the given TS packet starts a new PES payload packet, the converter
|
||||||
|
///< will be automatically reset. Any packets before the first one that starts
|
||||||
|
///< a new PES payload packet will be ignored.
|
||||||
|
const uchar *GetPes(int &Length);
|
||||||
|
///< Gets a pointer to the complete PES packet, or NULL if the packet
|
||||||
|
///< is not complete yet. If the packet is complete, Length will contain
|
||||||
|
///< the total packet length. The returned pointer is only valid until
|
||||||
|
///< the next call to PutTs() or Reset(), or until this object is destroyed.
|
||||||
|
void Reset(void);
|
||||||
|
///< Resets the converter. This needs to be called after a PES packet has
|
||||||
|
///< been fetched by a call to GetPes(), and before the next call to
|
||||||
|
///< PutTs().
|
||||||
|
};
|
||||||
|
|
||||||
|
// Some helper functions for debugging:
|
||||||
|
|
||||||
|
void BlockDump(const char *Name, const u_char *Data, int Length);
|
||||||
|
void TsDump(const char *Name, const u_char *Data, int Length);
|
||||||
|
void PesDump(const char *Name, const u_char *Data, int Length);
|
||||||
|
|
||||||
#endif // __REMUX_H
|
#endif // __REMUX_H
|
||||||
|
100
sources.conf
100
sources.conf
@ -19,29 +19,34 @@
|
|||||||
|
|
||||||
# Europe
|
# Europe
|
||||||
|
|
||||||
S5E Sirius 2/3
|
S3E Telecom 2C
|
||||||
|
S4E Eurobird 4
|
||||||
|
S5E Sirius 4
|
||||||
S7E Eutelsat W3A
|
S7E Eutelsat W3A
|
||||||
|
S9E Eurobird 9
|
||||||
S10E Eutelsat W1
|
S10E Eutelsat W1
|
||||||
S13E Hotbird 1-3/6/7A
|
S13E Hotbird 6/7A/8
|
||||||
S16E Eutelsat W2
|
S16E Eutelsat W2
|
||||||
S19.2E Astra 1B/C/E/F/G/H/2C
|
S19.2E Astra F/G/H/KR/L
|
||||||
S21.0E Afristar 1
|
S21.0E Afristar 1
|
||||||
S21.6E Eutelsat W6
|
S21.6E Eutelsat W6
|
||||||
S23.5E Astra 1D 3A
|
S23.5E Astra 1E/3A
|
||||||
S26E Arabsat 2D/2C/3A
|
S25.5E Eurobird 2
|
||||||
|
S26E Badr 3/4/6
|
||||||
S28.2E Astra 2D/A/B
|
S28.2E Astra 2D/A/B
|
||||||
S28.5E Eurobird 1 & Astra 2A/B/D
|
S28.5E Eurobird 1 & Astra 2A/B/C/D
|
||||||
S30.5E Arabsat 2B
|
S30.5E Arabsat 2B
|
||||||
|
S31.5E Astra 1D/5A
|
||||||
S33E Eurobird 3 & Intelsat 802
|
S33E Eurobird 3 & Intelsat 802
|
||||||
S36E Eutelsat W4 & Sesat
|
S36E Eutelsat W4 & Sesat
|
||||||
S38E Paksat 1
|
S38E Paksat 1
|
||||||
S39E Hellas Sat 2
|
S39E Hellas Sat 2
|
||||||
S40E Express AM1
|
S40E Express AM1
|
||||||
S42E Turksat 1C/2A
|
S42E Turksat 2A/3A
|
||||||
S45E Intelsat 12
|
S45E Intelsat 12
|
||||||
S49E Yamal 202
|
S49E Yamal 202
|
||||||
S53E Express AM 22
|
S53E Express AM 22
|
||||||
S55E Insat 3E & Intelsat 702
|
S55E Insat 3E
|
||||||
S56E Bonum 1
|
S56E Bonum 1
|
||||||
S57E NSS 703
|
S57E NSS 703
|
||||||
S60E Intelsat 904
|
S60E Intelsat 904
|
||||||
@ -54,10 +59,10 @@ S72E Intelsat 4
|
|||||||
|
|
||||||
# Asia
|
# Asia
|
||||||
|
|
||||||
S74E Insat 3C & Edusat
|
S74E Insat 3C/4CR & Edusat
|
||||||
S75E LMI 1
|
S75E ABS 1
|
||||||
S76.5E Telstar 10
|
S76.5E Telstar 10
|
||||||
S78.5E Thaicom 2/3
|
S78.5E Thaicom 2/5
|
||||||
S80E Express AM2
|
S80E Express AM2
|
||||||
S83E Insat 2E/3B/4A
|
S83E Insat 2E/3B/4A
|
||||||
S85.2E Intelsat 709
|
S85.2E Intelsat 709
|
||||||
@ -65,14 +70,17 @@ S87.5E Chinastar 1
|
|||||||
S88E ST 1
|
S88E ST 1
|
||||||
S90E Yamal 201
|
S90E Yamal 201
|
||||||
S91.5E Measat 1
|
S91.5E Measat 1
|
||||||
S93.5E Insat 3A
|
S92.2E Chinasat 9
|
||||||
|
S93.5E Insat 3A/4B
|
||||||
S95E NSS 6
|
S95E NSS 6
|
||||||
S96.5E Express AM 11
|
S96.5E Express AM 33
|
||||||
|
S98.5E Protostar 1
|
||||||
S100.5E Asiasat 2
|
S100.5E Asiasat 2
|
||||||
S103E Express A2
|
S103E Express A2
|
||||||
|
S105E Asiastar
|
||||||
S105.5E Asiasat 3S
|
S105.5E Asiasat 3S
|
||||||
S107.7E Cakrawarta 1
|
S107.7E Cakrawarta 1
|
||||||
S108E Telkom 1 & AAP 1
|
S108E Telkom 1 & NSS 11
|
||||||
S110E N-Sat 110 & BSAT 1A/2A
|
S110E N-Sat 110 & BSAT 1A/2A
|
||||||
S110.5E Sinosat 1
|
S110.5E Sinosat 1
|
||||||
S113E Palapa C2 & Koreasat 2
|
S113E Palapa C2 & Koreasat 2
|
||||||
@ -81,38 +89,38 @@ S118E Telkom 2
|
|||||||
S120E Thaicom 1A
|
S120E Thaicom 1A
|
||||||
S122.2E Asiasat 4
|
S122.2E Asiasat 4
|
||||||
S124E JCSAT 4a
|
S124E JCSAT 4a
|
||||||
|
S125E Sinosat 3
|
||||||
S128E JCSAT 3
|
S128E JCSAT 3
|
||||||
S132E N-Star A
|
S132E Vinasat 1 & JCSAT5a
|
||||||
S134E Apstar 6
|
S134E Apstar 6
|
||||||
S136E N-Star B
|
|
||||||
S138E Telstar 18
|
S138E Telstar 18
|
||||||
S140E Express AM 3
|
S140E Express AM 3
|
||||||
S144E Superbird C
|
S144E Superbird C
|
||||||
S146E Agila 2
|
S146E Agila 2
|
||||||
S148E Measat 2
|
S148E Measat 2
|
||||||
S150E JCSAT R
|
S150E JCSAT R
|
||||||
S152E Optus B3
|
S152E Optus D2
|
||||||
S154E JCSAT 2A
|
S154E JCSAT 2A
|
||||||
S156E Optus C1
|
S156E Optus C1
|
||||||
S158E Superbird A
|
S158E Superbird A
|
||||||
S160E Optus B1
|
S160E Optus D1
|
||||||
S162E Superbird B2
|
S162E Superbird B2
|
||||||
S164E Optus A3
|
S164E Optus B3
|
||||||
S166E Intelsat 8
|
S166E Intelsat 8
|
||||||
S169E Intelsat 2
|
S169E Intelsat 2
|
||||||
S172E AMC 23
|
S172E GE 23
|
||||||
S180E Intelsat 701
|
S180E Intelsat 701
|
||||||
S177W NSS 5
|
S177W NSS 5
|
||||||
|
|
||||||
# Atlantic
|
# Atlantic
|
||||||
|
|
||||||
S1W Thor 2/3 & Intelsat 10-02
|
S1W Thor 3/5 & Intelsat 10-02
|
||||||
S4W Amos 1/2
|
S4W Amos 1/2/3
|
||||||
S5W Atlantic Bird 3
|
S5W Atlantic Bird 3
|
||||||
S7W Nilesat 101 & 102
|
S7W Nilesat 101/102 & Atlantic Bird 4
|
||||||
S8W Telecom 2D & Atlantic Bird 2
|
S8W Telecom 2D & Atlantic Bird 2
|
||||||
S11W Express A3
|
S11W Express A3
|
||||||
S12.5W Atlantic Bird 2
|
S12.5W Atlantic Bird 1
|
||||||
S14W Express A4
|
S14W Express A4
|
||||||
S15W Telstar 12
|
S15W Telstar 12
|
||||||
S18W Intelsat 901
|
S18W Intelsat 901
|
||||||
@ -123,9 +131,9 @@ S27.5W Intelsat 907
|
|||||||
S30W Hispasat 1C/1D
|
S30W Hispasat 1C/1D
|
||||||
S31.5W Intelsat 801
|
S31.5W Intelsat 801
|
||||||
S34.5W Intelsat 903
|
S34.5W Intelsat 903
|
||||||
S37.5W Telstar 11 & AMC 12
|
S37.5W NSS 10
|
||||||
S40.5W NSS 806
|
S40.5W NSS 806
|
||||||
S43W Intelsat 3R/6B
|
S43W Intelsat 3R/11
|
||||||
S45W Intelsat 1R
|
S45W Intelsat 1R
|
||||||
S50W Intelsat 705
|
S50W Intelsat 705
|
||||||
S53W Intelsat 707
|
S53W Intelsat 707
|
||||||
@ -137,47 +145,45 @@ S61W Amazonas
|
|||||||
|
|
||||||
S61.5W Echostar 3 & Rainbow 1
|
S61.5W Echostar 3 & Rainbow 1
|
||||||
S63W Estrelo de Sul 1
|
S63W Estrelo de Sul 1
|
||||||
S65W Brasilsat B2
|
S65W Star One C1
|
||||||
S70W Brasilsat B1
|
S70W Star One C2
|
||||||
S72W Nahuel 1 & AMC 6
|
S72W Nahuel 1 & AMC 6
|
||||||
S72.5W DirecTV 1
|
S72.5W DirecTV 1R & Echostar 6
|
||||||
S74W SBS 6
|
S74W Horizons 2
|
||||||
S77W Echostar 4
|
S77W Echostar 4 & Galaxy 4R
|
||||||
S79W AMC5
|
S79W AMC5
|
||||||
S79.5W Nimiq 3
|
|
||||||
S82W Nimiq 2
|
S82W Nimiq 2
|
||||||
S83W AMC 9
|
S83W AMC 9
|
||||||
S84W Brasilsat B3
|
S84W Brasilsat B3/4
|
||||||
S85W AMC 2
|
S85W AMC 16
|
||||||
S85.1W XM 3
|
S85.1W XM 3
|
||||||
S87W AMC3
|
S87W AMC3
|
||||||
S89W Galaxy 28
|
S89W Galaxy 28
|
||||||
S91W Galaxy 11 & Nimiq 1
|
S91W Galaxy 11/17 & Nimiq 1
|
||||||
S91.5W DirecTV 2
|
S92W Brasilsat B2
|
||||||
S92W Brasilsat B4
|
|
||||||
S93W Galaxy 26
|
S93W Galaxy 26
|
||||||
S95W Galaxy 3C
|
S95W Galaxy 3C
|
||||||
S97W Galaxy 25
|
S97W Galaxy 25
|
||||||
S99W Galaxy 4R
|
S99W Galaxy 16
|
||||||
S99.2W Spaceway 2
|
S99.2W Spaceway 2 & DirecTV 11
|
||||||
S101W DirecTV 1R/4S/8 & AMC4
|
S101W DirecTV 4S/8 & AMC 2/4
|
||||||
S103W AMC1
|
S103W AMC1
|
||||||
S105W AMC15
|
S105W AMC15/18
|
||||||
S107.3W Anik F1/F1R
|
S107.3W Anik F1/F1R
|
||||||
S110W DirecTV 5 & Echostar 6/8/10
|
S110W DirecTV 5 & Echostar 8/10
|
||||||
S111.1W Anik F2
|
S111.1W Anik F2
|
||||||
S113W Solidaridad 2
|
S113W SatMex 6
|
||||||
S119W Echostar 7 & DirecTV 7S
|
S116.8W SatMex 5
|
||||||
|
S119W Anik F3 & Echostar 7 & DirecTV 7S
|
||||||
S121W Echostar 9 & Galaxy 23
|
S121W Echostar 9 & Galaxy 23
|
||||||
S123W Galaxy 10R
|
S123W Galaxy 18
|
||||||
S125W Galaxy 14
|
S125W Galaxy 14
|
||||||
S127W Galaxy 13/Horizons 1
|
S127W Galaxy 13/Horizons 1
|
||||||
S129W Echostar 5 & Galaxy 27
|
S129W Echostar 5 & Galaxy 27
|
||||||
S131W AMC 11
|
S131W AMC 11
|
||||||
S133W Galaxy15/1R
|
S133W Galaxy15
|
||||||
S135W AMC 10
|
S135W AMC 10
|
||||||
S137W AMC 7
|
S137W AMC 7
|
||||||
S138.5W Echostar 10
|
|
||||||
S139W AMC 8
|
S139W AMC 8
|
||||||
S148W Echostar 1/2
|
S148W Echostar 1/2
|
||||||
|
|
||||||
|
4
svdrp.c
4
svdrp.c
@ -10,7 +10,7 @@
|
|||||||
* and interact with the Video Disk Recorder - or write a full featured
|
* and interact with the Video Disk Recorder - or write a full featured
|
||||||
* graphical interface that sits on top of an SVDRP connection.
|
* graphical interface that sits on top of an SVDRP connection.
|
||||||
*
|
*
|
||||||
* $Id: svdrp.c 2.0 2008/02/17 13:36:01 kls Exp $
|
* $Id: svdrp.c 2.1 2008/05/02 14:15:38 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "svdrp.h"
|
#include "svdrp.h"
|
||||||
@ -1606,7 +1606,7 @@ bool cSVDRP::Process(void)
|
|||||||
char buffer[BUFSIZ];
|
char buffer[BUFSIZ];
|
||||||
gethostname(buffer, sizeof(buffer));
|
gethostname(buffer, sizeof(buffer));
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
Reply(220, "%s SVDRP VideoDiskRecorder %s; %s", buffer, VDRVERSION, *TimeToString(now));
|
Reply(220, "%s SVDRP VideoDiskRecorder %s; %s; %s", buffer, VDRVERSION, *TimeToString(now), cCharSetConv::SystemCharacterTable() ? cCharSetConv::SystemCharacterTable() : "UTF-8");
|
||||||
}
|
}
|
||||||
if (NewConnection)
|
if (NewConnection)
|
||||||
lastActivity = time(NULL);
|
lastActivity = time(NULL);
|
||||||
|
13
thread.c
13
thread.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: thread.c 2.1 2008/04/13 11:53:56 kls Exp $
|
* $Id: thread.c 2.2 2008/09/06 09:39:43 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
@ -25,11 +25,12 @@ static bool GetAbsTime(struct timespec *Abstime, int MillisecondsFromNow)
|
|||||||
{
|
{
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
if (gettimeofday(&now, NULL) == 0) { // get current time
|
if (gettimeofday(&now, NULL) == 0) { // get current time
|
||||||
now.tv_usec += MillisecondsFromNow * 1000; // add the timeout
|
now.tv_sec += MillisecondsFromNow / 1000; // add full seconds
|
||||||
while (now.tv_usec >= 1000000) { // take care of an overflow
|
now.tv_usec += (MillisecondsFromNow % 1000) * 1000; // add microseconds
|
||||||
now.tv_sec++;
|
if (now.tv_usec >= 1000000) { // take care of an overflow
|
||||||
now.tv_usec -= 1000000;
|
now.tv_sec++;
|
||||||
}
|
now.tv_usec -= 1000000;
|
||||||
|
}
|
||||||
Abstime->tv_sec = now.tv_sec; // seconds
|
Abstime->tv_sec = now.tv_sec; // seconds
|
||||||
Abstime->tv_nsec = now.tv_usec * 1000; // nano seconds
|
Abstime->tv_nsec = now.tv_usec * 1000; // nano seconds
|
||||||
return true;
|
return true;
|
||||||
|
4
tools.h
4
tools.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: tools.h 2.0 2008/02/17 13:41:27 kls Exp $
|
* $Id: tools.h 2.1 2008/05/22 10:26:57 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __TOOLS_H
|
#ifndef __TOOLS_H
|
||||||
@ -136,7 +136,7 @@ public:
|
|||||||
///< If ToCode is NULL, "UTF-8" is used.
|
///< If ToCode is NULL, "UTF-8" is used.
|
||||||
~cCharSetConv();
|
~cCharSetConv();
|
||||||
const char *Convert(const char *From, char *To = NULL, size_t ToLength = 0);
|
const char *Convert(const char *From, char *To = NULL, size_t ToLength = 0);
|
||||||
///< Converts the given Text from FromCode to ToCode (as set in the cosntructor).
|
///< Converts the given Text from FromCode to ToCode (as set in the constructor).
|
||||||
///< If To is given, it is used to copy at most ToLength bytes of the result
|
///< If To is given, it is used to copy at most ToLength bytes of the result
|
||||||
///< (including the terminating 0) into that buffer. If To is not given,
|
///< (including the terminating 0) into that buffer. If To is not given,
|
||||||
///< the result is copied into a dynamically allocated buffer and is valid as
|
///< the result is copied into a dynamically allocated buffer and is valid as
|
||||||
|
95
transfer.c
95
transfer.c
@ -4,109 +4,52 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: transfer.c 2.0 2007/01/05 10:45:28 kls Exp $
|
* $Id: transfer.c 2.1 2008/08/15 14:32:12 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "transfer.h"
|
#include "transfer.h"
|
||||||
|
|
||||||
#define TRANSFERBUFSIZE MEGABYTE(2)
|
|
||||||
#define POLLTIMEOUTS_BEFORE_DEVICECLEAR 6
|
|
||||||
|
|
||||||
// --- cTransfer -------------------------------------------------------------
|
// --- cTransfer -------------------------------------------------------------
|
||||||
|
|
||||||
cTransfer::cTransfer(tChannelID ChannelID, int VPid, const int *APids, const int *DPids, const int *SPids)
|
cTransfer::cTransfer(tChannelID ChannelID, int VPid, const int *APids, const int *DPids, const int *SPids)
|
||||||
:cReceiver(ChannelID, -1, VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids)
|
:cReceiver(ChannelID, -1, VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids)
|
||||||
,cThread("transfer")
|
|
||||||
{
|
{
|
||||||
ringBuffer = new cRingBufferLinear(TRANSFERBUFSIZE, TS_SIZE * 2, true, "Transfer");
|
patPmtGenerator.GeneratePmt(ChannelID);
|
||||||
remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cTransfer::~cTransfer()
|
cTransfer::~cTransfer()
|
||||||
{
|
{
|
||||||
cReceiver::Detach();
|
cReceiver::Detach();
|
||||||
cPlayer::Detach();
|
cPlayer::Detach();
|
||||||
delete remux;
|
|
||||||
delete ringBuffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cTransfer::Activate(bool On)
|
void cTransfer::Activate(bool On)
|
||||||
{
|
{
|
||||||
if (On)
|
if (On) {
|
||||||
Start();
|
PlayTs(patPmtGenerator.GetPat(), TS_SIZE);
|
||||||
else {
|
int Index = 0;
|
||||||
Cancel(3);
|
while (uchar *pmt = patPmtGenerator.GetPmt(Index))
|
||||||
cPlayer::Detach();
|
PlayTs(pmt, TS_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cTransfer::Receive(uchar *Data, int Length)
|
void cTransfer::Receive(uchar *Data, int Length)
|
||||||
{
|
{
|
||||||
if (cPlayer::IsAttached() && Running()) {
|
if (cPlayer::IsAttached()) {
|
||||||
int p = ringBuffer->Put(Data, Length);
|
// Transfer Mode means "live tv", so there's no point in doing any additional
|
||||||
if (p != Length && Running())
|
// buffering here. The TS packets *must* get through here! However, every
|
||||||
ringBuffer->ReportOverflow(Length - p);
|
// now and then there may be conditions where the packet just can't be
|
||||||
|
// handled when offered the first time, so that's why we try several times:
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
if (PlayTs(Data, Length) > 0)
|
||||||
|
return;
|
||||||
|
fprintf(stderr, "-");//XXX just for testing - remove when stable
|
||||||
|
cCondWait::SleepMs(10);
|
||||||
|
}
|
||||||
|
esyslog("ERROR: TS packet not accepted in Transfer Mode");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cTransfer::Action(void)
|
|
||||||
{
|
|
||||||
int PollTimeouts = 0;
|
|
||||||
uchar *p = NULL;
|
|
||||||
int Result = 0;
|
|
||||||
while (Running()) {
|
|
||||||
int Count;
|
|
||||||
uchar *b = ringBuffer->Get(Count);
|
|
||||||
if (b) {
|
|
||||||
if (ringBuffer->Available() > TRANSFERBUFSIZE * 9 / 10) {
|
|
||||||
// If the buffer runs full, we have no chance of ever catching up
|
|
||||||
// since the data comes in at the same rate as it goes out (it's "live").
|
|
||||||
// So let's clear the buffer instead of suffering from permanent
|
|
||||||
// overflows.
|
|
||||||
dsyslog("clearing transfer buffer to avoid overflows");
|
|
||||||
DeviceClear();
|
|
||||||
ringBuffer->Clear();
|
|
||||||
remux->Clear();
|
|
||||||
PlayPes(NULL, 0);
|
|
||||||
p = NULL;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Count = remux->Put(b, Count);
|
|
||||||
if (Count)
|
|
||||||
ringBuffer->Del(Count);
|
|
||||||
}
|
|
||||||
if (!p)
|
|
||||||
p = remux->Get(Result);
|
|
||||||
if (p) {
|
|
||||||
cPoller Poller;
|
|
||||||
if (DevicePoll(Poller, 100)) {
|
|
||||||
PollTimeouts = 0;
|
|
||||||
int w = PlayPes(p, Result);
|
|
||||||
if (w > 0) {
|
|
||||||
p += w;
|
|
||||||
Result -= w;
|
|
||||||
remux->Del(w);
|
|
||||||
if (Result <= 0)
|
|
||||||
p = NULL;
|
|
||||||
}
|
|
||||||
else if (w < 0 && FATALERRNO)
|
|
||||||
LOG_ERROR;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
PollTimeouts++;
|
|
||||||
if (PollTimeouts == POLLTIMEOUTS_BEFORE_DEVICECLEAR) {
|
|
||||||
dsyslog("clearing device because of consecutive poll timeouts");
|
|
||||||
DeviceClear();
|
|
||||||
ringBuffer->Clear();
|
|
||||||
remux->Clear();
|
|
||||||
PlayPes(NULL, 0);
|
|
||||||
p = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- cTransferControl ------------------------------------------------------
|
// --- cTransferControl ------------------------------------------------------
|
||||||
|
|
||||||
cDevice *cTransferControl::receiverDevice = NULL;
|
cDevice *cTransferControl::receiverDevice = NULL;
|
||||||
|
10
transfer.h
10
transfer.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: transfer.h 2.0 2007/01/05 10:45:45 kls Exp $
|
* $Id: transfer.h 2.1 2008/05/25 12:44:49 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __TRANSFER_H
|
#ifndef __TRANSFER_H
|
||||||
@ -13,17 +13,13 @@
|
|||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "receiver.h"
|
#include "receiver.h"
|
||||||
#include "remux.h"
|
#include "remux.h"
|
||||||
#include "ringbuffer.h"
|
|
||||||
#include "thread.h"
|
|
||||||
|
|
||||||
class cTransfer : public cReceiver, public cPlayer, public cThread {
|
class cTransfer : public cReceiver, public cPlayer {
|
||||||
private:
|
private:
|
||||||
cRingBufferLinear *ringBuffer;
|
cPatPmtGenerator patPmtGenerator;
|
||||||
cRemux *remux;
|
|
||||||
protected:
|
protected:
|
||||||
virtual void Activate(bool On);
|
virtual void Activate(bool On);
|
||||||
virtual void Receive(uchar *Data, int Length);
|
virtual void Receive(uchar *Data, int Length);
|
||||||
virtual void Action(void);
|
|
||||||
public:
|
public:
|
||||||
cTransfer(tChannelID ChannelID, int VPid, const int *APids, const int *DPids, const int *SPids);
|
cTransfer(tChannelID ChannelID, int VPid, const int *APids, const int *DPids, const int *SPids);
|
||||||
virtual ~cTransfer();
|
virtual ~cTransfer();
|
||||||
|
11
vdr.5
11
vdr.5
@ -8,7 +8,7 @@
|
|||||||
.\" License as specified in the file COPYING that comes with the
|
.\" License as specified in the file COPYING that comes with the
|
||||||
.\" vdr distribution.
|
.\" vdr distribution.
|
||||||
.\"
|
.\"
|
||||||
.\" $Id: vdr.5 2.1 2008/04/12 10:46:32 kls Exp $
|
.\" $Id: vdr.5 2.4 2008/07/06 13:00:19 kls Exp $
|
||||||
.\"
|
.\"
|
||||||
.TH vdr 5 "10 Feb 2008" "1.6" "Video Disk Recorder Files"
|
.TH vdr 5 "10 Feb 2008" "1.6" "Video Disk Recorder Files"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
@ -95,6 +95,7 @@ l l.
|
|||||||
\fBO\fR@rollOff (0, 20, 25, 35)
|
\fBO\fR@rollOff (0, 20, 25, 35)
|
||||||
\fBP\fR@Priority (0, 1)
|
\fBP\fR@Priority (0, 1)
|
||||||
\fBR\fR@Right circular polarization
|
\fBR\fR@Right circular polarization
|
||||||
|
\fBS\fR@delivery System (0, 1)
|
||||||
\fBT\fR@Transmission mode (2, 4, 8)
|
\fBT\fR@Transmission mode (2, 4, 8)
|
||||||
\fBV\fR@Vertical polarization
|
\fBV\fR@Vertical polarization
|
||||||
\fBY\fR@hierarchY (0, 1)
|
\fBY\fR@hierarchY (0, 1)
|
||||||
@ -125,7 +126,13 @@ The symbol rate of this channel (DVB-S and DVB-C only).
|
|||||||
The video PID (set to '0' for radio channels).
|
The video PID (set to '0' for radio channels).
|
||||||
If this channel uses a separate PCR PID, it follows the VPID, separated by a
|
If this channel uses a separate PCR PID, it follows the VPID, separated by a
|
||||||
plus sign, as in
|
plus sign, as in
|
||||||
|
|
||||||
.B ...:164+17:...
|
.B ...:164+17:...
|
||||||
|
|
||||||
|
If this channel has a video mode other than 0, the mode
|
||||||
|
follows the pids, separated by an '=' sign, as in
|
||||||
|
|
||||||
|
.B ...:164+17=27:...
|
||||||
.TP
|
.TP
|
||||||
.B APID
|
.B APID
|
||||||
The audio PID (either one number, or several, separated by commas).
|
The audio PID (either one number, or several, separated by commas).
|
||||||
@ -652,7 +659,7 @@ l l.
|
|||||||
<title> @is the title of the event
|
<title> @is the title of the event
|
||||||
<short text> @is the short text of the event (typically the name of the episode etc.)
|
<short text> @is the short text of the event (typically the name of the episode etc.)
|
||||||
<description> @is the description of the event (any '|' characters will be interpreted as newlines)
|
<description> @is the description of the event (any '|' characters will be interpreted as newlines)
|
||||||
<stream> @is the stream content (1 = video, 2 = audio, 3 = subtitles)
|
<stream> @is the stream content (1 = video, 2 = audio, 3 = subtitles, 4 = AC3)
|
||||||
<type> @is the stream type according to ETSI EN 300 468
|
<type> @is the stream type according to ETSI EN 300 468
|
||||||
<language> @is the three letter language code (optionally two codes, separated by '+')
|
<language> @is the three letter language code (optionally two codes, separated by '+')
|
||||||
<descr> @is the description of this stream component
|
<descr> @is the description of this stream component
|
||||||
|
30
vdr.c
30
vdr.c
@ -22,7 +22,7 @@
|
|||||||
*
|
*
|
||||||
* The project's page is at http://www.cadsoft.de/vdr
|
* The project's page is at http://www.cadsoft.de/vdr
|
||||||
*
|
*
|
||||||
* $Id: vdr.c 2.0 2008/03/14 13:22:39 kls Exp $
|
* $Id: vdr.c 2.3 2008/09/06 14:08:44 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
@ -141,7 +141,6 @@ static bool SetKeepCaps(bool On)
|
|||||||
|
|
||||||
static void SignalHandler(int signum)
|
static void SignalHandler(int signum)
|
||||||
{
|
{
|
||||||
isyslog("caught signal %d", signum);
|
|
||||||
switch (signum) {
|
switch (signum) {
|
||||||
case SIGPIPE:
|
case SIGPIPE:
|
||||||
break;
|
break;
|
||||||
@ -210,9 +209,6 @@ int main(int argc, char *argv[])
|
|||||||
#elif defined(REMOTE_RCU)
|
#elif defined(REMOTE_RCU)
|
||||||
RcuDevice = RCU_DEVICE;
|
RcuDevice = RCU_DEVICE;
|
||||||
#endif
|
#endif
|
||||||
#if defined(VFAT)
|
|
||||||
VfatFileSystem = true;
|
|
||||||
#endif
|
|
||||||
#if defined(VDR_USER)
|
#if defined(VDR_USER)
|
||||||
VdrUser = VDR_USER;
|
VdrUser = VDR_USER;
|
||||||
#endif
|
#endif
|
||||||
@ -563,17 +559,15 @@ int main(int argc, char *argv[])
|
|||||||
cThemes::SetThemesDirectory(AddDirectory(ConfigDirectory, "themes"));
|
cThemes::SetThemesDirectory(AddDirectory(ConfigDirectory, "themes"));
|
||||||
|
|
||||||
Setup.Load(AddDirectory(ConfigDirectory, "setup.conf"));
|
Setup.Load(AddDirectory(ConfigDirectory, "setup.conf"));
|
||||||
if (!(Sources.Load(AddDirectory(ConfigDirectory, "sources.conf"), true, true) &&
|
Sources.Load(AddDirectory(ConfigDirectory, "sources.conf"), true, true);
|
||||||
Diseqcs.Load(AddDirectory(ConfigDirectory, "diseqc.conf"), true, Setup.DiSEqC) &&
|
Diseqcs.Load(AddDirectory(ConfigDirectory, "diseqc.conf"), true, Setup.DiSEqC);
|
||||||
Channels.Load(AddDirectory(ConfigDirectory, "channels.conf"), false, true) &&
|
Channels.Load(AddDirectory(ConfigDirectory, "channels.conf"), false, true);
|
||||||
Timers.Load(AddDirectory(ConfigDirectory, "timers.conf")) &&
|
Timers.Load(AddDirectory(ConfigDirectory, "timers.conf"));
|
||||||
Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"), true) &&
|
Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"), true);
|
||||||
RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf"), true) &&
|
RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf"), true);
|
||||||
SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true) &&
|
SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true);
|
||||||
Keys.Load(AddDirectory(ConfigDirectory, "remote.conf")) &&
|
Keys.Load(AddDirectory(ConfigDirectory, "remote.conf"));
|
||||||
KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true)
|
KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true);
|
||||||
))
|
|
||||||
EXIT(2);
|
|
||||||
|
|
||||||
if (!*cFont::GetFontFileName(Setup.FontOsd)) {
|
if (!*cFont::GetFontFileName(Setup.FontOsd)) {
|
||||||
const char *msg = "no fonts available - OSD will not show any text!";
|
const char *msg = "no fonts available - OSD will not show any text!";
|
||||||
@ -1288,9 +1282,11 @@ Exit:
|
|||||||
ReportEpgBugFixStats();
|
ReportEpgBugFixStats();
|
||||||
if (WatchdogTimeout > 0)
|
if (WatchdogTimeout > 0)
|
||||||
dsyslog("max. latency time %d seconds", MaxLatencyTime);
|
dsyslog("max. latency time %d seconds", MaxLatencyTime);
|
||||||
isyslog("exiting, exit code %d", ShutdownHandler.GetExitCode());
|
if (LastSignal)
|
||||||
|
isyslog("caught signal %d", LastSignal);
|
||||||
if (ShutdownHandler.EmergencyExitRequested())
|
if (ShutdownHandler.EmergencyExitRequested())
|
||||||
esyslog("emergency exit!");
|
esyslog("emergency exit!");
|
||||||
|
isyslog("exiting, exit code %d", ShutdownHandler.GetExitCode());
|
||||||
if (SysLogLevel > 0)
|
if (SysLogLevel > 0)
|
||||||
closelog();
|
closelog();
|
||||||
if (HasStdin)
|
if (HasStdin)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user