mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	Added support for AC3 replay over the DVB device
This commit is contained in:
		@@ -263,6 +263,8 @@ Werner Fink <werner@suse.de>
 | 
			
		||||
 for suggesting to add more checks and polling when getting frontend events
 | 
			
		||||
 for setting the VPID before the APID in live mode to avoid unnecessary
 | 
			
		||||
 overhead in the firmware
 | 
			
		||||
 for a patch that was used as a base for implementing a modified PES packet
 | 
			
		||||
 handling in order to play AC3 audio over full featured DVB cards
 | 
			
		||||
 | 
			
		||||
Rolf Hakenes <hakenes@hippomi.de>
 | 
			
		||||
 for providing 'libdtv' and adapting the EIT mechanisms to it
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								HISTORY
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								HISTORY
									
									
									
									
									
								
							@@ -3160,7 +3160,7 @@ Video Disk Recorder Revision History
 | 
			
		||||
  right day of week for timers in the future.
 | 
			
		||||
- Some improvements to cPoller (thanks to Marco Schl<68><6C>ler).
 | 
			
		||||
 | 
			
		||||
2004-11-27: Version 1.3.18
 | 
			
		||||
2004-12-17: Version 1.3.18
 | 
			
		||||
 | 
			
		||||
- Removed an unused variable from cTimer::GetWDayFromMDay() (thanks to Wayne Keer
 | 
			
		||||
  for reporting this one).
 | 
			
		||||
@@ -3171,3 +3171,25 @@ Video Disk Recorder Revision History
 | 
			
		||||
  picture mode (thanks to Reinhard Nissl for reporting this one).
 | 
			
		||||
- Fixed a possible race condition in generating the DVB device names (thanks to
 | 
			
		||||
  Rainer Zocholl for reporting this one).
 | 
			
		||||
- Changed the way PES packets are played to allow replay of AC3 sound over the
 | 
			
		||||
  full featured DVB cards (partially based on a patch from Werner Fink).
 | 
			
		||||
  + The new function cDevice::PlayPes() is now called with the complete PES data
 | 
			
		||||
    stream and calls PlayVideo() and PlayAudio() as necessary.
 | 
			
		||||
  + cDevice::PlayVideo() is now only called with actual video PES packets.
 | 
			
		||||
  + cDevice::PlayAudio() is now called with the actual audio PES packets, which
 | 
			
		||||
    can be either "normal" audio or AC3 data. You need at least firmware version
 | 
			
		||||
    0x261d to replay AC3 sound over a full featured DVB card. This function now
 | 
			
		||||
    has an 'int' return value.
 | 
			
		||||
  + PlayAudio() of derived cDevice classes shall no longer call the base class
 | 
			
		||||
    function. It shall just play the given data as audio.
 | 
			
		||||
  + cPlayer::PlayVideo() and cPlayer::PlayAudio() are now obsolete and have been
 | 
			
		||||
    replaced with cPlayer::PlayPes().
 | 
			
		||||
  + All StripAudioPackets() functions are now obsolete. The functionality has been
 | 
			
		||||
    moved into cDevice::PlayPes(), where only the video and audio packets that are
 | 
			
		||||
    actually required will be processed.
 | 
			
		||||
  + All audio track handling is now done by cDevice; cTransfer and cDvbPlayer no
 | 
			
		||||
    longer care about audio tracks. cPlayer, however, still has the virtual hooks
 | 
			
		||||
    for audio track handling in order to allow plugins to implement players that
 | 
			
		||||
    have their own idea about this.
 | 
			
		||||
  + cChannel::[AD]pid[12]() have been replaced with cChannel::[AD]pid(int i) to
 | 
			
		||||
    allow access to all available PIDs.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										62
									
								
								PLUGINS.html
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								PLUGINS.html
									
									
									
									
									
								
							@@ -14,18 +14,18 @@ Copyright © 2004 Klaus Schmidinger<br>
 | 
			
		||||
<a href="http://www.cadsoft.de/vdr">www.cadsoft.de/vdr</a>
 | 
			
		||||
</center>
 | 
			
		||||
<p>
 | 
			
		||||
<!--X1.2.6--><table width=100%><tr><td bgcolor=#0000AA> </td><td width=100%>
 | 
			
		||||
Important modifications introduced in version 1.2.6 are marked like this.
 | 
			
		||||
<!--X1.2.6--></td></tr></table>
 | 
			
		||||
<!--X1.3.0--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%>
 | 
			
		||||
<!--X1.3.0--><table width=100%><tr><td bgcolor=#0000AA> </td><td width=100%>
 | 
			
		||||
Important modifications introduced in version 1.3.0 are marked like this.
 | 
			
		||||
<!--X1.3.0--></td></tr></table>
 | 
			
		||||
<!--X1.3.7--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%>
 | 
			
		||||
<!--X1.3.7--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%>
 | 
			
		||||
Important modifications introduced in version 1.3.7 are marked like this.
 | 
			
		||||
<!--X1.3.7--></td></tr></table>
 | 
			
		||||
<!--X1.3.8--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%>
 | 
			
		||||
<!--X1.3.8--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%>
 | 
			
		||||
Important modifications introduced in version 1.3.8 are marked like this.
 | 
			
		||||
<!--X1.3.8--></td></tr></table>
 | 
			
		||||
<!--X1.3.18--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%>
 | 
			
		||||
Important modifications introduced in version 1.3.18 are marked like this.
 | 
			
		||||
<!--X1.3.18--></td></tr></table>
 | 
			
		||||
<p>
 | 
			
		||||
VDR provides an easy to use plugin interface that allows additional functionality
 | 
			
		||||
to be added to the program by implementing a dynamically loadable library file.
 | 
			
		||||
@@ -73,11 +73,11 @@ structures and allows it to hook itself into specific areas to perform special a
 | 
			
		||||
<li><a href="#Status monitor">Status monitor</a>
 | 
			
		||||
<li><a href="#Players">Players</a>
 | 
			
		||||
<li><a href="#Receivers">Receivers</a>
 | 
			
		||||
<!--X1.3.0--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%>
 | 
			
		||||
<!--X1.3.0--><table width=100%><tr><td bgcolor=#0000AA> </td><td width=100%>
 | 
			
		||||
<li><a href="#Filters">Filters</a>
 | 
			
		||||
<!--X1.3.0--></td></tr></table>
 | 
			
		||||
<li><a href="#The On Screen Display">The On Screen Display</a>
 | 
			
		||||
<!--X1.3.7--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%>
 | 
			
		||||
<!--X1.3.7--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%>
 | 
			
		||||
<li><a href="#Skins">Skins</a>
 | 
			
		||||
<li><a href="#Themes">Themes</a>
 | 
			
		||||
<!--X1.3.7--></td></tr></table>
 | 
			
		||||
@@ -1023,17 +1023,21 @@ public:
 | 
			
		||||
Take a look at the files <tt>player.h</tt> and <tt>dvbplayer.c</tt> to see how VDR implements
 | 
			
		||||
its own player for the VDR recordings.
 | 
			
		||||
<p>
 | 
			
		||||
To play the video data, the player needs to call its member function
 | 
			
		||||
<!--X1.3.18--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%>
 | 
			
		||||
To play the actual data, the player needs to call its member function
 | 
			
		||||
 | 
			
		||||
<p><table><tr><td bgcolor=#F0F0F0><pre>
 | 
			
		||||
int PlayVideo(const uchar *Data, int Length);
 | 
			
		||||
int PlayPes(const uchar *Data, int Length, bool VideoOnly);
 | 
			
		||||
</pre></td></tr></table><p>
 | 
			
		||||
 | 
			
		||||
where <tt>Data</tt> points to a block of <tt>Length</tt> bytes of a PES data
 | 
			
		||||
stream. There are no prerequisites regarding the length or alignment of an
 | 
			
		||||
stream containing any combination of video, audio or dolby tracks. Which audio
 | 
			
		||||
or dolby track will actually be played is controlled by the device the player
 | 
			
		||||
is attached to. There are no prerequisites regarding the length or alignment of an
 | 
			
		||||
individual block of data. The sum of all blocks must simply result in the
 | 
			
		||||
desired video data stream, and it must be delivered fast enough so that the
 | 
			
		||||
desired data stream, and it must be delivered fast enough so that the
 | 
			
		||||
DVB device doesn't run out of data.
 | 
			
		||||
<!--X1.3.18--></td></tr></table>
 | 
			
		||||
To avoid busy loops the player should call its member function
 | 
			
		||||
 | 
			
		||||
<p><table><tr><td bgcolor=#F0F0F0><pre>
 | 
			
		||||
@@ -1042,24 +1046,26 @@ bool DevicePoll(cPoller &Poller, int TimeoutMs = 0);
 | 
			
		||||
 | 
			
		||||
to determine whether the device is ready for further data.
 | 
			
		||||
<p>
 | 
			
		||||
If the player can provide more than a single audio track, it can implement the
 | 
			
		||||
following functions to make them available:
 | 
			
		||||
<!--X1.3.18--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%>
 | 
			
		||||
By default all audio track handling is done by the device a player is
 | 
			
		||||
attached to.
 | 
			
		||||
If the player can provide more than a single audio track, and has special
 | 
			
		||||
requirements in order to set a given track, it can implement the
 | 
			
		||||
following function to allow the device to set a specific track:
 | 
			
		||||
 | 
			
		||||
<p><table><tr><td bgcolor=#F0F0F0><pre>
 | 
			
		||||
virtual int NumAudioTracks(void) const;
 | 
			
		||||
virtual const char **GetAudioTracks(int *CurrentTrack = NULL);
 | 
			
		||||
virtual void SetAudioTrack(int Index);
 | 
			
		||||
virtual void SetAudioTrack(eTrackType Type, const tTrackId *TrackId)
 | 
			
		||||
</pre></td></tr></table><p>
 | 
			
		||||
 | 
			
		||||
<p>
 | 
			
		||||
If there is an additional audio track that has to be replayed with external hardware,
 | 
			
		||||
the player shall call its member function
 | 
			
		||||
A player that has special requirements about audio tracks should announce its
 | 
			
		||||
available audio tracks by calling
 | 
			
		||||
 | 
			
		||||
<p><table><tr><td bgcolor=#F0F0F0><pre>
 | 
			
		||||
void PlayAudio(const uchar *Data, int Length);
 | 
			
		||||
bool DeviceSetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language = NULL, uint32_t Flags = 0)
 | 
			
		||||
</pre></td></tr></table><p>
 | 
			
		||||
 | 
			
		||||
where <tt>Data</tt> points to a complete audio PES packet of <tt>Length</tt> bytes.
 | 
			
		||||
See <tt>device.h</tt> for details about the parameters for track handling.
 | 
			
		||||
<!--X1.3.18--></td></tr></table>
 | 
			
		||||
<p>
 | 
			
		||||
The second part needed here is a control object that receives user input from the main
 | 
			
		||||
program loop and reacts on this by telling the player what to do:
 | 
			
		||||
@@ -1217,7 +1223,7 @@ Mode</i>).
 | 
			
		||||
If the <tt>cReceiver</tt> isn't needed any more, it may simply be <i>deleted</i>
 | 
			
		||||
and will automatically detach itself from the <tt>cDevice</tt>.
 | 
			
		||||
 | 
			
		||||
<!--X1.3.0--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%>
 | 
			
		||||
