mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Added support for AC3 replay over the DVB device
This commit is contained in:
parent
69ecb6a4d8
commit
c77989ee70
@ -263,6 +263,8 @@ Werner Fink <werner@suse.de>
|
|||||||
for suggesting to add more checks and polling when getting frontend events
|
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
|
for setting the VPID before the APID in live mode to avoid unnecessary
|
||||||
overhead in the firmware
|
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>
|
Rolf Hakenes <hakenes@hippomi.de>
|
||||||
for providing 'libdtv' and adapting the EIT mechanisms to it
|
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.
|
right day of week for timers in the future.
|
||||||
- Some improvements to cPoller (thanks to Marco Schlüßler).
|
- Some improvements to cPoller (thanks to Marco Schlüß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
|
- Removed an unused variable from cTimer::GetWDayFromMDay() (thanks to Wayne Keer
|
||||||
for reporting this one).
|
for reporting this one).
|
||||||
@ -3171,3 +3171,25 @@ Video Disk Recorder Revision History
|
|||||||
picture mode (thanks to Reinhard Nissl for reporting this one).
|
picture mode (thanks to Reinhard Nissl for reporting this one).
|
||||||
- Fixed a possible race condition in generating the DVB device names (thanks to
|
- Fixed a possible race condition in generating the DVB device names (thanks to
|
||||||
Rainer Zocholl for reporting this one).
|
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>
|
<a href="http://www.cadsoft.de/vdr">www.cadsoft.de/vdr</a>
|
||||||
</center>
|
</center>
|
||||||
<p>
|
<p>
|
||||||
<!--X1.2.6--><table width=100%><tr><td bgcolor=#0000AA> </td><td width=100%>
|
<!--X1.3.0--><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%>
|
|
||||||
Important modifications introduced in version 1.3.0 are marked like this.
|
Important modifications introduced in version 1.3.0 are marked like this.
|
||||||
<!--X1.3.0--></td></tr></table>
|
<!--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.
|
Important modifications introduced in version 1.3.7 are marked like this.
|
||||||
<!--X1.3.7--></td></tr></table>
|
<!--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.
|
Important modifications introduced in version 1.3.8 are marked like this.
|
||||||
<!--X1.3.8--></td></tr></table>
|
<!--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>
|
<p>
|
||||||
VDR provides an easy to use plugin interface that allows additional functionality
|
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.
|
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="#Status monitor">Status monitor</a>
|
||||||
<li><a href="#Players">Players</a>
|
<li><a href="#Players">Players</a>
|
||||||
<li><a href="#Receivers">Receivers</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>
|
<li><a href="#Filters">Filters</a>
|
||||||
<!--X1.3.0--></td></tr></table>
|
<!--X1.3.0--></td></tr></table>
|
||||||
<li><a href="#The On Screen Display">The On Screen Display</a>
|
<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="#Skins">Skins</a>
|
||||||
<li><a href="#Themes">Themes</a>
|
<li><a href="#Themes">Themes</a>
|
||||||
<!--X1.3.7--></td></tr></table>
|
<!--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
|
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.
|
its own player for the VDR recordings.
|
||||||
<p>
|
<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>
|
<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>
|
</pre></td></tr></table><p>
|
||||||
|
|
||||||
where <tt>Data</tt> points to a block of <tt>Length</tt> bytes of a PES data
|
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
|
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.
|
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
|
To avoid busy loops the player should call its member function
|
||||||
|
|
||||||
<p><table><tr><td bgcolor=#F0F0F0><pre>
|
<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.
|
to determine whether the device is ready for further data.
|
||||||
<p>
|
<p>
|
||||||
If the player can provide more than a single audio track, it can implement the
|
<!--X1.3.18--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%>
|
||||||
following functions to make them available:
|
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>
|
<p><table><tr><td bgcolor=#F0F0F0><pre>
|
||||||
virtual int NumAudioTracks(void) const;
|
virtual void SetAudioTrack(eTrackType Type, const tTrackId *TrackId)
|
||||||
virtual const char **GetAudioTracks(int *CurrentTrack = NULL);
|
|
||||||
virtual void SetAudioTrack(int Index);
|
|
||||||
</pre></td></tr></table><p>
|
</pre></td></tr></table><p>
|
||||||
|
|
||||||
<p>
|
A player that has special requirements about audio tracks should announce its
|
||||||
If there is an additional audio track that has to be replayed with external hardware,
|
available audio tracks by calling
|
||||||
the player shall call its member function
|
|
||||||
|
|
||||||
<p><table><tr><td bgcolor=#F0F0F0><pre>
|
<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>
|
</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>
|
<p>
|
||||||
The second part needed here is a control object that receives user input from the main
|
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:
|
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>
|
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>.
|
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>
|
<a name="Filters"><hr><h2>Filters</h2>
|
||||||
|
|
||||||
<center><i><b>A Fistful of Datas</b></i></center><p>
|
<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.
|
See VDR/eit.c or VDR/pat.c to learn how to process filter data.
|
||||||
<!--X1.3.0--></td></tr></table>
|
<!--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>
|
<a name="The On Screen Display"><hr><h2>The On Screen Display</h2>
|
||||||
|
|
||||||
<center><i><b>Window to the world</b></i></center><p>
|
<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.
|
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.
|
Do not delete this object, it will be automatically deleted when the program ends.
|
||||||
<p>
|
<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
|
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
|
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 HasDecoder(void) const;
|
||||||
virtual bool CanReplay(void) const;
|
virtual bool CanReplay(void) const;
|
||||||
virtual bool SetPlayMode(ePlayMode PlayMode);
|
virtual bool SetPlayMode(ePlayMode PlayMode);
|
||||||
<!--X1.2.6--><table width=100%><tr><td bgcolor=#0000AA> </td><td width=100%>
|
|
||||||
virtual int64_t GetSTC(void);
|
virtual int64_t GetSTC(void);
|
||||||
<!--X1.2.6--></td></tr></table>
|
|
||||||
virtual void TrickSpeed(int Speed);
|
virtual void TrickSpeed(int Speed);
|
||||||
virtual void Clear(void);
|
virtual void Clear(void);
|
||||||
virtual void Play(void);
|
virtual void Play(void);
|
||||||
@ -1549,7 +1553,7 @@ virtual void SetVideoFormat(bool VideoFormat16_9);
|
|||||||
virtual void SetVolumeDevice(int Volume);
|
virtual void SetVolumeDevice(int Volume);
|
||||||
</pre></td></tr></table><p>
|
</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>
|
<p>
|
||||||
<b>Section Filtering</b>
|
<b>Section Filtering</b>
|
||||||
<p>
|
<p>
|
||||||
@ -1579,7 +1583,7 @@ handle section data.
|
|||||||
<p>
|
<p>
|
||||||
<b>On Screen Display</b>
|
<b>On Screen Display</b>
|
||||||
<p>
|
<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
|
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
|
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>
|
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
|
2004-10-16: Version 0.3.1
|
||||||
|
|
||||||
- Improved buffer handling.
|
- 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.
|
* 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>
|
#include <sys/socket.h>
|
||||||
@ -14,7 +14,7 @@
|
|||||||
#include <vdr/plugin.h>
|
#include <vdr/plugin.h>
|
||||||
#include <vdr/sources.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";
|
static const char *DESCRIPTION = "Sky Digibox interface";
|
||||||
|
|
||||||
// --- cDigiboxDevice --------------------------------------------------------
|
// --- cDigiboxDevice --------------------------------------------------------
|
||||||
@ -213,7 +213,7 @@ bool cDigiboxDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
|||||||
cSkyChannel *SkyChannel = SkyChannels.GetSkyChannel(Channel);
|
cSkyChannel *SkyChannel = SkyChannels.GetSkyChannel(Channel);
|
||||||
if (SkyChannel) {
|
if (SkyChannel) {
|
||||||
digiboxChannelNumber = SkyChannel->digiboxChannelNumber;
|
digiboxChannelNumber = SkyChannel->digiboxChannelNumber;
|
||||||
apid = Channel->Apid1();
|
apid = Channel->Apid(0);
|
||||||
vpid = Channel->Vpid();
|
vpid = Channel->Vpid();
|
||||||
//XXX only when recording??? -> faster channel switching!
|
//XXX only when recording??? -> faster channel switching!
|
||||||
LircSend("SKY"); // makes sure the Digibox is "on"
|
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
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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
|
#ifndef __CHANNELS_H
|
||||||
@ -145,10 +145,10 @@ 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 Apid1(void) const { return apids[0]; }
|
int Apid(int i) const { return (0 <= i && i < MAXAPIDS) ? apids[i] : 0; }
|
||||||
int Apid2(void) const { return apids[1]; }
|
int Dpid(int i) const { return (0 <= i && i < MAXAPIDS) ? dpids[i] : 0; }
|
||||||
int Dpid1(void) const { return dpids[0]; }
|
const char *Alang(int i) const { return (0 <= i && i < MAXAPIDS) ? alangs[i] : ""; }
|
||||||
int Dpid2(void) const { return dpids[1]; }
|
const char *Dlang(int i) const { return (0 <= i && i < MAXAPIDS) ? dlangs[i] : ""; }
|
||||||
int Tpid(void) const { return tpid; }
|
int Tpid(void) const { return tpid; }
|
||||||
int Ca(int Index = 0) const { return Index < MAXCAIDS ? caids[Index] : 0; }
|
int Ca(int Index = 0) const { return Index < MAXCAIDS ? caids[Index] : 0; }
|
||||||
int Nid(void) const { return nid; }
|
int Nid(void) const { return nid; }
|
||||||
|
268
device.c
268
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 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"
|
#include "device.h"
|
||||||
@ -19,6 +19,87 @@
|
|||||||
#include "status.h"
|
#include "status.h"
|
||||||
#include "transfer.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 ---------------------------------------------------------------
|
// --- cDevice ---------------------------------------------------------------
|
||||||
|
|
||||||
// The default priority for non-primary devices:
|
// The default priority for non-primary devices:
|
||||||
@ -53,6 +134,9 @@ cDevice::cDevice(void)
|
|||||||
|
|
||||||
ciHandler = NULL;
|
ciHandler = NULL;
|
||||||
player = NULL;
|
player = NULL;
|
||||||
|
pesAssembler = new cPesAssembler;
|
||||||
|
ClrAvailableTracks();
|
||||||
|
currentAudioTrack = ttAudioFirst;
|
||||||
|
|
||||||
for (int i = 0; i < MAXRECEIVERS; i++)
|
for (int i = 0; i < MAXRECEIVERS; i++)
|
||||||
receiver[i] = NULL;
|
receiver[i] = NULL;
|
||||||
@ -74,6 +158,7 @@ cDevice::~cDevice()
|
|||||||
delete patFilter;
|
delete patFilter;
|
||||||
delete eitFilter;
|
delete eitFilter;
|
||||||
delete sectionHandler;
|
delete sectionHandler;
|
||||||
|
delete pesAssembler;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cDevice::SetUseDevice(int n)
|
void cDevice::SetUseDevice(int n)
|
||||||
@ -427,7 +512,7 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
|
|||||||
if (CaDevice && CanReplay()) {
|
if (CaDevice && CanReplay()) {
|
||||||
cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel
|
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()!
|
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
|
else
|
||||||
Result = scrNoTransfer;
|
Result = scrNoTransfer;
|
||||||
}
|
}
|
||||||
@ -482,17 +567,7 @@ void cDevice::SetVolumeDevice(int Volume)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int cDevice::NumAudioTracksDevice(void) const
|
void cDevice::SetAudioTrackDevice(eTrackType Type)
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char **cDevice::GetAudioTracksDevice(int *CurrentTrack) const
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cDevice::SetAudioTrackDevice(int Index)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cDevice::SetAudioTrack(int Index)
|
|
||||||
{
|
{
|
||||||
|
if (ttNone < Type && Type < ttDolbyLast) {
|
||||||
|
if (IS_DOLBY_TRACK(Type))
|
||||||
|
SetDigitalAudioDevice(true);
|
||||||
|
currentAudioTrack = Type;
|
||||||
if (player)
|
if (player)
|
||||||
player->SetAudioTrack(Index);
|
player->SetAudioTrack(currentAudioTrack, GetTrack(currentAudioTrack));
|
||||||
else
|
else
|
||||||
SetAudioTrackDevice(Index);
|
SetAudioTrackDevice(currentAudioTrack);
|
||||||
|
if (IS_AUDIO_TRACK(Type))
|
||||||
|
SetDigitalAudioDevice(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cDevice::IncCurrentAudioTrack(void)
|
||||||
|
{
|
||||||
|
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
|
bool cDevice::CanReplay(void) const
|
||||||
@ -595,6 +720,7 @@ bool cDevice::AttachPlayer(cPlayer *Player)
|
|||||||
if (CanReplay()) {
|
if (CanReplay()) {
|
||||||
if (player)
|
if (player)
|
||||||
Detach(player);
|
Detach(player);
|
||||||
|
ClrAvailableTracks();
|
||||||
player = Player;
|
player = Player;
|
||||||
SetPlayMode(player->playMode);
|
SetPlayMode(player->playMode);
|
||||||
player->device = this;
|
player->device = this;
|
||||||
@ -639,11 +765,105 @@ int cDevice::PlayVideo(const uchar *Data, int Length)
|
|||||||
return -1;
|
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 cDevice::Ca(void) const
|
||||||
{
|
{
|
||||||
int ca = 0;
|
int ca = 0;
|
||||||
|
136
device.h
136
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 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
|
#ifndef __DEVICE_H
|
||||||
@ -56,10 +56,36 @@ enum eVideoSystem { vsPAL,
|
|||||||
vsNTSC
|
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 cChannel;
|
||||||
class cPlayer;
|
class cPlayer;
|
||||||
class cReceiver;
|
class cReceiver;
|
||||||
class cSpuDecoder;
|
class cSpuDecoder;
|
||||||
|
class cPesAssembler;
|
||||||
|
|
||||||
/// 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.
|
||||||
|
|
||||||
@ -283,6 +309,37 @@ public:
|
|||||||
///< Returns the video system of the currently displayed material
|
///< Returns the video system of the currently displayed material
|
||||||
///< (default is PAL).
|
///< (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
|
// Audio facilities
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -291,27 +348,9 @@ private:
|
|||||||
protected:
|
protected:
|
||||||
virtual void SetVolumeDevice(int Volume);
|
virtual void SetVolumeDevice(int Volume);
|
||||||
///< Sets the audio volume on this device (Volume = 0...255).
|
///< Sets the audio volume on this device (Volume = 0...255).
|
||||||
virtual int NumAudioTracksDevice(void) const;
|
virtual void SetDigitalAudioDevice(bool On) {}
|
||||||
///< Returns the number of audio tracks that are currently available on this
|
///< Tells the actual device that digital audio output shall be switched
|
||||||
///< device. The default return value is 0, meaning that this device
|
///< on or off.
|
||||||
///< 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).
|
|
||||||
public:
|
public:
|
||||||
bool IsMute(void) const { return mute; }
|
bool IsMute(void) const { return mute; }
|
||||||
bool ToggleMute(void);
|
bool ToggleMute(void);
|
||||||
@ -320,32 +359,37 @@ public:
|
|||||||
///< Sets the volume to the given value, either absolutely or relative to
|
///< Sets the volume to the given value, either absolutely or relative to
|
||||||
///< the current volume.
|
///< the current volume.
|
||||||
static int CurrentVolume(void) { return primaryDevice ? primaryDevice->volume : 0; }//XXX???
|
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
|
// Player facilities
|
||||||
|
|
||||||
private:
|
private:
|
||||||
cPlayer *player;
|
cPlayer *player;
|
||||||
|
cPesAssembler *pesAssembler;
|
||||||
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.
|
||||||
virtual bool SetPlayMode(ePlayMode PlayMode);
|
virtual bool SetPlayMode(ePlayMode PlayMode);
|
||||||
///< Sets the device into the given play mode.
|
///< Sets the device into the given play mode.
|
||||||
///< \return true if the operation was successful.
|
///< \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:
|
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
|
||||||
@ -382,14 +426,16 @@ public:
|
|||||||
///< If TimeoutMs is not zero, the device will wait up to the given
|
///< If TimeoutMs is not zero, the device will wait up to the given
|
||||||
///< number of milliseconds before returning in case there is still
|
///< number of milliseconds before returning in case there is still
|
||||||
///< data in the buffers..
|
///< data in the buffers..
|
||||||
virtual int PlayVideo(const uchar *Data, int Length);
|
virtual int PlayPes(const uchar *Data, int Length, bool VideoOnly = false);
|
||||||
///< Actually plays the given data block as video. The data must be
|
///< Plays all valid PES packets in Data with the given Length.
|
||||||
///< part of a PES (Packetized Elementary Stream) which can contain
|
///< If Data is NULL any leftover data from a previous call will be
|
||||||
///< one video and one audio stream.
|
///< discarded. If VideoOnly is true, only the video will be displayed,
|
||||||
virtual void PlayAudio(const uchar *Data, int Length);
|
///< which is necessary for trick modes like 'fast forward'.
|
||||||
///< Plays additional audio streams, like Dolby Digital.
|
///< Data should point to a sequence of complete PES packets. If the
|
||||||
///< A derived class must call the base class function to make sure data
|
///< last packet in Data is not complete, it will be copied and combined
|
||||||
///< is distributed to all registered cAudio objects.
|
///< 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;
|
bool Replaying(void) const;
|
||||||
///< Returns true if we are currently replaying.
|
///< Returns true if we are currently replaying.
|
||||||
void StopReplay(void);
|
void StopReplay(void);
|
||||||
|
76
dvbdevice.c
76
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 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"
|
#include "dvbdevice.h"
|
||||||
@ -322,9 +322,9 @@ void cDvbTuner::Action(void)
|
|||||||
cCiCaPmt CaPmt(channel.Source(), channel.Transponder(), channel.Sid(), ciHandler->GetCaSystemIds(Slot));
|
cCiCaPmt CaPmt(channel.Source(), channel.Transponder(), channel.Sid(), ciHandler->GetCaSystemIds(Slot));
|
||||||
if (CaPmt.Valid()) {
|
if (CaPmt.Valid()) {
|
||||||
CaPmt.AddPid(channel.Vpid(), 2);
|
CaPmt.AddPid(channel.Vpid(), 2);
|
||||||
CaPmt.AddPid(channel.Apid1(), 4);
|
CaPmt.AddPid(channel.Apid(0), 4);
|
||||||
CaPmt.AddPid(channel.Apid2(), 4);
|
CaPmt.AddPid(channel.Apid(1), 4);
|
||||||
CaPmt.AddPid(channel.Dpid1(), 0);
|
CaPmt.AddPid(channel.Dpid(0), 0);
|
||||||
if (ciHandler->SetCaPmt(CaPmt, Slot)) {
|
if (ciHandler->SetCaPmt(CaPmt, Slot)) {
|
||||||
tunerStatus = tsCam;
|
tunerStatus = tsCam;
|
||||||
startTime = 0;
|
startTime = 0;
|
||||||
@ -352,8 +352,8 @@ cDvbDevice::cDvbDevice(int n)
|
|||||||
dvbTuner = NULL;
|
dvbTuner = NULL;
|
||||||
frontendType = fe_type_t(-1); // don't know how else to initialize this - there is no FE_UNKNOWN
|
frontendType = fe_type_t(-1); // don't know how else to initialize this - there is no FE_UNKNOWN
|
||||||
spuDecoder = NULL;
|
spuDecoder = NULL;
|
||||||
|
digitalAudio = false;
|
||||||
playMode = pmNone;
|
playMode = pmNone;
|
||||||
aPid1 = aPid2 = 0;
|
|
||||||
|
|
||||||
// Devices that are present on all card types:
|
// Devices that are present on all card types:
|
||||||
|
|
||||||
@ -728,7 +728,7 @@ bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Ne
|
|||||||
result = hasPriority;
|
result = hasPriority;
|
||||||
if (Priority >= 0 && Receiving(true)) {
|
if (Priority >= 0 && Receiving(true)) {
|
||||||
if (dvbTuner->IsTunedTo(Channel)) {
|
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
|
#ifdef DO_MULTIPLE_RECORDINGS
|
||||||
if (Ca() > CACONFBASE || Channel->Ca() > CACONFBASE)
|
if (Ca() > CACONFBASE || Channel->Ca() > CACONFBASE)
|
||||||
needsDetachReceivers = !ciHandler // only LL-firmware can do non-live CA channels
|
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:
|
// PID settings:
|
||||||
|
|
||||||
if (TurnOnLivePIDs) {
|
if (TurnOnLivePIDs) {
|
||||||
aPid1 = Channel->Apid1();
|
ClrAvailableTracks();
|
||||||
aPid2 = Channel->Apid2();
|
for (int i = 0; i < MAXAPIDS; i++) {
|
||||||
if (!(AddPid(Channel->Ppid(), ptPcr) && AddPid(Channel->Vpid(), ptVideo) && AddPid(Channel->Apid1(), ptAudio))) {//XXX+ dolby dpid1!!! (if audio plugins are attached)
|
//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);
|
esyslog("ERROR: failed to set PIDs for channel %d on device %d", Channel->Number(), CardIndex() + 1);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -815,7 +819,7 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
|||||||
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
|
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
|
||||||
}
|
}
|
||||||
else if (StartTransferMode)
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
@ -835,35 +839,33 @@ void cDvbDevice::SetVolumeDevice(int Volume)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int cDvbDevice::NumAudioTracksDevice(void) const
|
void cDvbDevice::SetDigitalAudioDevice(bool On)
|
||||||
{
|
{
|
||||||
int n = 0;
|
if (digitalAudio != On) {
|
||||||
if (aPid1)
|
if (digitalAudio)
|
||||||
n++;
|
cCondWait::SleepMs(1000); // Wait until any leftover digital data has been flushed
|
||||||
if (Ca() <= MAXDEVICES && aPid2 && aPid1 != aPid2) // a CA recording session blocks switching live audio tracks
|
SetVolumeDevice(On || IsMute() ? 0 : CurrentVolume());
|
||||||
n++;
|
digitalAudio = On;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cDvbDevice::SetAudioTrackDevice(int Index)
|
void cDvbDevice::SetAudioTrackDevice(eTrackType Type)
|
||||||
{
|
{
|
||||||
if (0 <= Index && Index < NumAudioTracksDevice()) {
|
const tTrackId *TrackId = GetTrack(Type);
|
||||||
int Pid = Index ? aPid2 : aPid1;
|
if (TrackId && TrackId->id) {
|
||||||
pidHandles[ptAudio].pid = Pid;
|
if (IS_AUDIO_TRACK(Type)) {
|
||||||
|
pidHandles[ptAudio].pid = TrackId->id;
|
||||||
SetPid(&pidHandles[ptAudio], ptAudio, true);
|
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)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cDvbDevice::CanReplay(void) const
|
bool cDvbDevice::CanReplay(void) const
|
||||||
@ -1120,16 +1122,12 @@ bool cDvbDevice::Flush(int TimeoutMs)
|
|||||||
|
|
||||||
int cDvbDevice::PlayVideo(const uchar *Data, int Length)
|
int cDvbDevice::PlayVideo(const uchar *Data, int Length)
|
||||||
{
|
{
|
||||||
int fd = (playMode == pmAudioOnly || playMode == pmAudioOnlyBlack) ? fd_audio : fd_video;
|
return write(fd_video, Data, Length);
|
||||||
if (fd >= 0)
|
|
||||||
return write(fd, Data, Length);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
return write(fd_audio, Data, Length);
|
||||||
cDevice::PlayAudio(Data, Length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cDvbDevice::OpenDvr(void)
|
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
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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
|
#ifndef __DVBDEVICE_H
|
||||||
@ -90,15 +90,18 @@ public:
|
|||||||
virtual void SetVideoFormat(bool VideoFormat16_9);
|
virtual void SetVideoFormat(bool VideoFormat16_9);
|
||||||
virtual eVideoSystem GetVideoSystem(void);
|
virtual eVideoSystem GetVideoSystem(void);
|
||||||
|
|
||||||
|
// Track facilities
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void SetAudioTrackDevice(eTrackType Type);
|
||||||
|
|
||||||
// Audio facilities
|
// Audio facilities
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int aPid1, aPid2;
|
bool digitalAudio;
|
||||||
protected:
|
protected:
|
||||||
virtual void SetVolumeDevice(int Volume);
|
virtual void SetVolumeDevice(int Volume);
|
||||||
virtual int NumAudioTracksDevice(void) const;
|
virtual void SetDigitalAudioDevice(bool On);
|
||||||
virtual const char **GetAudioTracksDevice(int *CurrentTrack = NULL) const;
|
|
||||||
virtual void SetAudioTrackDevice(int Index);
|
|
||||||
|
|
||||||
// Player facilities
|
// Player facilities
|
||||||
|
|
||||||
@ -106,6 +109,8 @@ protected:
|
|||||||
ePlayMode playMode;
|
ePlayMode playMode;
|
||||||
virtual bool CanReplay(void) const;
|
virtual bool CanReplay(void) const;
|
||||||
virtual bool SetPlayMode(ePlayMode PlayMode);
|
virtual bool SetPlayMode(ePlayMode PlayMode);
|
||||||
|
virtual int PlayVideo(const uchar *Data, int Length);
|
||||||
|
virtual int PlayAudio(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);
|
||||||
@ -116,8 +121,6 @@ public:
|
|||||||
virtual void StillPicture(const uchar *Data, int Length);
|
virtual void StillPicture(const uchar *Data, int Length);
|
||||||
virtual bool Poll(cPoller &Poller, int TimeoutMs = 0);
|
virtual bool Poll(cPoller &Poller, int TimeoutMs = 0);
|
||||||
virtual bool Flush(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
|
// Receiver facilities
|
||||||
|
|
||||||
|
87
dvbplayer.c
87
dvbplayer.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: 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"
|
#include "dvbplayer.h"
|
||||||
@ -194,13 +194,10 @@ private:
|
|||||||
ePlayDirs playDir;
|
ePlayDirs playDir;
|
||||||
int trickSpeed;
|
int trickSpeed;
|
||||||
int readIndex, writeIndex;
|
int readIndex, writeIndex;
|
||||||
bool canToggleAudioTrack;
|
|
||||||
uchar audioTrack;
|
|
||||||
cFrame *readFrame;
|
cFrame *readFrame;
|
||||||
cFrame *playFrame;
|
cFrame *playFrame;
|
||||||
void TrickSpeed(int Increment);
|
void TrickSpeed(int Increment);
|
||||||
void Empty(void);
|
void Empty(void);
|
||||||
void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00);
|
|
||||||
bool NextFile(uchar FileNumber = 0, int FileOffset = -1);
|
bool NextFile(uchar FileNumber = 0, int FileOffset = -1);
|
||||||
int Resume(void);
|
int Resume(void);
|
||||||
bool Save(void);
|
bool Save(void);
|
||||||
@ -220,9 +217,6 @@ public:
|
|||||||
void Goto(int Position, bool Still = false);
|
void Goto(int Position, bool Still = false);
|
||||||
virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
|
virtual bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
|
||||||
virtual bool GetReplayMode(bool &Play, bool &Forward, int &Speed);
|
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?
|
#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;
|
playMode = pmPlay;
|
||||||
playDir = pdForward;
|
playDir = pdForward;
|
||||||
trickSpeed = NORMAL_SPEED;
|
trickSpeed = NORMAL_SPEED;
|
||||||
canToggleAudioTrack = false;
|
|
||||||
audioTrack = 0xC0;
|
|
||||||
readIndex = writeIndex = -1;
|
readIndex = writeIndex = -1;
|
||||||
readFrame = NULL;
|
readFrame = NULL;
|
||||||
playFrame = NULL;
|
playFrame = NULL;
|
||||||
@ -312,41 +304,6 @@ void cDvbPlayer::Empty(void)
|
|||||||
firstPacket = true;
|
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)
|
bool cDvbPlayer::NextFile(uchar FileNumber, int FileOffset)
|
||||||
{
|
{
|
||||||
if (FileNumber > 0)
|
if (FileNumber > 0)
|
||||||
@ -413,7 +370,6 @@ void cDvbPlayer::Action(void)
|
|||||||
|
|
||||||
nonBlockingFileReader = new cNonBlockingFileReader;
|
nonBlockingFileReader = new cNonBlockingFileReader;
|
||||||
int Length = 0;
|
int Length = 0;
|
||||||
int AudioTrack = 0; // -1 = any, 0 = none, >0 = audioTrack
|
|
||||||
|
|
||||||
running = true;
|
running = true;
|
||||||
while (running && (NextFile() || readIndex >= 0 || ringBuffer->Available() || !DeviceFlush(100))) {
|
while (running && (NextFile() || readIndex >= 0 || ringBuffer->Available() || !DeviceFlush(100))) {
|
||||||
@ -449,9 +405,6 @@ void cDvbPlayer::Action(void)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
readIndex = Index;
|
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) {
|
else if (index) {
|
||||||
uchar FileNumber;
|
uchar FileNumber;
|
||||||
@ -462,12 +415,9 @@ void cDvbPlayer::Action(void)
|
|||||||
eof = true;
|
eof = true;
|
||||||
continue;
|
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;
|
Length = MAXFRAMESIZE;
|
||||||
AudioTrack = -1;
|
|
||||||
}
|
|
||||||
if (Length == -1)
|
if (Length == -1)
|
||||||
Length = MAXFRAMESIZE; // this means we read up to EOF (see cIndex)
|
Length = MAXFRAMESIZE; // this means we read up to EOF (see cIndex)
|
||||||
else if (Length > MAXFRAMESIZE) {
|
else if (Length > MAXFRAMESIZE) {
|
||||||
@ -478,8 +428,6 @@ void cDvbPlayer::Action(void)
|
|||||||
}
|
}
|
||||||
int r = nonBlockingFileReader->Read(replayFile, b, Length);
|
int r = nonBlockingFileReader->Read(replayFile, b, Length);
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
if (AudioTrack == 0)
|
|
||||||
StripAudioPackets(b, r);
|
|
||||||
readFrame = new cFrame(b, -r, ftUnknown, readIndex); // hands over b to the ringBuffer
|
readFrame = new cFrame(b, -r, ftUnknown, readIndex); // hands over b to the ringBuffer
|
||||||
b = NULL;
|
b = NULL;
|
||||||
}
|
}
|
||||||
@ -517,15 +465,14 @@ void cDvbPlayer::Action(void)
|
|||||||
pc = playFrame->Count();
|
pc = playFrame->Count();
|
||||||
if (p) {
|
if (p) {
|
||||||
if (firstPacket) {
|
if (firstPacket) {
|
||||||
|
PlayPes(NULL, 0);
|
||||||
cRemux::SetBrokenLink(p, pc);
|
cRemux::SetBrokenLink(p, pc);
|
||||||
firstPacket = false;
|
firstPacket = false;
|
||||||
}
|
}
|
||||||
if (AudioTrack > 0)
|
|
||||||
StripAudioPackets(p, pc, AudioTrack);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (p) {
|
if (p) {
|
||||||
int w = PlayVideo(p, pc);
|
int w = PlayPes(p, pc, playMode != pmPlay);
|
||||||
if (w > 0) {
|
if (w > 0) {
|
||||||
p += w;
|
p += w;
|
||||||
pc -= w;
|
pc -= w;
|
||||||
@ -717,7 +664,6 @@ void cDvbPlayer::Goto(int Index, bool Still)
|
|||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
if (playMode == pmPause)
|
if (playMode == pmPause)
|
||||||
DevicePlay();
|
DevicePlay();
|
||||||
StripAudioPackets(b, r);
|
|
||||||
DeviceStillPicture(b, r);
|
DeviceStillPicture(b, r);
|
||||||
}
|
}
|
||||||
playMode = pmStill;
|
playMode = pmStill;
|
||||||
@ -757,31 +703,6 @@ bool cDvbPlayer::GetReplayMode(bool &Play, bool &Forward, int &Speed)
|
|||||||
return true;
|
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::cDvbPlayerControl(const char *FileName)
|
cDvbPlayerControl::cDvbPlayerControl(const char *FileName)
|
||||||
|
13
menu.c
13
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 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"
|
#include "menu.h"
|
||||||
@ -2471,16 +2471,9 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
|
|||||||
state = replaying ? osContinue : osRecord;
|
state = replaying ? osContinue : osRecord;
|
||||||
break;
|
break;
|
||||||
case kGreen: if (!HadSubMenu) {
|
case kGreen: if (!HadSubMenu) {
|
||||||
int CurrentAudioTrack = -1;
|
cDevice::PrimaryDevice()->IncCurrentAudioTrack();
|
||||||
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;
|
state = osEnd;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case kYellow: if (!HadSubMenu)
|
case kYellow: if (!HadSubMenu)
|
||||||
state = replaying ? osContinue : osPause;
|
state = replaying ? osContinue : osPause;
|
||||||
@ -2826,7 +2819,7 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)
|
|||||||
isyslog("record %s", fileName);
|
isyslog("record %s", fileName);
|
||||||
if (MakeDirs(fileName, true)) {
|
if (MakeDirs(fileName, true)) {
|
||||||
const cChannel *ch = timer->Channel();
|
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)) {
|
if (device->AttachReceiver(recorder)) {
|
||||||
Recording.WriteSummary();
|
Recording.WriteSummary();
|
||||||
cStatus::MsgRecording(device, Recording.Name());
|
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
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#include "player.h"
|
||||||
@ -23,23 +23,14 @@ cPlayer::~cPlayer()
|
|||||||
Detach();
|
Detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
int cPlayer::PlayVideo(const uchar *Data, int Length)
|
int cPlayer::PlayPes(const uchar *Data, int Length, bool VideoOnly)
|
||||||
{
|
{
|
||||||
if (device)
|
if (device)
|
||||||
return device->PlayVideo(Data, Length);
|
return device->PlayPes(Data, Length, VideoOnly);
|
||||||
esyslog("ERROR: attempt to use cPlayer::PlayVideo() without attaching to a cDevice!");
|
esyslog("ERROR: attempt to use cPlayer::PlayPes() without attaching to a cDevice!");
|
||||||
return -1;
|
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)
|
void cPlayer::Detach(void)
|
||||||
{
|
{
|
||||||
if (device)
|
if (device)
|
||||||
|
36
player.h
36
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 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
|
#ifndef __PLAYER_H
|
||||||
@ -19,6 +19,7 @@ private:
|
|||||||
cDevice *device;
|
cDevice *device;
|
||||||
ePlayMode playMode;
|
ePlayMode playMode;
|
||||||
protected:
|
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 DevicePoll(cPoller &Poller, int TimeoutMs = 0) { return device ? device->Poll(Poller, TimeoutMs) : false; }
|
||||||
bool DeviceFlush(int TimeoutMs = 0) { return device ? device->Flush(TimeoutMs) : true; }
|
bool DeviceFlush(int TimeoutMs = 0) { return device ? device->Flush(TimeoutMs) : true; }
|
||||||
void DeviceTrickSpeed(int Speed) { if (device) device->TrickSpeed(Speed); }
|
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
|
// This function is called right after the cPlayer has been attached to
|
||||||
// (On == true) or before it gets detached from (On == false) a cDevice.
|
// (On == true) or before it gets detached from (On == false) a cDevice.
|
||||||
// It can be used to do things like starting/stopping a thread.
|
// It can be used to do things like starting/stopping a thread.
|
||||||
int PlayVideo(const uchar *Data, int Length);
|
int PlayPes(const uchar *Data, int Length, bool VideoOnly = false);
|
||||||
// Sends the given Data to the video 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 video 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).
|
||||||
void PlayAudio(const uchar *Data, int Length);
|
|
||||||
// Plays additional audio streams, like Dolby Digital.
|
|
||||||
public:
|
public:
|
||||||
cPlayer(ePlayMode PlayMode = pmAudioVideo);
|
cPlayer(ePlayMode PlayMode = pmAudioVideo);
|
||||||
virtual ~cPlayer();
|
virtual ~cPlayer();
|
||||||
@ -51,27 +50,10 @@ public:
|
|||||||
// we are going forward or backward and 'Speed' is -1 if this is normal
|
// 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
|
// play/pause mode, 0 if it is single speed fast/slow forward/back mode
|
||||||
// and >0 if this is multi speed mode.
|
// and >0 if this is multi speed mode.
|
||||||
virtual int NumAudioTracks(void) const { return 0; }
|
virtual void SetAudioTrack(eTrackType Type, const tTrackId *TrackId) {}
|
||||||
// Returns the number of audio tracks that are currently available on this
|
// Sets the current audio track to the given value.
|
||||||
// player. The default return value is 0, meaning that this player
|
// This is just a virtual hook for players that need to do special things
|
||||||
// doesn't have multiple audio track capabilities. The return value may
|
// in order to switch audio tracks.
|
||||||
// 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).
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class cControl : public cOsdObject {
|
class cControl : public cOsdObject {
|
||||||
|
@ -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: 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® is a registered trademark of Paramount Pictures
|
// Star Trek: The Next Generation® is a registered trademark of Paramount Pictures
|
||||||
@ -233,14 +233,14 @@ void cSkinSTTNGDisplayChannel::SetChannel(const cChannel *Channel, int Number)
|
|||||||
x -= bmEncrypted.Width() + d;
|
x -= bmEncrypted.Width() + d;
|
||||||
osd->DrawBitmap(x, y0 + (y1 - y0 - bmEncrypted.Height()) / 2, bmEncrypted, Theme.Color(Channel->Ca() ? clrChannelSymbolOn : clrChannelSymbolOff), frameColor);
|
osd->DrawBitmap(x, y0 + (y1 - y0 - bmEncrypted.Height()) / 2, bmEncrypted, Theme.Color(Channel->Ca() ? clrChannelSymbolOn : clrChannelSymbolOff), frameColor);
|
||||||
x -= bmDolbyDigital.Width() + d;
|
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;
|
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()) {
|
if (Channel->Vpid()) {
|
||||||
x -= bmTeletext.Width() + d;
|
x -= bmTeletext.Width() + d;
|
||||||
osd->DrawBitmap(x, y0 + (y1 - y0 - bmTeletext.Height()) / 2, bmTeletext, Theme.Color(Channel->Tpid() ? clrChannelSymbolOn : clrChannelSymbolOff), frameColor);
|
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;
|
x -= bmRadio.Width() + d;
|
||||||
osd->DrawBitmap(x, y0 + (y1 - y0 - bmRadio.Height()) / 2, bmRadio, Theme.Color(clrChannelSymbolOn), frameColor);
|
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
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#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");
|
ringBuffer = new cRingBufferLinear(TRANSFERBUFSIZE, TS_SIZE * 2, true, "Transfer");
|
||||||
remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2);
|
remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2);
|
||||||
canToggleAudioTrack = false;
|
|
||||||
audioTrack = 0xC0;
|
|
||||||
active = false;
|
active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,8 +58,41 @@ void cTransfer::Action(void)
|
|||||||
int PollTimeouts = 0;
|
int PollTimeouts = 0;
|
||||||
uchar *p = NULL;
|
uchar *p = NULL;
|
||||||
int Result = 0;
|
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;
|
active = true;
|
||||||
while (active) {
|
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;
|
int Count;
|
||||||
uchar *b = ringBuffer->Get(Count);
|
uchar *b = ringBuffer->Get(Count);
|
||||||
if (b) {
|
if (b) {
|
||||||
@ -80,13 +111,13 @@ void cTransfer::Action(void)
|
|||||||
if (Count)
|
if (Count)
|
||||||
ringBuffer->Del(Count);
|
ringBuffer->Del(Count);
|
||||||
}
|
}
|
||||||
if (!p && (p = remux->Get(Result)) != NULL)
|
if (!p)
|
||||||
StripAudioPackets(p, Result, audioTrack);
|
p = remux->Get(Result);
|
||||||
if (p) {
|
if (p) {
|
||||||
cPoller Poller;
|
cPoller Poller;
|
||||||
if (DevicePoll(Poller, 100)) {
|
if (DevicePoll(Poller, 100)) {
|
||||||
PollTimeouts = 0;
|
PollTimeouts = 0;
|
||||||
int w = PlayVideo(p, Result);
|
int w = PlayPes(p, Result);
|
||||||
if (w > 0) {
|
if (w > 0) {
|
||||||
p += w;
|
p += w;
|
||||||
Result -= w;
|
Result -= w;
|
||||||
@ -112,64 +143,6 @@ void cTransfer::Action(void)
|
|||||||
active = false;
|
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 ------------------------------------------------------
|
// --- cTransferControl ------------------------------------------------------
|
||||||
|
|
||||||
cDevice *cTransferControl::receiverDevice = NULL;
|
cDevice *cTransferControl::receiverDevice = NULL;
|
||||||
|
@ -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 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
|
#ifndef __TRANSFER_H
|
||||||
@ -20,10 +20,7 @@ class cTransfer : public cReceiver, public cPlayer, public cThread {
|
|||||||
private:
|
private:
|
||||||
cRingBufferLinear *ringBuffer;
|
cRingBufferLinear *ringBuffer;
|
||||||
cRemux *remux;
|
cRemux *remux;
|
||||||
bool canToggleAudioTrack;
|
|
||||||
uchar audioTrack;
|
|
||||||
bool active;
|
bool active;
|
||||||
void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00);
|
|
||||||
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);
|
||||||
@ -31,9 +28,6 @@ protected:
|
|||||||
public:
|
public:
|
||||||
cTransfer(int VPid, int APid1, int APid2, int DPid1, int DPid2);
|
cTransfer(int VPid, int APid1, int APid2, int DPid1, int DPid2);
|
||||||
virtual ~cTransfer();
|
virtual ~cTransfer();
|
||||||
virtual int NumAudioTracks(void) const;
|
|
||||||
virtual const char **GetAudioTracks(int *CurrentTrack = NULL) const;
|
|
||||||
virtual void SetAudioTrack(int Index);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class cTransferControl : public cControl {
|
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
|
* 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>
|
#include <getopt.h>
|
||||||
@ -532,7 +532,7 @@ int main(int argc, char *argv[])
|
|||||||
static time_t lastTime = 0;
|
static time_t lastTime = 0;
|
||||||
if (time(NULL) - lastTime > MINCHANNELWAIT) {
|
if (time(NULL) - lastTime > MINCHANNELWAIT) {
|
||||||
cChannel *Channel = Channels.GetByNumber(cDevice::CurrentChannel());
|
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...
|
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...
|
&& !(LastTimerChannel > 0 && Channels.SwitchTo(LastTimerChannel)) // ...or the one used by the last timer...
|
||||||
&& !cDevice::SwitchChannel(1) // ...or the next higher available one...
|
&& !cDevice::SwitchChannel(1) // ...or the next higher available one...
|
||||||
|
Loading…
Reference in New Issue
Block a user