diff options
| author | Klaus Schmidinger <vdr@tvdr.de> | 2004-12-17 14:55:49 +0100 | 
|---|---|---|
| committer | Klaus Schmidinger <vdr@tvdr.de> | 2004-12-17 14:55:49 +0100 | 
| commit | c77989ee70085be02dca4dc1be362801baa15ff3 (patch) | |
| tree | 03433d0f032c3657c39384108ad56a1423e9c9a6 | |
| parent | 69ecb6a4d8d7eb73bd81f690d8e153a7cc6b882e (diff) | |
| download | vdr-c77989ee70085be02dca4dc1be362801baa15ff3.tar.gz vdr-c77989ee70085be02dca4dc1be362801baa15ff3.tar.bz2 | |
Added support for AC3 replay over the DVB device
| -rw-r--r-- | CONTRIBUTORS | 2 | ||||
| -rw-r--r-- | HISTORY | 24 | ||||
| -rw-r--r-- | PLUGINS.html | 62 | ||||
| -rw-r--r-- | PLUGINS/src/sky/HISTORY | 4 | ||||
| -rw-r--r-- | PLUGINS/src/sky/sky.c | 6 | ||||
| -rw-r--r-- | channels.h | 10 | ||||
| -rw-r--r-- | device.c | 266 | ||||
| -rw-r--r-- | device.h | 136 | ||||
| -rw-r--r-- | dvbdevice.c | 78 | ||||
| -rw-r--r-- | dvbdevice.h | 17 | ||||
| -rw-r--r-- | dvbplayer.c | 87 | ||||
| -rw-r--r-- | menu.c | 15 | ||||
| -rw-r--r-- | player.c | 17 | ||||
| -rw-r--r-- | player.h | 36 | ||||
| -rw-r--r-- | skinsttng.c | 8 | ||||
| -rw-r--r-- | transfer.c | 101 | ||||
| -rw-r--r-- | transfer.h | 8 | ||||
| -rw-r--r-- | vdr.c | 4 | 
18 files changed, 517 insertions, 364 deletions
| diff --git a/CONTRIBUTORS b/CONTRIBUTORS index f6c27f9b..fb69037f 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -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 @@ -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üß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. diff --git a/PLUGINS.html b/PLUGINS.html index cfd28d12..878c3670 100644 --- a/PLUGINS.html +++ b/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> diff --git a/PLUGINS/src/sky/HISTORY b/PLUGINS/src/sky/HISTORY index 2d15da7e..490ee62b 100644 --- a/PLUGINS/src/sky/HISTORY +++ b/PLUGINS/src/sky/HISTORY @@ -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. diff --git a/PLUGINS/src/sky/sky.c b/PLUGINS/src/sky/sky.c index eea697ea..8936774e 100644 --- a/PLUGINS/src/sky/sky.c +++ b/PLUGINS/src/sky/sky.c @@ -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" @@ -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; } @@ -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; @@ -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); diff --git a/dvbdevice.c b/dvbdevice.c index 0c370c4f..ed3a710e 100644 --- a/dvbdevice.c +++ b/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 -{ -  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 +void cDvbDevice::SetDigitalAudioDevice(bool On)  { -  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) diff --git a/dvbdevice.h b/dvbdevice.h index 1817f371..e0213990 100644 --- a/dvbdevice.h +++ b/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 diff --git a/dvbplayer.c b/dvbplayer.c index 99a9aad9..aa9c04de 100644 --- a/dvbplayer.c +++ b/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) @@ -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()); @@ -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) @@ -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 { diff --git a/skinsttng.c b/skinsttng.c index f80175f8..f1f79bf5 100644 --- a/skinsttng.c +++ b/skinsttng.c @@ -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® 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);          } @@ -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 { @@ -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... | 