<!--X1.3.0--><table width=100%><tr><td bgcolor=#0000AA> </td><td width=100%>
 | 
			
		||||
<a name="Filters"><hr><h2>Filters</h2>
 | 
			
		||||
 | 
			
		||||
<center><i><b>A Fistful of Datas</b></i></center><p>
 | 
			
		||||
@@ -1263,7 +1269,7 @@ and will automatically detach itself from the <tt>cDevice</tt>.
 | 
			
		||||
See VDR/eit.c or VDR/pat.c to learn how to process filter data.
 | 
			
		||||
<!--X1.3.0--></td></tr></table>
 | 
			
		||||
 | 
			
		||||
<!--X1.3.7--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%>
 | 
			
		||||
<!--X1.3.7--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%>
 | 
			
		||||
<a name="The On Screen Display"><hr><h2>The On Screen Display</h2>
 | 
			
		||||
 | 
			
		||||
<center><i><b>Window to the world</b></i></center><p>
 | 
			
		||||
@@ -1375,7 +1381,7 @@ new cMySkin;
 | 
			
		||||
in the <a href="#Getting started"><tt>Start()</tt></a> function of your plugin.
 | 
			
		||||
Do not delete this object, it will be automatically deleted when the program ends.
 | 
			
		||||
<p>
 | 
			
		||||
<!--X1.3.8--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%>
 | 
			
		||||
<!--X1.3.8--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%>
 | 
			
		||||
In order to be able to easily identify plugins that implement a skin it is recommended
 | 
			
		||||
that the name of such a plugin should be
 | 
			
		||||
 | 
			
		||||
@@ -1527,9 +1533,7 @@ The functions to implement replaying capabilites are
 | 
			
		||||
virtual bool HasDecoder(void) const;
 | 
			
		||||
virtual bool CanReplay(void) const;
 | 
			
		||||
virtual bool SetPlayMode(ePlayMode PlayMode);
 | 
			
		||||
<!--X1.2.6--><table width=100%><tr><td bgcolor=#0000AA> </td><td width=100%>
 | 
			
		||||
virtual int64_t GetSTC(void);
 | 
			
		||||
<!--X1.2.6--></td></tr></table>
 | 
			
		||||
virtual void TrickSpeed(int Speed);
 | 
			
		||||
virtual void Clear(void);
 | 
			
		||||
virtual void Play(void);
 | 
			
		||||
@@ -1549,7 +1553,7 @@ virtual void SetVideoFormat(bool VideoFormat16_9);
 | 
			
		||||
virtual void SetVolumeDevice(int Volume);
 | 
			
		||||
</pre></td></tr></table><p>
 | 
			
		||||
 | 
			
		||||
<!--X1.3.0--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%>
 | 
			
		||||
<!--X1.3.0--><table width=100%><tr><td bgcolor=#0000AA> </td><td width=100%>
 | 
			
		||||
<p>
 | 
			
		||||
<b>Section Filtering</b>
 | 
			
		||||
<p>
 | 
			
		||||
@@ -1579,7 +1583,7 @@ handle section data.
 | 
			
		||||
<p>
 | 
			
		||||
<b>On Screen Display</b>
 | 
			
		||||
<p>
 | 
			
		||||
<!--X1.3.7--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%>
 | 
			
		||||
<!--X1.3.7--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%>
 | 
			
		||||
If your device provides On Screen Display (OSD) capabilities (which every device
 | 
			
		||||
that is supposed to be used as a primary device should do), it shall implement
 | 
			
		||||
an "OSD provider" class, derived from <tt>cOsdProvider</tt>, which, when its <tt>CreateOsd()</tt>
 | 
			
		||||
 
 | 
			
		||||
@@ -28,3 +28,7 @@ VDR Plugin 'sky' Revision History
 | 
			
		||||
2004-10-16: Version 0.3.1
 | 
			
		||||
 | 
			
		||||
- Improved buffer handling.
 | 
			
		||||
 | 
			
		||||
2004-12-12: Version 0.3.2
 | 
			
		||||
 | 
			
		||||
- Changed Apid access in cChannel.
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 * See the README file for copyright information and how to reach the author.
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: sky.c 1.7 2004/10/16 09:10:06 kls Exp $
 | 
			
		||||
 * $Id: sky.c 1.8 2004/12/12 14:27:33 kls Exp $
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
@@ -14,7 +14,7 @@
 | 
			
		||||
#include <vdr/plugin.h>
 | 
			
		||||
#include <vdr/sources.h>
 | 
			
		||||
 | 
			
		||||
static const char *VERSION        = "0.3.1";
 | 
			
		||||
static const char *VERSION        = "0.3.2";
 | 
			
		||||
static const char *DESCRIPTION    = "Sky Digibox interface";
 | 
			
		||||
 | 
			
		||||
// --- cDigiboxDevice --------------------------------------------------------
 | 
			
		||||
@@ -213,7 +213,7 @@ bool cDigiboxDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
 | 
			
		||||
     cSkyChannel *SkyChannel = SkyChannels.GetSkyChannel(Channel);
 | 
			
		||||
     if (SkyChannel) {
 | 
			
		||||
        digiboxChannelNumber = SkyChannel->digiboxChannelNumber;
 | 
			
		||||
        apid = Channel->Apid1();
 | 
			
		||||
        apid = Channel->Apid(0);
 | 
			
		||||
        vpid = Channel->Vpid();
 | 
			
		||||
        //XXX only when recording??? -> faster channel switching!
 | 
			
		||||
        LircSend("SKY"); // makes sure the Digibox is "on"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								channels.h
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								channels.h
									
									
									
									
									
								
							@@ -4,7 +4,7 @@
 | 
			
		||||
 * See the main source file 'vdr.c' for copyright information and
 | 
			
		||||
 * how to reach the author.
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: channels.h 1.22 2004/10/31 12:54:26 kls Exp $
 | 
			
		||||
 * $Id: channels.h 1.23 2004/12/05 13:49:04 kls Exp $
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __CHANNELS_H
 | 
			
		||||
@@ -145,10 +145,10 @@ public:
 | 
			
		||||
  int Srate(void) const { return srate; }
 | 
			
		||||
  int Vpid(void) const { return vpid; }
 | 
			
		||||
  int Ppid(void) const { return ppid; }
 | 
			
		||||
  int Apid1(void) const { return apids[0]; }
 | 
			
		||||
  int Apid2(void) const { return apids[1]; }
 | 
			
		||||
  int Dpid1(void) const { return dpids[0]; }
 | 
			
		||||
  int Dpid2(void) const { return dpids[1]; }
 | 
			
		||||
  int Apid(int i) const { return (0 <= i && i < MAXAPIDS) ? apids[i] : 0; }
 | 
			
		||||
  int Dpid(int i) const { return (0 <= i && i < MAXAPIDS) ? dpids[i] : 0; }
 | 
			
		||||
  const char *Alang(int i) const { return (0 <= i && i < MAXAPIDS) ? alangs[i] : ""; }
 | 
			
		||||
  const char *Dlang(int i) const { return (0 <= i && i < MAXAPIDS) ? dlangs[i] : ""; }
 | 
			
		||||
  int Tpid(void) const { return tpid; }
 | 
			
		||||
  int Ca(int Index = 0) const { return Index < MAXCAIDS ? caids[Index] : 0; }
 | 
			
		||||
  int Nid(void) const { return nid; }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										266
									
								
								device.c
									
									
									
									
									
								
							
							
						
						
									
										266
									
								
								device.c
									
									
									
									
									
								
							@@ -4,7 +4,7 @@
 | 
			
		||||
 * See the main source file 'vdr.c' for copyright information and
 | 
			
		||||
 * how to reach the author.
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: device.c 1.62 2004/10/30 14:53:38 kls Exp $
 | 
			
		||||
 * $Id: device.c 1.63 2004/12/17 13:51:44 kls Exp $
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "device.h"
 | 
			
		||||
@@ -19,6 +19,87 @@
 | 
			
		||||
#include "status.h"
 | 
			
		||||
#include "transfer.h"
 | 
			
		||||
 | 
			
		||||
// --- 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 data[4] * 256 + data[5] + 6; }
 | 
			
		||||
  int Length(void) { return length; }
 | 
			
		||||
  const uchar *Data(void) { return data; }
 | 
			
		||||
  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) {
 | 
			
		||||
     tag = (tag << 8) | c;
 | 
			
		||||
     if ((tag & 0xFFFFFF00) == 0x00000100) {
 | 
			
		||||
        if (Realloc(4)) {
 | 
			
		||||
           *(uint32_t *)data = htonl(tag);
 | 
			
		||||
           length = 4;
 | 
			
		||||
           }
 | 
			
		||||
        }
 | 
			
		||||
     }
 | 
			
		||||
  else if (Realloc(length + 1))
 | 
			
		||||
     data[length++] = c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cPesAssembler::Put(const uchar *Data, int Length)
 | 
			
		||||
{
 | 
			
		||||
  while (!length && Length > 0) {
 | 
			
		||||
        Put(*Data++);
 | 
			
		||||
        Length--;
 | 
			
		||||
        }
 | 
			
		||||
  if (Length && Realloc(length + Length)) {
 | 
			
		||||
     memcpy(data + length, Data, Length);
 | 
			
		||||
     length += Length;
 | 
			
		||||
     }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// --- cDevice ---------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
// The default priority for non-primary devices:
 | 
			
		||||
@@ -53,6 +134,9 @@ cDevice::cDevice(void)
 | 
			
		||||
 | 
			
		||||
  ciHandler = NULL;
 | 
			
		||||
  player = NULL;
 | 
			
		||||
  pesAssembler = new cPesAssembler;
 | 
			
		||||
  ClrAvailableTracks();
 | 
			
		||||
  currentAudioTrack = ttAudioFirst;
 | 
			
		||||
 | 
			
		||||
  for (int i = 0; i < MAXRECEIVERS; i++)
 | 
			
		||||
      receiver[i] = NULL;
 | 
			
		||||
@@ -74,6 +158,7 @@ cDevice::~cDevice()
 | 
			
		||||
  delete patFilter;
 | 
			
		||||
  delete eitFilter;
 | 
			
		||||
  delete sectionHandler;
 | 
			
		||||
  delete pesAssembler;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cDevice::SetUseDevice(int n)
 | 
			
		||||
@@ -427,7 +512,7 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
 | 
			
		||||
     if (CaDevice && CanReplay()) {
 | 
			
		||||
        cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel
 | 
			
		||||
        if (CaDevice->SetChannel(Channel, false) == scrOk) // calling SetChannel() directly, not SwitchChannel()!
 | 
			
		||||
           cControl::Launch(new cTransferControl(CaDevice, Channel->Vpid(), Channel->Apid1(), Channel->Apid2(), Channel->Dpid1(), Channel->Dpid2()));//XXX+
 | 
			
		||||
           cControl::Launch(new cTransferControl(CaDevice, Channel->Vpid(), Channel->Apid(0), Channel->Apid(1), Channel->Dpid(0), Channel->Dpid(1)));
 | 
			
		||||
        else
 | 
			
		||||
           Result = scrNoTransfer;
 | 
			
		||||
        }
 | 
			
		||||
@@ -482,17 +567,7 @@ void cDevice::SetVolumeDevice(int Volume)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int cDevice::NumAudioTracksDevice(void) const
 | 
			
		||||
{
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char **cDevice::GetAudioTracksDevice(int *CurrentTrack) const
 | 
			
		||||
{
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cDevice::SetAudioTrackDevice(int Index)
 | 
			
		||||
void cDevice::SetAudioTrackDevice(eTrackType Type)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -524,22 +599,72 @@ void cDevice::SetVolume(int Volume, bool Absolute)
 | 
			
		||||
     }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cDevice::ClrAvailableTracks(void)
 | 
			
		||||
{
 | 
			
		||||
  memset(availableTracks, 0, sizeof(availableTracks));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cDevice::SetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language, uint32_t Flags)
 | 
			
		||||
{
 | 
			
		||||
  eTrackType t = eTrackType(Type + Index);
 | 
			
		||||
  if ((Type == ttAudio && IS_AUDIO_TRACK(t)) ||
 | 
			
		||||
      (Type == ttDolby && IS_DOLBY_TRACK(t))) {
 | 
			
		||||
     if (Language)
 | 
			
		||||
        strn0cpy(availableTracks[t].language, Language, sizeof(availableTracks[t].language));
 | 
			
		||||
     availableTracks[t].flags = Flags;
 | 
			
		||||
     availableTracks[t].id = Id; // setting 'id' last to avoid the need for extensive locking
 | 
			
		||||
     return true;
 | 
			
		||||
     }
 | 
			
		||||
  else
 | 
			
		||||
     esyslog("ERROR: SetAvailableTrack called with invalid Type/Index (%d/%d)", Type, Index);
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const tTrackId *cDevice::GetTrack(eTrackType Type)
 | 
			
		||||
{
 | 
			
		||||
  return (ttNone < Type && Type < ttMaxTrackTypes) ? &availableTracks[Type] : NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int cDevice::NumAudioTracks(void) const
 | 
			
		||||
{
 | 
			
		||||
  return player ? player->NumAudioTracks() : NumAudioTracksDevice();
 | 
			
		||||
  int n = 0;
 | 
			
		||||
  for (int i = ttAudioFirst; i <= ttDolbyLast; i++) {
 | 
			
		||||
      if (availableTracks[i].id)
 | 
			
		||||
         n++;
 | 
			
		||||
      }
 | 
			
		||||
  return n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char **cDevice::GetAudioTracks(int *CurrentTrack) const
 | 
			
		||||
bool cDevice::SetCurrentAudioTrack(eTrackType Type)
 | 
			
		||||
{
 | 
			
		||||
  return player ? player->GetAudioTracks(CurrentTrack) : GetAudioTracksDevice(CurrentTrack);
 | 
			
		||||
  if (ttNone < Type && Type < ttDolbyLast) {
 | 
			
		||||
     if (IS_DOLBY_TRACK(Type))
 | 
			
		||||
        SetDigitalAudioDevice(true);
 | 
			
		||||
     currentAudioTrack = Type;
 | 
			
		||||
     if (player)
 | 
			
		||||
        player->SetAudioTrack(currentAudioTrack, GetTrack(currentAudioTrack));
 | 
			
		||||
     else
 | 
			
		||||
        SetAudioTrackDevice(currentAudioTrack);
 | 
			
		||||
     if (IS_AUDIO_TRACK(Type))
 | 
			
		||||
        SetDigitalAudioDevice(false);
 | 
			
		||||
     return true;
 | 
			
		||||
     }
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cDevice::SetAudioTrack(int Index)
 | 
			
		||||
bool cDevice::IncCurrentAudioTrack(void)
 | 
			
		||||
{
 | 
			
		||||
  if (player)
 | 
			
		||||
     player->SetAudioTrack(Index);
 | 
			
		||||
  else
 | 
			
		||||
     SetAudioTrackDevice(Index);
 | 
			
		||||
  int i = currentAudioTrack + 1;
 | 
			
		||||
  for (;;) {
 | 
			
		||||
      if (i > ttDolbyLast)
 | 
			
		||||
         i = ttAudioFirst;
 | 
			
		||||
      if (i == currentAudioTrack)
 | 
			
		||||
         break;
 | 
			
		||||
      if (availableTracks[i].id)
 | 
			
		||||
         return SetCurrentAudioTrack(eTrackType(i));
 | 
			
		||||
      i++;
 | 
			
		||||
      }
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cDevice::CanReplay(void) const
 | 
			
		||||
@@ -595,6 +720,7 @@ bool cDevice::AttachPlayer(cPlayer *Player)
 | 
			
		||||
  if (CanReplay()) {
 | 
			
		||||
     if (player)
 | 
			
		||||
        Detach(player);
 | 
			
		||||
     ClrAvailableTracks();
 | 
			
		||||
     player = Player;
 | 
			
		||||
     SetPlayMode(player->playMode);
 | 
			
		||||
     player->device = this;
 | 
			
		||||
@@ -639,11 +765,105 @@ int cDevice::PlayVideo(const uchar *Data, int Length)
 | 
			
		||||
  return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cDevice::PlayAudio(const uchar *Data, int Length)
 | 
			
		||||
int cDevice::PlayAudio(const uchar *Data, int Length)
 | 
			
		||||
{
 | 
			
		||||
  Audios.PlayAudio(Data, Length);
 | 
			
		||||
  return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly)
 | 
			
		||||
{
 | 
			
		||||
  bool FirstLoop = true;
 | 
			
		||||
  uchar c = Data[3];
 | 
			
		||||
  const uchar *Start = Data;
 | 
			
		||||
  const uchar *End = Start + Length;
 | 
			
		||||
  while (Start < End) {
 | 
			
		||||
        int d = End - Start;
 | 
			
		||||
        int w = d;
 | 
			
		||||
        switch (c) {
 | 
			
		||||
          case 0xE0 ... 0xEF: // video
 | 
			
		||||
               w = PlayVideo(Start, d);
 | 
			
		||||
               break;
 | 
			
		||||
          case 0xC0 ... 0xDF: // audio
 | 
			
		||||
               SetAvailableTrack(ttAudio, c - 0xC0, c);
 | 
			
		||||
               if (!VideoOnly && c == availableTracks[currentAudioTrack].id)
 | 
			
		||||
                  w = PlayAudio(Start, d);
 | 
			
		||||
               break;
 | 
			
		||||
          case 0xBD: // dolby
 | 
			
		||||
               SetAvailableTrack(ttDolby, 0, c);
 | 
			
		||||
               if (!VideoOnly && c == availableTracks[currentAudioTrack].id) {
 | 
			
		||||
                  w = PlayAudio(Start, d);
 | 
			
		||||
                  if (FirstLoop)
 | 
			
		||||
                     Audios.PlayAudio(Data, Length);
 | 
			
		||||
                  }
 | 
			
		||||
               break;
 | 
			
		||||
          default:
 | 
			
		||||
               ;//esyslog("ERROR: unexpected packet id %02X", c);
 | 
			
		||||
          }
 | 
			
		||||
        if (w > 0)
 | 
			
		||||
           Start += w;
 | 
			
		||||
        else if (w <= 0) {
 | 
			
		||||
           if (Start != Data)
 | 
			
		||||
              esyslog("ERROR: incomplete PES packet write!");
 | 
			
		||||
           return Start == Data ? w : Start - Data;
 | 
			
		||||
           }
 | 
			
		||||
        FirstLoop = false;
 | 
			
		||||
        }
 | 
			
		||||
  return Length;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int cDevice::PlayPes(const uchar *Data, int Length, bool VideoOnly)
 | 
			
		||||
{
 | 
			
		||||
  if (!Data) {
 | 
			
		||||
     pesAssembler->Reset();
 | 
			
		||||
     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;
 | 
			
		||||
  while (i <= Length - 6) {
 | 
			
		||||
        if (Data[i] == 0x00 && Data[i + 1] == 0x00 && Data[i + 2] == 0x01) {
 | 
			
		||||
           int l = Data[i + 4] * 256 + Data[i + 5] + 6;
 | 
			
		||||
           if (i + l > Length) {
 | 
			
		||||
              // Store incomplete PES packet for later completion:
 | 
			
		||||
              pesAssembler->Put(Data + i, Length - i);
 | 
			
		||||
              return Length;
 | 
			
		||||
              }
 | 
			
		||||
           int w = PlayPesPacket(Data + i, l, VideoOnly);
 | 
			
		||||
           if (w > 0)
 | 
			
		||||
              i += l;
 | 
			
		||||
           else if (w < 0)
 | 
			
		||||
              return i == 0 ? w : i;
 | 
			
		||||
           }
 | 
			
		||||
        else
 | 
			
		||||
           i++;
 | 
			
		||||
        }
 | 
			
		||||
  if (i < Length)
 | 
			
		||||
     pesAssembler->Put(Data + i, Length - i);
 | 
			
		||||
  return Length;
 | 
			
		||||
 }
 | 
			
		||||
 | 
			
		||||
int cDevice::Ca(void) const
 | 
			
		||||
{
 | 
			
		||||
  int ca = 0;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										136
									
								
								device.h
									
									
									
									
									
								
							
							
						
						
									
										136
									
								
								device.h
									
									
									
									
									
								
							@@ -4,7 +4,7 @@
 | 
			
		||||
 * See the main source file 'vdr.c' for copyright information and
 | 
			
		||||
 * how to reach the author.
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: device.h 1.46 2004/10/30 14:49:56 kls Exp $
 | 
			
		||||
 * $Id: device.h 1.47 2004/12/17 13:44:34 kls Exp $
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __DEVICE_H
 | 
			
		||||
@@ -56,10 +56,36 @@ enum eVideoSystem { vsPAL,
 | 
			
		||||
                    vsNTSC
 | 
			
		||||
                  };
 | 
			
		||||
 | 
			
		||||
enum eTrackType { ttNone,
 | 
			
		||||
                  ttAudio,
 | 
			
		||||
                  ttAudioFirst = ttAudio,
 | 
			
		||||
                  ttAudioLast  = ttAudioFirst + 31/*XXX MAXAPIDS - 1*/,
 | 
			
		||||
                  ttDolby,
 | 
			
		||||
                  ttDolbyFirst = ttDolby,
 | 
			
		||||
                  ttDolbyLast  = ttDolbyFirst + 31/*XXX MAXAPIDS - 1*/,
 | 
			
		||||
                  /* future...
 | 
			
		||||
                  ttSubtitle,
 | 
			
		||||
                  ttSubtitleFirst = ttSubtitle,
 | 
			
		||||
                  ttSubtitleLast  = ttSubtitleFirst + 31,
 | 
			
		||||
                  */
 | 
			
		||||
                  ttMaxTrackTypes
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
#define IS_AUDIO_TRACK(t) (ttAudioFirst <= (t) && (t) <= ttAudioLast)
 | 
			
		||||
#define IS_DOLBY_TRACK(t) (ttDolbyFirst <= (t) && (t) <= ttDolbyLast)
 | 
			
		||||
 | 
			
		||||
struct tTrackId {
 | 
			
		||||
  uint16_t id;      // The PES packet id or the PID.
 | 
			
		||||
  char language[8]; // something like either "eng" or "deu/eng"
 | 
			
		||||
  // for future use:
 | 
			
		||||
  uint32_t flags;   // Used to further identify the actual track.
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
class cChannel;
 | 
			
		||||
class cPlayer;
 | 
			
		||||
class cReceiver;
 | 
			
		||||
class cSpuDecoder;
 | 
			
		||||
class cPesAssembler;
 | 
			
		||||
 | 
			
		||||
/// The cDevice class is the base from which actual devices can be derived.
 | 
			
		||||
 | 
			
		||||
@@ -283,6 +309,37 @@ public:
 | 
			
		||||
         ///< Returns the video system of the currently displayed material
 | 
			
		||||
         ///< (default is PAL).
 | 
			
		||||
 | 
			
		||||
// Track facilities
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  tTrackId availableTracks[ttMaxTrackTypes];
 | 
			
		||||
  eTrackType currentAudioTrack;
 | 
			
		||||
protected:
 | 
			
		||||
  virtual void SetAudioTrackDevice(eTrackType Type);
 | 
			
		||||
       ///< Sets the current audio track to the given value.
 | 
			
		||||
public:
 | 
			
		||||
  void ClrAvailableTracks(void);
 | 
			
		||||
  bool SetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language = NULL, uint32_t Flags = 0);
 | 
			
		||||
       ///< Sets the track of the given Type and Index to the given values.
 | 
			
		||||
       ///< Type must be one of the basic eTrackType values, like ttAudio or ttDolby.
 | 
			
		||||
       ///< Index tells which track of the given basic type is meant.
 | 
			
		||||
       ///< \return Returns true if the track was set correctly, false otherwise.
 | 
			
		||||
  const tTrackId *GetTrack(eTrackType Type);
 | 
			
		||||
       ///< Returns a pointer to the given track id, or NULL if Type is not
 | 
			
		||||
       ///< less than ttMaxTrackTypes.
 | 
			
		||||
  int NumAudioTracks(void) const;
 | 
			
		||||
       ///< Returns the number of audio tracks that are currently available.
 | 
			
		||||
       ///< This is just for information, to quickly find out whether there
 | 
			
		||||
       ///< is more than one audio track.
 | 
			
		||||
  eTrackType GetCurrentAudioTrack(void) { return currentAudioTrack; }
 | 
			
		||||
  bool SetCurrentAudioTrack(eTrackType Type);
 | 
			
		||||
       ///< Sets the current audio track to the given Type.
 | 
			
		||||
       ///< \return Returns true if Type is a valid audio track, false otherwise.
 | 
			
		||||
  bool IncCurrentAudioTrack(void);
 | 
			
		||||
       ///< Sets the current audio track to the next available track (wraps to
 | 
			
		||||
       ///< to the first one if necessary).
 | 
			
		||||
       ///< \return Returns true if the audio track has been changed, false otherwise.
 | 
			
		||||
 | 
			
		||||
// Audio facilities
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
@@ -291,27 +348,9 @@ private:
 | 
			
		||||
protected:
 | 
			
		||||
  virtual void SetVolumeDevice(int Volume);
 | 
			
		||||
       ///< Sets the audio volume on this device (Volume = 0...255).
 | 
			
		||||
  virtual int NumAudioTracksDevice(void) const;
 | 
			
		||||
       ///< Returns the number of audio tracks that are currently available on this
 | 
			
		||||
       ///< device. The default return value is 0, meaning that this device
 | 
			
		||||
       ///< doesn't have multiple audio track capabilities. The return value may
 | 
			
		||||
       ///< change with every call and need not necessarily be the number of list
 | 
			
		||||
       ///< entries returned by GetAudioTracksDevice(). This function is mainly called to
 | 
			
		||||
       ///< decide whether there should be an "Audio" button in a menu.
 | 
			
		||||
  virtual const char **GetAudioTracksDevice(int *CurrentTrack = NULL) const;
 | 
			
		||||
       ///< Returns a list of currently available audio tracks. The last entry in the
 | 
			
		||||
       ///< list must be NULL. The number of entries does not necessarily have to be
 | 
			
		||||
       ///< the same as returned by a previous call to NumAudioTracksDevice().
 | 
			
		||||
       ///< If CurrentTrack is given, it will be set to the index of the current track
 | 
			
		||||
       ///< in the returned list. Note that the list must not be changed after it has
 | 
			
		||||
       ///< been returned by a call to GetAudioTracksDevice()! The only time the list may
 | 
			
		||||
       ///< change is *inside* the GetAudioTracksDevice() function.
 | 
			
		||||
       ///< By default the return value is NULL and CurrentTrack, if given, will not
 | 
			
		||||
       ///< have any meaning.
 | 
			
		||||
  virtual void SetAudioTrackDevice(int Index);
 | 
			
		||||
       ///< Sets the current audio track to the given value, which should be within the
 | 
			
		||||
       ///< range of the list returned by a previous call to GetAudioTracksDevice()
 | 
			
		||||
       ///< (otherwise nothing will happen).
 | 
			
		||||
  virtual void SetDigitalAudioDevice(bool On) {}
 | 
			
		||||
       ///< Tells the actual device that digital audio output shall be switched
 | 
			
		||||
       ///< on or off.
 | 
			
		||||
public:
 | 
			
		||||
  bool IsMute(void) const { return mute; }
 | 
			
		||||
  bool ToggleMute(void);
 | 
			
		||||
@@ -320,32 +359,37 @@ public:
 | 
			
		||||
       ///< Sets the volume to the given value, either absolutely or relative to
 | 
			
		||||
       ///< the current volume.
 | 
			
		||||
  static int CurrentVolume(void) { return primaryDevice ? primaryDevice->volume : 0; }//XXX???
 | 
			
		||||
  int NumAudioTracks(void) const;
 | 
			
		||||
       ///< Returns the number of audio tracks that are currently available on this
 | 
			
		||||
       ///< device or a player attached to it.
 | 
			
		||||
  const char **GetAudioTracks(int *CurrentTrack = NULL) const;
 | 
			
		||||
       ///< Returns a list of currently available audio tracks. The last entry in the
 | 
			
		||||
       ///< list is NULL. The number of entries does not necessarily have to be
 | 
			
		||||
       ///< the same as returned by a previous call to NumAudioTracks().
 | 
			
		||||
       ///< If CurrentTrack is given, it will be set to the index of the current track
 | 
			
		||||
       ///< in the returned list.
 | 
			
		||||
       ///< By default the return value is NULL and CurrentTrack, if given, will not
 | 
			
		||||
       ///< have any meaning.
 | 
			
		||||
  void SetAudioTrack(int Index);
 | 
			
		||||
       ///< Sets the current audio track to the given value, which should be within the
 | 
			
		||||
       ///< range of the list returned by a previous call to GetAudioTracks() (otherwise
 | 
			
		||||
       ///< nothing will happen).
 | 
			
		||||
 | 
			
		||||
// Player facilities
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  cPlayer *player;
 | 
			
		||||
  cPesAssembler *pesAssembler;
 | 
			
		||||
protected:
 | 
			
		||||
  virtual bool CanReplay(void) const;
 | 
			
		||||
       ///< Returns true if this device can currently start a replay session.
 | 
			
		||||
  virtual bool SetPlayMode(ePlayMode PlayMode);
 | 
			
		||||
       ///< Sets the device into the given play mode.
 | 
			
		||||
       ///< \return true if the operation was successful.
 | 
			
		||||
  virtual int PlayVideo(const uchar *Data, int Length);
 | 
			
		||||
       ///< Plays the given data block as video.
 | 
			
		||||
       ///< Data points to exactly one complete PES packet of the given Length.
 | 
			
		||||
       ///< PlayVideo() shall process the packet either as a whole (returning
 | 
			
		||||
       ///< Length) or not at all (returning 0 or -1 and setting 'errno' to EAGAIN).
 | 
			
		||||
       ///< \return Returns the number of bytes actually taken from Data, or -1
 | 
			
		||||
       ///< in case of an error.
 | 
			
		||||
  virtual int PlayAudio(const uchar *Data, int Length);
 | 
			
		||||
       ///< Plays the given data block as audio.
 | 
			
		||||
       ///< Data points to exactly one complete PES packet of the given Length.
 | 
			
		||||
       ///< PlayAudio() shall process the packet either as a whole (returning
 | 
			
		||||
       ///< Length) or not at all (returning 0 or -1 and setting 'errno' to EAGAIN).
 | 
			
		||||
       ///< \return Returns the number of bytes actually taken from Data, or -1
 | 
			
		||||
       ///< in case of an error.
 | 
			
		||||
  virtual int PlayPesPacket(const uchar *Data, int Length, bool VideoOnly = false);
 | 
			
		||||
       ///< Plays the single PES packet in Data with the given Length.
 | 
			
		||||
       ///< If VideoOnly is true, only the video will be displayed,
 | 
			
		||||
       ///< which is necessary for trick modes like 'fast forward'.
 | 
			
		||||
       ///< Data must point to one single, complete PES packet.
 | 
			
		||||
public:
 | 
			
		||||
  virtual int64_t GetSTC(void);
 | 
			
		||||
       ///< Gets the current System Time Counter, which can be used to
 | 
			
		||||
@@ -382,14 +426,16 @@ public:
 | 
			
		||||
       ///< If TimeoutMs is not zero, the device will wait up to the given
 | 
			
		||||
       ///< number of milliseconds before returning in case there is still
 | 
			
		||||
       ///< data in the buffers..
 | 
			
		||||
  virtual int PlayVideo(const uchar *Data, int Length);
 | 
			
		||||
       ///< Actually plays the given data block as video. The data must be
 | 
			
		||||
       ///< part of a PES (Packetized Elementary Stream) which can contain
 | 
			
		||||
       ///< one video and one audio stream.
 | 
			
		||||
  virtual void PlayAudio(const uchar *Data, int Length);
 | 
			
		||||
       ///< Plays additional audio streams, like Dolby Digital.
 | 
			
		||||
       ///< A derived class must call the base class function to make sure data
 | 
			
		||||
       ///< is distributed to all registered cAudio objects.
 | 
			
		||||
  virtual int PlayPes(const uchar *Data, int Length, bool VideoOnly = false);
 | 
			
		||||
       ///< Plays all valid PES packets in Data with the given Length.
 | 
			
		||||
       ///< If Data is NULL any leftover data from a previous call will be
 | 
			
		||||
       ///< discarded. If VideoOnly is true, only the video will be displayed,
 | 
			
		||||
       ///< which is necessary for trick modes like 'fast forward'.
 | 
			
		||||
       ///< Data should point to a sequence of complete PES packets. If the
 | 
			
		||||
       ///< last packet in Data is not complete, it will be copied and combined
 | 
			
		||||
       ///< to a complete packet with data from the next call to PlayPes().
 | 
			
		||||
       ///< That way any functions called from within PlayPes() will be
 | 
			
		||||
       ///< guaranteed to always receive complete PES packets.
 | 
			
		||||
  bool Replaying(void) const;
 | 
			
		||||
       ///< Returns true if we are currently replaying.
 | 
			
		||||
  void StopReplay(void);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										78
									
								
								dvbdevice.c
									
									
									
									
									
								
							
							
						
						
									
										78
									
								
								dvbdevice.c
									
									
									
									
									
								
							@@ -4,7 +4,7 @@
 | 
			
		||||
 * See the main source file 'vdr.c' for copyright information and
 | 
			
		||||
 * how to reach the author.
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: dvbdevice.c 1.106 2004/11/27 10:24:47 kls Exp $
 | 
			
		||||
 * $Id: dvbdevice.c 1.107 2004/12/17 14:19:48 kls Exp $
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "dvbdevice.h"
 | 
			
		||||
@@ -322,9 +322,9 @@ void cDvbTuner::Action(void)
 | 
			
		||||
                     cCiCaPmt CaPmt(channel.Source(), channel.Transponder(), channel.Sid(), ciHandler->GetCaSystemIds(Slot));
 | 
			
		||||
                     if (CaPmt.Valid()) {
 | 
			
		||||
                        CaPmt.AddPid(channel.Vpid(), 2);
 | 
			
		||||
                        CaPmt.AddPid(channel.Apid1(), 4);
 | 
			
		||||
                        CaPmt.AddPid(channel.Apid2(), 4);
 | 
			
		||||
                        CaPmt.AddPid(channel.Dpid1(), 0);
 | 
			
		||||
                        CaPmt.AddPid(channel.Apid(0), 4);
 | 
			
		||||
                        CaPmt.AddPid(channel.Apid(1), 4);
 | 
			
		||||
                        CaPmt.AddPid(channel.Dpid(0), 0);
 | 
			
		||||
                        if (ciHandler->SetCaPmt(CaPmt, Slot)) {
 | 
			
		||||
                           tunerStatus = tsCam;
 | 
			
		||||
                           startTime = 0;
 | 
			
		||||
@@ -352,8 +352,8 @@ cDvbDevice::cDvbDevice(int n)
 | 
			
		||||
  dvbTuner = NULL;
 | 
			
		||||
  frontendType = fe_type_t(-1); // don't know how else to initialize this - there is no FE_UNKNOWN
 | 
			
		||||
  spuDecoder = NULL;
 | 
			
		||||
  digitalAudio = false;
 | 
			
		||||
  playMode = pmNone;
 | 
			
		||||
  aPid1 = aPid2 = 0;
 | 
			
		||||
 | 
			
		||||
  // Devices that are present on all card types:
 | 
			
		||||
 | 
			
		||||
@@ -728,7 +728,7 @@ bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Ne
 | 
			
		||||
     result = hasPriority;
 | 
			
		||||
     if (Priority >= 0 && Receiving(true)) {
 | 
			
		||||
        if (dvbTuner->IsTunedTo(Channel)) {
 | 
			
		||||
           if (Channel->Vpid() && !HasPid(Channel->Vpid()) || Channel->Apid1() && !HasPid(Channel->Apid1())) {
 | 
			
		||||
           if (Channel->Vpid() && !HasPid(Channel->Vpid()) || Channel->Apid(0) && !HasPid(Channel->Apid(0))) {
 | 
			
		||||
#ifdef DO_MULTIPLE_RECORDINGS
 | 
			
		||||
              if (Ca() > CACONFBASE || Channel->Ca() > CACONFBASE)
 | 
			
		||||
                 needsDetachReceivers = !ciHandler // only LL-firmware can do non-live CA channels
 | 
			
		||||
@@ -801,9 +801,13 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
 | 
			
		||||
  // PID settings:
 | 
			
		||||
 | 
			
		||||
  if (TurnOnLivePIDs) {
 | 
			
		||||
     aPid1 = Channel->Apid1();
 | 
			
		||||
     aPid2 = Channel->Apid2();
 | 
			
		||||
     if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(Channel->Vpid(), ptVideo) && AddPid(Channel->Apid1(), ptAudio))) {//XXX+ dolby dpid1!!! (if audio plugins are attached)
 | 
			
		||||
     ClrAvailableTracks();
 | 
			
		||||
     for (int i = 0; i < MAXAPIDS; i++) {
 | 
			
		||||
         //XXX do this in cDevice???
 | 
			
		||||
         SetAvailableTrack(ttAudio, i, Channel->Apid(i), Channel->Alang(i));
 | 
			
		||||
         SetAvailableTrack(ttDolby, i, Channel->Dpid(i), Channel->Dlang(i));
 | 
			
		||||
         }
 | 
			
		||||
     if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(Channel->Vpid(), ptVideo) && AddPid(Channel->Apid(0), ptAudio))) {//XXX+ dolby dpid1!!! (if audio plugins are attached)
 | 
			
		||||
        esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1);
 | 
			
		||||
        return false;
 | 
			
		||||
        }
 | 
			
		||||
@@ -815,7 +819,7 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
 | 
			
		||||
     CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
 | 
			
		||||
     }
 | 
			
		||||
  else if (StartTransferMode)
 | 
			
		||||
     cControl::Launch(new cTransferControl(this, Channel->Vpid(), Channel->Apid1(), Channel->Apid2(), Channel->Dpid1(), Channel->Dpid2()));
 | 
			
		||||
     cControl::Launch(new cTransferControl(this, Channel->Vpid(), Channel->Apid(0), Channel->Apid(1), Channel->Dpid(0), Channel->Dpid(1)));
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
@@ -835,34 +839,32 @@ void cDvbDevice::SetVolumeDevice(int Volume)
 | 
			
		||||
     }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int cDvbDevice::NumAudioTracksDevice(void) const
 | 
			
		||||
void cDvbDevice::SetDigitalAudioDevice(bool On)
 | 
			
		||||
{
 | 
			
		||||
  int n = 0;
 | 
			
		||||
  if (aPid1)
 | 
			
		||||
     n++;
 | 
			
		||||
  if (Ca() <= MAXDEVICES && aPid2 && aPid1 != aPid2) // a CA recording session blocks switching live audio tracks
 | 
			
		||||
     n++;
 | 
			
		||||
  return n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char **cDvbDevice::GetAudioTracksDevice(int *CurrentTrack) const
 | 
			
		||||
{
 | 
			
		||||
  if (NumAudioTracksDevice()) {
 | 
			
		||||
     if (CurrentTrack)
 | 
			
		||||
        *CurrentTrack = (pidHandles[ptAudio].pid == aPid1) ? 0 : 1;
 | 
			
		||||
     static const char *audioTracks1[] = { "Audio 1", NULL };
 | 
			
		||||
     static const char *audioTracks2[] = { "Audio 1", "Audio 2", NULL };
 | 
			
		||||
     return NumAudioTracksDevice() > 1 ? audioTracks2 : audioTracks1;
 | 
			
		||||
  if (digitalAudio != On) {
 | 
			
		||||
     if (digitalAudio)
 | 
			
		||||
        cCondWait::SleepMs(1000); // Wait until any leftover digital data has been flushed
 | 
			
		||||
     SetVolumeDevice(On || IsMute() ? 0 : CurrentVolume());
 | 
			
		||||
     digitalAudio = On;
 | 
			
		||||
     }
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cDvbDevice::SetAudioTrackDevice(int Index)
 | 
			
		||||
void cDvbDevice::SetAudioTrackDevice(eTrackType Type)
 | 
			
		||||
{
 | 
			
		||||
  if (0 <= Index && Index < NumAudioTracksDevice()) {
 | 
			
		||||
     int Pid = Index ? aPid2 : aPid1;
 | 
			
		||||
     pidHandles[ptAudio].pid = Pid;
 | 
			
		||||
     SetPid(&pidHandles[ptAudio], ptAudio, true);
 | 
			
		||||
  const tTrackId *TrackId = GetTrack(Type);
 | 
			
		||||
  if (TrackId && TrackId->id) {
 | 
			
		||||
     if (IS_AUDIO_TRACK(Type)) {
 | 
			
		||||
        pidHandles[ptAudio].pid = TrackId->id;
 | 
			
		||||
        SetPid(&pidHandles[ptAudio], ptAudio, true);
 | 
			
		||||
        }
 | 
			
		||||
     else if (IS_DOLBY_TRACK(Type)) {
 | 
			
		||||
        // Currently this works only in Transfer Mode
 | 
			
		||||
        cChannel *Channel = Channels.GetByNumber(CurrentChannel());
 | 
			
		||||
        if (Channel) {
 | 
			
		||||
           SetChannelDevice(Channel, false);
 | 
			
		||||
           cControl::Launch(new cTransferControl(this, Channel->Vpid(), Channel->Apid(0), Channel->Apid(1), Channel->Dpid(0), Channel->Dpid(1)));
 | 
			
		||||
           }
 | 
			
		||||
        }
 | 
			
		||||
     }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1120,16 +1122,12 @@ bool cDvbDevice::Flush(int TimeoutMs)
 | 
			
		||||
 | 
			
		||||
int cDvbDevice::PlayVideo(const uchar *Data, int Length)
 | 
			
		||||
{
 | 
			
		||||
  int fd = (playMode == pmAudioOnly || playMode == pmAudioOnlyBlack) ? fd_audio : fd_video;
 | 
			
		||||
  if (fd >= 0)
 | 
			
		||||
     return write(fd, Data, Length);
 | 
			
		||||
  return -1;
 | 
			
		||||
  return write(fd_video, Data, Length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cDvbDevice::PlayAudio(const uchar *Data, int Length)
 | 
			
		||||
int cDvbDevice::PlayAudio(const uchar *Data, int Length)
 | 
			
		||||
{
 | 
			
		||||
  //XXX actually this function will only be needed to implement replaying AC3 over the DVB card's S/PDIF
 | 
			
		||||
  cDevice::PlayAudio(Data, Length);
 | 
			
		||||
  return write(fd_audio, Data, Length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cDvbDevice::OpenDvr(void)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								dvbdevice.h
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								dvbdevice.h
									
									
									
									
									
								
							@@ -4,7 +4,7 @@
 | 
			
		||||
 * See the main source file 'vdr.c' for copyright information and
 | 
			
		||||
 * how to reach the author.
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: dvbdevice.h 1.30 2004/11/07 10:25:16 kls Exp $
 | 
			
		||||
 * $Id: dvbdevice.h 1.31 2004/12/17 14:01:31 kls Exp $
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __DVBDEVICE_H
 | 
			
		||||
@@ -90,15 +90,18 @@ public:
 | 
			
		||||
  virtual void SetVideoFormat(bool VideoFormat16_9);
 | 
			
		||||
  virtual eVideoSystem GetVideoSystem(void);
 | 
			
		||||
 | 
			
		||||
// Track facilities
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
  virtual void SetAudioTrackDevice(eTrackType Type);
 | 
			
		||||
 | 
			
		||||
// Audio facilities
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  int aPid1, aPid2;
 | 
			
		||||
  bool digitalAudio;
 | 
			
		||||
protected:
 | 
			
		||||
  virtual void SetVolumeDevice(int Volume);
 | 
			
		||||
  virtual int NumAudioTracksDevice(void) const;
 | 
			
		||||
  virtual const char **GetAudioTracksDevice(int *CurrentTrack = NULL) const;
 | 
			
		||||
  virtual void SetAudioTrackDevice(int Index);
 | 
			
		||||
  virtual void SetDigitalAudioDevice(bool On);
 | 
			
		||||
 | 
			
		||||
// Player facilities
 | 
			
		||||
 | 
			
		||||
@@ -106,6 +109,8 @@ protected:
 | 
			
		||||
  ePlayMode playMode;
 | 
			
		||||
  virtual bool CanReplay(void) const;
 | 
			
		||||
  virtual bool SetPlayMode(ePlayMode PlayMode);
 | 
			
		||||
  virtual int PlayVideo(const uchar *Data, int Length);
 | 
			
		||||
  virtual int PlayAudio(const uchar *Data, int Length);
 | 
			
		||||
public:
 | 
			
		||||
  virtual int64_t GetSTC(void);
 | 
			
		||||
  virtual void TrickSpeed(int Speed);
 | 
			
		||||
@@ -116,8 +121,6 @@ public:
 | 
			
		||||
  virtual void StillPicture(const uchar *Data, int Length);
 | 
			
		||||
  virtual bool Poll(cPoller &Poller, int TimeoutMs = 0);
 | 
			
		||||
  virtual bool Flush(int TimeoutMs = 0);
 | 
			
		||||
  virtual int PlayVideo(const uchar *Data, int Length);
 | 
			
		||||
  virtual void PlayAudio(const uchar *Data, int Length);
 | 
			
		||||
 | 
			
		||||
// Receiver facilities
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										87
									
								
								dvbplayer.c
									
									
									
									
									
								
							
							
						
						
									
										87
									
								
								dvbplayer.c
									
									
									
									
									
								
							@@ -4,7 +4,7 @@
 | 
			
		||||
 * See the main source file 'vdr.c' for copyright information and
 | 
			
		||||
 * how to reach the author.
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: dvbplayer.c 1.27 2004/11/27 10:07:05 kls Exp $
 | 
			
		||||
 * $Id: dvbplayer.c 1.28 2004/12/11 17:02:40 kls Exp $
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "dvbplayer.h"
 | 
			
		||||
@@ -194,13 +194,10 @@ private:
 | 
			
		||||
  ePlayDirs playDir;
 | 
			
		||||
  int trickSpeed;
 | 
			
		||||
  int readIndex, writeIndex;
 | 
			
		||||
  bool canToggleAudioTrack;
 | 
			
		||||
  uchar audioTrack;
 | 
			
		||||
  cFrame *readFrame;
 | 
			
		||||
  cFrame *playFrame;
 | 
			
		||||
  void TrickSpeed(int Increment);
 | 
			
		||||
  void Empty(void);
 | 
			
		||||
  void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00);
 | 
			
		||||
  bool NextFile(uchar FileNumber = 0, int FileOffset = -1);
 | 
			
		||||
  int Resume(void);
 | 
			
		||||
  bool Save(void);
 | 
			
		||||
@@ -220,9 +217,6 @@ public:
 | 
			
		||||
  void Goto(int Position, bool Still = false);
 | 
			
		||||
  virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
 | 
			
		||||
  virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed);
 | 
			
		||||
  virtual int NumAudioTracks(void) const;
 | 
			
		||||
  virtual const char **GetAudioTracks(int *CurrentTrack = NULL) const;
 | 
			
		||||
  virtual void SetAudioTrack(int Index);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
#define MAX_VIDEO_SLOWMOTION 63 // max. arg to pass to VIDEO_SLOWMOTION // TODO is this value correct?
 | 
			
		||||
@@ -245,8 +239,6 @@ cDvbPlayer::cDvbPlayer(const char *FileName)
 | 
			
		||||
  playMode = pmPlay;
 | 
			
		||||
  playDir = pdForward;
 | 
			
		||||
  trickSpeed = NORMAL_SPEED;
 | 
			
		||||
  canToggleAudioTrack = false;
 | 
			
		||||
  audioTrack = 0xC0;
 | 
			
		||||
  readIndex = writeIndex = -1;
 | 
			
		||||
  readFrame = NULL;
 | 
			
		||||
  playFrame = NULL;
 | 
			
		||||
@@ -312,41 +304,6 @@ void cDvbPlayer::Empty(void)
 | 
			
		||||
  firstPacket = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cDvbPlayer::StripAudioPackets(uchar *b, int Length, uchar Except)
 | 
			
		||||
{
 | 
			
		||||
  if (index) {
 | 
			
		||||
     for (int i = 0; i < Length - 6; i++) {
 | 
			
		||||
         if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) {
 | 
			
		||||
            uchar c = b[i + 3];
 | 
			
		||||
            int l = b[i + 4] * 256 + b[i + 5] + 6;
 | 
			
		||||
            switch (c) {
 | 
			
		||||
              case 0xBD: // dolby
 | 
			
		||||
                   if (Except)
 | 
			
		||||
                      PlayAudio(&b[i], l);
 | 
			
		||||
                   // continue with deleting the data - otherwise it disturbs DVB replay
 | 
			
		||||
              case 0xC0 ... 0xC1: // audio
 | 
			
		||||
                   if (c == 0xC1)
 | 
			
		||||
                      canToggleAudioTrack = true;
 | 
			
		||||
                   if (!Except || c != Except)
 | 
			
		||||
                      memset(&b[i], 0x00, min(l, Length-i));
 | 
			
		||||
                   break;
 | 
			
		||||
              case 0xE0 ... 0xEF: // video
 | 
			
		||||
                   break;
 | 
			
		||||
              default:
 | 
			
		||||
                   //esyslog("ERROR: unexpected packet id %02X", c);
 | 
			
		||||
                   l = 0;
 | 
			
		||||
              }
 | 
			
		||||
            if (l)
 | 
			
		||||
               i += l - 1; // the loop increments, too!
 | 
			
		||||
            }
 | 
			
		||||
         /*XXX
 | 
			
		||||
         else
 | 
			
		||||
            esyslog("ERROR: broken packet header");
 | 
			
		||||
            XXX*/
 | 
			
		||||
         }
 | 
			
		||||
     }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cDvbPlayer::NextFile(uchar FileNumber, int FileOffset)
 | 
			
		||||
{
 | 
			
		||||
  if (FileNumber > 0)
 | 
			
		||||
@@ -413,7 +370,6 @@ void cDvbPlayer::Action(void)
 | 
			
		||||
 | 
			
		||||
  nonBlockingFileReader = new cNonBlockingFileReader;
 | 
			
		||||
  int Length = 0;
 | 
			
		||||
  int AudioTrack = 0; // -1 = any, 0 = none, >0 = audioTrack
 | 
			
		||||
 | 
			
		||||
  running = true;
 | 
			
		||||
  while (running && (NextFile() || readIndex >= 0 || ringBuffer->Available() || !DeviceFlush(100))) {
 | 
			
		||||
@@ -449,9 +405,6 @@ void cDvbPlayer::Action(void)
 | 
			
		||||
                          continue;
 | 
			
		||||
                          }
 | 
			
		||||
                       readIndex = Index;
 | 
			
		||||
                       AudioTrack = 0;
 | 
			
		||||
                       // must clear all audio packets because the buffer is not emptied
 | 
			
		||||
                       // when falling back from "fast forward" to "play" (see above)
 | 
			
		||||
                       }
 | 
			
		||||
                    else if (index) {
 | 
			
		||||
                       uchar FileNumber;
 | 
			
		||||
@@ -462,12 +415,9 @@ void cDvbPlayer::Action(void)
 | 
			
		||||
                          eof = true;
 | 
			
		||||
                          continue;
 | 
			
		||||
                          }
 | 
			
		||||
                       AudioTrack = audioTrack;
 | 
			
		||||
                       }
 | 
			
		||||
                    else { // allows replay even if the index file is missing
 | 
			
		||||
                    else // allows replay even if the index file is missing
 | 
			
		||||
                       Length = MAXFRAMESIZE;
 | 
			
		||||
                       AudioTrack = -1;
 | 
			
		||||
                       }
 | 
			
		||||
                    if (Length == -1)
 | 
			
		||||
                       Length = MAXFRAMESIZE; // this means we read up to EOF (see cIndex)
 | 
			
		||||
                    else if (Length > MAXFRAMESIZE) {
 | 
			
		||||
@@ -478,8 +428,6 @@ void cDvbPlayer::Action(void)
 | 
			
		||||
                    }
 | 
			
		||||
                 int r = nonBlockingFileReader->Read(replayFile, b, Length);
 | 
			
		||||
                 if (r > 0) {
 | 
			
		||||
                    if (AudioTrack == 0)
 | 
			
		||||
                       StripAudioPackets(b, r);
 | 
			
		||||
                    readFrame = new cFrame(b, -r, ftUnknown, readIndex); // hands over b to the ringBuffer
 | 
			
		||||
                    b = NULL;
 | 
			
		||||
                    }
 | 
			
		||||
@@ -517,15 +465,14 @@ void cDvbPlayer::Action(void)
 | 
			
		||||
                 pc = playFrame->Count();
 | 
			
		||||
                 if (p) {
 | 
			
		||||
                    if (firstPacket) {
 | 
			
		||||
                       PlayPes(NULL, 0);
 | 
			
		||||
                       cRemux::SetBrokenLink(p, pc);
 | 
			
		||||
                       firstPacket = false;
 | 
			
		||||
                       }
 | 
			
		||||
                    if (AudioTrack > 0)
 | 
			
		||||
                       StripAudioPackets(p, pc, AudioTrack);
 | 
			
		||||
                    }
 | 
			
		||||
                 }
 | 
			
		||||
              if (p) {
 | 
			
		||||
                 int w = PlayVideo(p, pc);
 | 
			
		||||
                 int w = PlayPes(p, pc, playMode != pmPlay);
 | 
			
		||||
                 if (w > 0) {
 | 
			
		||||
                    p += w;
 | 
			
		||||
                    pc -= w;
 | 
			
		||||
@@ -717,7 +664,6 @@ void cDvbPlayer::Goto(int Index, bool Still)
 | 
			
		||||
        if (r > 0) {
 | 
			
		||||
           if (playMode == pmPause)
 | 
			
		||||
              DevicePlay();
 | 
			
		||||
           StripAudioPackets(b, r);
 | 
			
		||||
           DeviceStillPicture(b, r);
 | 
			
		||||
           }
 | 
			
		||||
        playMode = pmStill;
 | 
			
		||||
@@ -757,31 +703,6 @@ bool cDvbPlayer::GetReplayMode(bool &Play, bool &Forward, int &Speed)
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int cDvbPlayer::NumAudioTracks(void) const
 | 
			
		||||
{
 | 
			
		||||
  return canToggleAudioTrack ? 2 : 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char **cDvbPlayer::GetAudioTracks(int *CurrentTrack) const
 | 
			
		||||
{
 | 
			
		||||
  if (NumAudioTracks()) {
 | 
			
		||||
     if (CurrentTrack)
 | 
			
		||||
        *CurrentTrack = (audioTrack == 0xC0) ? 0 : 1;
 | 
			
		||||
     static const char *audioTracks1[] = { "Audio 1", NULL };
 | 
			
		||||
     static const char *audioTracks2[] = { "Audio 1", "Audio 2", NULL };
 | 
			
		||||
     return NumAudioTracks() > 1 ? audioTracks2 : audioTracks1;
 | 
			
		||||
     }
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cDvbPlayer::SetAudioTrack(int Index)
 | 
			
		||||
{
 | 
			
		||||
  if ((audioTrack == 0xC0) != (Index == 0)) {
 | 
			
		||||
     audioTrack = (Index == 1) ? 0xC1 : 0xC0;
 | 
			
		||||
     Empty();
 | 
			
		||||
     }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// --- cDvbPlayerControl -----------------------------------------------------
 | 
			
		||||
 | 
			
		||||
cDvbPlayerControl::cDvbPlayerControl(const char *FileName)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								menu.c
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								menu.c
									
									
									
									
									
								
							@@ -4,7 +4,7 @@
 | 
			
		||||
 * See the main source file 'vdr.c' for copyright information and
 | 
			
		||||
 * how to reach the author.
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: menu.c 1.320 2004/11/20 10:49:17 kls Exp $
 | 
			
		||||
 * $Id: menu.c 1.321 2004/12/12 16:07:05 kls Exp $
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "menu.h"
 | 
			
		||||
@@ -2471,15 +2471,8 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
 | 
			
		||||
                                state = replaying ? osContinue : osRecord;
 | 
			
		||||
                             break;
 | 
			
		||||
               case kGreen:  if (!HadSubMenu) {
 | 
			
		||||
                                int CurrentAudioTrack = -1;
 | 
			
		||||
                                const char **AudioTracks = cDevice::PrimaryDevice()->GetAudioTracks(&CurrentAudioTrack);
 | 
			
		||||
                                if (AudioTracks) {
 | 
			
		||||
                                   const char **at = &AudioTracks[CurrentAudioTrack];
 | 
			
		||||
                                   if (!*++at)
 | 
			
		||||
                                      at = AudioTracks;
 | 
			
		||||
                                   cDevice::PrimaryDevice()->SetAudioTrack(at - AudioTracks);
 | 
			
		||||
                                   state = osEnd;
 | 
			
		||||
                                   }
 | 
			
		||||
                                cDevice::PrimaryDevice()->IncCurrentAudioTrack();
 | 
			
		||||
                                state = osEnd;
 | 
			
		||||
                                }
 | 
			
		||||
                             break;
 | 
			
		||||
               case kYellow: if (!HadSubMenu)
 | 
			
		||||
@@ -2826,7 +2819,7 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)
 | 
			
		||||
  isyslog("record %s", fileName);
 | 
			
		||||
  if (MakeDirs(fileName, true)) {
 | 
			
		||||
     const cChannel *ch = timer->Channel();
 | 
			
		||||
     recorder = new cRecorder(fileName, ch->Ca(), timer->Priority(), ch->Vpid(), ch->Apid1(), ch->Apid2(), ch->Dpid1(), ch->Dpid2());
 | 
			
		||||
     recorder = new cRecorder(fileName, ch->Ca(), timer->Priority(), ch->Vpid(), ch->Apid(0), ch->Apid(1), ch->Dpid(0), ch->Dpid(1));
 | 
			
		||||
     if (device->AttachReceiver(recorder)) {
 | 
			
		||||
        Recording.WriteSummary();
 | 
			
		||||
        cStatus::MsgRecording(device, Recording.Name());
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								player.c
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								player.c
									
									
									
									
									
								
							@@ -4,7 +4,7 @@
 | 
			
		||||
 * See the main source file 'vdr.c' for copyright information and
 | 
			
		||||
 * how to reach the author.
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: player.c 1.8 2004/11/20 11:33:08 kls Exp $
 | 
			
		||||
 * $Id: player.c 1.9 2004/12/12 11:21:07 kls Exp $
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "player.h"
 | 
			
		||||
@@ -23,23 +23,14 @@ cPlayer::~cPlayer()
 | 
			
		||||
  Detach();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int cPlayer::PlayVideo(const uchar *Data, int Length)
 | 
			
		||||
int cPlayer::PlayPes(const uchar *Data, int Length, bool VideoOnly)
 | 
			
		||||
{
 | 
			
		||||
  if (device)
 | 
			
		||||
     return device->PlayVideo(Data, Length);
 | 
			
		||||
  esyslog("ERROR: attempt to use cPlayer::PlayVideo() without attaching to a cDevice!");
 | 
			
		||||
     return device->PlayPes(Data, Length, VideoOnly);
 | 
			
		||||
  esyslog("ERROR: attempt to use cPlayer::PlayPes() without attaching to a cDevice!");
 | 
			
		||||
  return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cPlayer::PlayAudio(const uchar *Data, int Length)
 | 
			
		||||
{
 | 
			
		||||
  if (device) {
 | 
			
		||||
     device->PlayAudio(Data, Length);
 | 
			
		||||
     return;
 | 
			
		||||
     }
 | 
			
		||||
  esyslog("ERROR: attempt to use cPlayer::PlayAudio() without attaching to a cDevice!");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cPlayer::Detach(void)
 | 
			
		||||
{
 | 
			
		||||
  if (device)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										36
									
								
								player.h
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								player.h
									
									
									
									
									
								
							@@ -4,7 +4,7 @@
 | 
			
		||||
 * See the main source file 'vdr.c' for copyright information and
 | 
			
		||||
 * how to reach the author.
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: player.h 1.12 2004/06/19 08:53:07 kls Exp $
 | 
			
		||||
 * $Id: player.h 1.13 2004/12/12 11:20:19 kls Exp $
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PLAYER_H
 | 
			
		||||
@@ -19,6 +19,7 @@ private:
 | 
			
		||||
  cDevice *device;
 | 
			
		||||
  ePlayMode playMode;
 | 
			
		||||
protected:
 | 
			
		||||
  bool DeviceSetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language = NULL, uint32_t Flags = 0) { return device ? device->SetAvailableTrack(Type, Index, Id, Language, Flags) : false; }
 | 
			
		||||
  bool DevicePoll(cPoller &Poller, int TimeoutMs = 0) { return device ? device->Poll(Poller, TimeoutMs) : false; }
 | 
			
		||||
  bool DeviceFlush(int TimeoutMs = 0) { return device ? device->Flush(TimeoutMs) : true; }
 | 
			
		||||
  void DeviceTrickSpeed(int Speed) { if (device) device->TrickSpeed(Speed); }
 | 
			
		||||
@@ -32,12 +33,10 @@ protected:
 | 
			
		||||
       // This function is called right after the cPlayer has been attached to
 | 
			
		||||
       // (On == true) or before it gets detached from (On == false) a cDevice.
 | 
			
		||||
       // It can be used to do things like starting/stopping a thread.
 | 
			
		||||
  int PlayVideo(const uchar *Data, int Length);
 | 
			
		||||
       // Sends the given Data to the video device and returns the number of
 | 
			
		||||
       // bytes that have actually been accepted by the video device (or a
 | 
			
		||||
  int PlayPes(const uchar *Data, int Length, bool VideoOnly = false);
 | 
			
		||||
       // Sends the given PES Data to the device and returns the number of
 | 
			
		||||
       // bytes that have actually been accepted by the device (or a
 | 
			
		||||
       // negative value in case of an error).
 | 
			
		||||
  void PlayAudio(const uchar *Data, int Length);
 | 
			
		||||
       // Plays additional audio streams, like Dolby Digital.
 | 
			
		||||
public:
 | 
			
		||||
  cPlayer(ePlayMode PlayMode = pmAudioVideo);
 | 
			
		||||
  virtual ~cPlayer();
 | 
			
		||||
@@ -51,27 +50,10 @@ public:
 | 
			
		||||
       // we are going forward or backward and 'Speed' is -1 if this is normal
 | 
			
		||||
       // play/pause mode, 0 if it is single speed fast/slow forward/back mode
 | 
			
		||||
       // and >0 if this is multi speed mode.
 | 
			
		||||
  virtual int NumAudioTracks(void) const { return 0; }
 | 
			
		||||
       // Returns the number of audio tracks that are currently available on this
 | 
			
		||||
       // player. The default return value is 0, meaning that this player
 | 
			
		||||
       // doesn't have multiple audio track capabilities. The return value may
 | 
			
		||||
       // change with every call and need not necessarily be the number of list
 | 
			
		||||
       // entries returned by GetAudioTracks(). This function is mainly called to
 | 
			
		||||
       // decide whether there should be an "Audio" button in a menu.
 | 
			
		||||
  virtual const char **GetAudioTracks(int *CurrentTrack = NULL) const { return NULL; }
 | 
			
		||||
       // Returns a list of currently available audio tracks. The last entry in the
 | 
			
		||||
       // list must be NULL. The number of entries does not necessarily have to be
 | 
			
		||||
       // the same as returned by a previous call to NumAudioTracks().
 | 
			
		||||
       // If CurrentTrack is given, it will be set to the index of the current track
 | 
			
		||||
       // in the returned list. Note that the list must not be changed after it has
 | 
			
		||||
       // been returned by a call to GetAudioTracks()! The only time the list may
 | 
			
		||||
       // change is *inside* the GetAudioTracks() function.
 | 
			
		||||
       // By default the return value is NULL and CurrentTrack, if given, will not
 | 
			
		||||
       // have any meaning.
 | 
			
		||||
  virtual void SetAudioTrack(int Index) {}
 | 
			
		||||
       // Sets the current audio track to the given value, which should be within the
 | 
			
		||||
       // range of the list returned by a previous call to GetAudioTracks()
 | 
			
		||||
       // (otherwise nothing will happen).
 | 
			
		||||
  virtual void SetAudioTrack(eTrackType Type, const tTrackId *TrackId) {}
 | 
			
		||||
       // Sets the current audio track to the given value.
 | 
			
		||||
       // This is just a virtual hook for players that need to do special things
 | 
			
		||||
       // in order to switch audio tracks.
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
class cControl : public cOsdObject {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
 * See the main source file 'vdr.c' for copyright information and
 | 
			
		||||
 * how to reach the author.
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: skinsttng.c 1.6 2004/07/18 11:32:42 kls Exp $
 | 
			
		||||
 * $Id: skinsttng.c 1.7 2004/12/05 13:19:59 kls Exp $
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
// Star Trek: The Next Generation<6F> is a registered trademark of Paramount Pictures
 | 
			
		||||
@@ -233,14 +233,14 @@ void cSkinSTTNGDisplayChannel::SetChannel(const cChannel *Channel, int Number)
 | 
			
		||||
     x -= bmEncrypted.Width() + d;
 | 
			
		||||
     osd->DrawBitmap(x, y0 + (y1 - y0 - bmEncrypted.Height()) / 2, bmEncrypted, Theme.Color(Channel->Ca() ? clrChannelSymbolOn : clrChannelSymbolOff), frameColor);
 | 
			
		||||
     x -= bmDolbyDigital.Width() + d;
 | 
			
		||||
     osd->DrawBitmap(x, y0 + (y1 - y0 - bmDolbyDigital.Height()) / 2, bmDolbyDigital, Theme.Color(Channel->Dpid1() ? clrChannelSymbolOn : clrChannelSymbolOff), frameColor);
 | 
			
		||||
     osd->DrawBitmap(x, y0 + (y1 - y0 - bmDolbyDigital.Height()) / 2, bmDolbyDigital, Theme.Color(Channel->Dpid(0) ? clrChannelSymbolOn : clrChannelSymbolOff), frameColor);
 | 
			
		||||
     x -= bmAudio.Width() + d;
 | 
			
		||||
     osd->DrawBitmap(x, y0 + (y1 - y0 - bmAudio.Height()) / 2, bmAudio, Theme.Color(Channel->Apid2() ? clrChannelSymbolOn : clrChannelSymbolOff), frameColor);
 | 
			
		||||
     osd->DrawBitmap(x, y0 + (y1 - y0 - bmAudio.Height()) / 2, bmAudio, Theme.Color(Channel->Apid(1) ? clrChannelSymbolOn : clrChannelSymbolOff), frameColor);
 | 
			
		||||
     if (Channel->Vpid()) {
 | 
			
		||||
        x -= bmTeletext.Width() + d;
 | 
			
		||||
        osd->DrawBitmap(x, y0 + (y1 - y0 - bmTeletext.Height()) / 2, bmTeletext, Theme.Color(Channel->Tpid() ? clrChannelSymbolOn : clrChannelSymbolOff), frameColor);
 | 
			
		||||
        }
 | 
			
		||||
     else if (Channel->Apid1()) {
 | 
			
		||||
     else if (Channel->Apid(0)) {
 | 
			
		||||
        x -= bmRadio.Width() + d;
 | 
			
		||||
        osd->DrawBitmap(x, y0 + (y1 - y0 - bmRadio.Height()) / 2, bmRadio, Theme.Color(clrChannelSymbolOn), frameColor);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										101
									
								
								transfer.c
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								transfer.c
									
									
									
									
									
								
							@@ -4,7 +4,7 @@
 | 
			
		||||
 * See the main source file 'vdr.c' for copyright information and
 | 
			
		||||
 * how to reach the author.
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: transfer.c 1.18 2004/10/23 13:35:08 kls Exp $
 | 
			
		||||
 * $Id: transfer.c 1.19 2004/11/28 11:51:00 kls Exp $
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "transfer.h"
 | 
			
		||||
@@ -20,8 +20,6 @@ cTransfer::cTransfer(int VPid, int APid1, int APid2, int DPid1, int DPid2)
 | 
			
		||||
{
 | 
			
		||||
  ringBuffer = new cRingBufferLinear(TRANSFERBUFSIZE, TS_SIZE * 2, true, "Transfer");
 | 
			
		||||
  remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2);
 | 
			
		||||
  canToggleAudioTrack = false;
 | 
			
		||||
  audioTrack = 0xC0;
 | 
			
		||||
  active = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -60,8 +58,41 @@ void cTransfer::Action(void)
 | 
			
		||||
  int PollTimeouts = 0;
 | 
			
		||||
  uchar *p = NULL;
 | 
			
		||||
  int Result = 0;
 | 
			
		||||
// XXX Apparently this isn't necessary with the new PES data handling that
 | 
			
		||||
// XXX was intorduced in VDR 1.3.18. If you do need this, enable the following
 | 
			
		||||
// XXX line and send an email to kls@cadsoft.de. If nobody requires this, it
 | 
			
		||||
// XXX will be removed later. kls 2004-12-27
 | 
			
		||||
//#define FW_NEEDS_BUFFER_RESERVE_FOR_AC3
 | 
			
		||||
#ifdef FW_NEEDS_BUFFER_RESERVE_FOR_AC3
 | 
			
		||||
  bool Cleared = false;
 | 
			
		||||
  bool GotBufferReserve = false;
 | 
			
		||||
#endif
 | 
			
		||||
  active = true;
 | 
			
		||||
  while (active) {
 | 
			
		||||
#ifdef FW_NEEDS_BUFFER_RESERVE_FOR_AC3
 | 
			
		||||
#define HasDolby true
 | 
			
		||||
        if (HasDolby) {
 | 
			
		||||
           if (IsAttached() && !Cleared) {
 | 
			
		||||
              PlayPes(NULL, 0);
 | 
			
		||||
              Cleared = true;
 | 
			
		||||
              }
 | 
			
		||||
           //XXX For dolby we've to fill the buffer because the firmware does
 | 
			
		||||
           //XXX not decode dolby but use a PCM stream for transport, therefore
 | 
			
		||||
           //XXX the firmware has not enough buffer for noiseless skipping early
 | 
			
		||||
           //XXX PCM samples (each dolby frame requires 6144 bytes in PCM and
 | 
			
		||||
           //XXX audio is mostly to early in comparison to video).
 | 
			
		||||
           //XXX To resolve this, the remuxer or PlayPes() should synchronize
 | 
			
		||||
           //XXX audio with the video frames. 2004/09/09 Werner
 | 
			
		||||
           if (!GotBufferReserve) {
 | 
			
		||||
              if (ringBuffer->Available() < 3 * MAXFRAMESIZE / 2) {
 | 
			
		||||
                 cCondWait::SleepMs(20); // allow the buffer to collect some reserve
 | 
			
		||||
                 continue;
 | 
			
		||||
                 }
 | 
			
		||||
              else
 | 
			
		||||
                 GotBufferReserve = true;
 | 
			
		||||
              }
 | 
			
		||||
           }
 | 
			
		||||
#endif
 | 
			
		||||
        int Count;
 | 
			
		||||
        uchar *b = ringBuffer->Get(Count);
 | 
			
		||||
        if (b) {
 | 
			
		||||
@@ -80,13 +111,13 @@ void cTransfer::Action(void)
 | 
			
		||||
           if (Count)
 | 
			
		||||
              ringBuffer->Del(Count);
 | 
			
		||||
           }
 | 
			
		||||
        if (!p && (p = remux->Get(Result)) != NULL)
 | 
			
		||||
           StripAudioPackets(p, Result, audioTrack);
 | 
			
		||||
        if (!p)
 | 
			
		||||
           p = remux->Get(Result);
 | 
			
		||||
        if (p) {
 | 
			
		||||
           cPoller Poller;
 | 
			
		||||
           if (DevicePoll(Poller, 100)) {
 | 
			
		||||
              PollTimeouts = 0;
 | 
			
		||||
              int w = PlayVideo(p, Result);
 | 
			
		||||
              int w = PlayPes(p, Result);
 | 
			
		||||
              if (w > 0) {
 | 
			
		||||
                 p += w;
 | 
			
		||||
                 Result -= w;
 | 
			
		||||
@@ -112,64 +143,6 @@ void cTransfer::Action(void)
 | 
			
		||||
  active = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cTransfer::StripAudioPackets(uchar *b, int Length, uchar Except)
 | 
			
		||||
{
 | 
			
		||||
  for (int i = 0; i < Length - 6; i++) {
 | 
			
		||||
      if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) {
 | 
			
		||||
         uchar c = b[i + 3];
 | 
			
		||||
         int l = b[i + 4] * 256 + b[i + 5] + 6;
 | 
			
		||||
         switch (c) {
 | 
			
		||||
           case 0xBD: // dolby
 | 
			
		||||
                if (Except)
 | 
			
		||||
                   PlayAudio(&b[i], l);
 | 
			
		||||
                // continue with deleting the data - otherwise it disturbs DVB replay
 | 
			
		||||
           case 0xC0 ... 0xC1: // audio
 | 
			
		||||
                if (c == 0xC1)
 | 
			
		||||
                   canToggleAudioTrack = true;
 | 
			
		||||
                if (!Except || c != Except)
 | 
			
		||||
                   memset(&b[i], 0x00, min(l, Length-i));
 | 
			
		||||
                break;
 | 
			
		||||
           case 0xE0 ... 0xEF: // video
 | 
			
		||||
                break;
 | 
			
		||||
           default:
 | 
			
		||||
                //esyslog("ERROR: unexpected packet id %02X", c);
 | 
			
		||||
                l = 0;
 | 
			
		||||
           }
 | 
			
		||||
         if (l)
 | 
			
		||||
            i += l - 1; // the loop increments, too!
 | 
			
		||||
         }
 | 
			
		||||
      /*XXX
 | 
			
		||||
      else
 | 
			
		||||
         esyslog("ERROR: broken packet header");
 | 
			
		||||
         XXX*/
 | 
			
		||||
      }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int cTransfer::NumAudioTracks(void) const
 | 
			
		||||
{
 | 
			
		||||
  return canToggleAudioTrack ? 2 : 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char **cTransfer::GetAudioTracks(int *CurrentTrack) const
 | 
			
		||||
{
 | 
			
		||||
  if (NumAudioTracks()) {
 | 
			
		||||
     if (CurrentTrack)
 | 
			
		||||
        *CurrentTrack = (audioTrack == 0xC0) ? 0 : 1;
 | 
			
		||||
     static const char *audioTracks1[] = { "Audio 1", NULL };
 | 
			
		||||
     static const char *audioTracks2[] = { "Audio 1", "Audio 2", NULL };
 | 
			
		||||
     return NumAudioTracks() > 1 ? audioTracks2 : audioTracks1;
 | 
			
		||||
     }
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cTransfer::SetAudioTrack(int Index)
 | 
			
		||||
{
 | 
			
		||||
  if ((audioTrack == 0xC0) != (Index == 0)) {
 | 
			
		||||
     audioTrack = (Index == 1) ? 0xC1 : 0xC0;
 | 
			
		||||
     DeviceClear();
 | 
			
		||||
     }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// --- cTransferControl ------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
cDevice *cTransferControl::receiverDevice = NULL;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
 * See the main source file 'vdr.c' for copyright information and
 | 
			
		||||
 * how to reach the author.
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: transfer.h 1.5 2004/10/15 12:39:54 kls Exp $
 | 
			
		||||
 * $Id: transfer.h 1.6 2004/11/28 11:51:37 kls Exp $
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __TRANSFER_H
 | 
			
		||||
@@ -20,10 +20,7 @@ class cTransfer : public cReceiver, public cPlayer, public cThread {
 | 
			
		||||
private:
 | 
			
		||||
  cRingBufferLinear *ringBuffer;
 | 
			
		||||
  cRemux *remux;
 | 
			
		||||
  bool canToggleAudioTrack;
 | 
			
		||||
  uchar audioTrack;
 | 
			
		||||
  bool active;
 | 
			
		||||
  void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00);
 | 
			
		||||
protected:
 | 
			
		||||
  virtual void Activate(bool On);
 | 
			
		||||
  virtual void Receive(uchar *Data, int Length);
 | 
			
		||||
@@ -31,9 +28,6 @@ protected:
 | 
			
		||||
public:
 | 
			
		||||
  cTransfer(int VPid, int APid1, int APid2, int DPid1, int DPid2);
 | 
			
		||||
  virtual ~cTransfer();
 | 
			
		||||
  virtual int NumAudioTracks(void) const;
 | 
			
		||||
  virtual const char **GetAudioTracks(int *CurrentTrack = NULL) const;
 | 
			
		||||
  virtual void SetAudioTrack(int Index);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
class cTransferControl : public cControl {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								vdr.c
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								vdr.c
									
									
									
									
									
								
							@@ -22,7 +22,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 * The project's page is at http://www.cadsoft.de/vdr
 | 
			
		||||
 *
 | 
			
		||||
 * $Id: vdr.c 1.193 2004/11/06 10:30:30 kls Exp $
 | 
			
		||||
 * $Id: vdr.c 1.194 2004/12/05 13:20:29 kls Exp $
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
@@ -532,7 +532,7 @@ int main(int argc, char *argv[])
 | 
			
		||||
           static time_t lastTime = 0;
 | 
			
		||||
           if (time(NULL) - lastTime > MINCHANNELWAIT) {
 | 
			
		||||
              cChannel *Channel = Channels.GetByNumber(cDevice::CurrentChannel());
 | 
			
		||||
              if (Channel && (Channel->Vpid() || Channel->Apid1())) {
 | 
			
		||||
              if (Channel && (Channel->Vpid() || Channel->Apid(0))) {
 | 
			
		||||
                 if (!Channels.SwitchTo(cDevice::CurrentChannel()) // try to switch to the original channel...
 | 
			
		||||
                     && !(LastTimerChannel > 0 && Channels.SwitchTo(LastTimerChannel)) // ...or the one used by the last timer...
 | 
			
		||||
                     && !cDevice::SwitchChannel(1) // ...or the next higher available one...
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user