]> git.vomp.tv Git - vompclient-marten.git/commitdiff
New TS demuxer
authorChris Tallon <chris@vomp.tv>
Sun, 17 Dec 2006 20:09:50 +0000 (20:09 +0000)
committerChris Tallon <chris@vomp.tv>
Sun, 17 Dec 2006 20:09:50 +0000 (20:09 +0000)
15 files changed:
channel.cc
channel.h
demuxer.cc
demuxer.h
demuxerts.cc [new file with mode: 0644]
demuxerts.h [new file with mode: 0644]
objects.mk
player.cc
player.h
playerradio.cc
playerradio.h
vdr.cc
vdr.h
vfeed.cc
vvideolive.cc

index cc01b2326719024dc689c97acf9c60ddb5297051..4de723d4eda31c22e8254ba61c511af823b66997 100644 (file)
@@ -19,6 +19,7 @@
 */
 
 #include "channel.h"
+#include "vdr.h"
 
 Channel::Channel()
 {
@@ -27,10 +28,34 @@ Channel::Channel()
   name = NULL;
 
   index = -1;
+  vpid = 0;
+  numAPids = 0;
 }
 
 Channel::~Channel()
 {
   if (name) delete[] name;
   index = -1; // just in case
+
+  for(ULONG i = 0; i < numAPids; i++) delete[] apids[i].name;
+}
+
+void Channel::loadPids()
+{
+  // Clear the list if this is a reload
+  if (numAPids)
+  {
+    for(ULONG i = 0; i < numAPids; i++) delete[] apids[i].name;
+    apids.clear();
+    vpid = 0;
+    numAPids = 0;
+  }
+
+  VDR::getInstance()->getChannelPids(this); // FIXME sort out this system
+
+  Log::getInstance()->log("Channel", Log::DEBUG, "C.%lu loaded, VPid=%lu, numApids=%lu", number, vpid, numAPids);
+  for (ULONG i = 0; i < numAPids; i++)
+  {
+    Log::getInstance()->log("Channel", Log::DEBUG, "APid %lu %s", apids[i].pid, apids[i].name);
+  }
 }
index e17bdd39c151f9373e261db55bcde6ea2d27fcb2..4bb496c26151d730038ce7c8550781dbc390bbc6 100644 (file)
--- a/channel.h
+++ b/channel.h
 #define CHANNEL_H
 
 #include <stdio.h>
+#include <vector>
 
+#include "log.h"
 #include "defines.h"
 
+// A struct to hold a audio pid pair
+
+typedef struct _apid
+{
+  ULONG pid;
+  char* name;
+} apid;
+
+typedef vector<apid> APidList;
+
 class Channel
 {
   public:
     Channel();
     ~Channel();
 
+    void loadPids();
+
     ULONG number;
     ULONG type;
     char* name;
 
     int index;
+
+    ULONG vpid;
+    ULONG numAPids;
+    APidList apids;
 };
 
 #endif
index dbdf0095dd1ede88042820307f39a41416fe931b..a503387e9088b0978e3dab02cc1ed1ec32ff8de5 100644 (file)
@@ -179,6 +179,11 @@ void Demuxer::PESPacket::init(UCHAR type)
   seq_header = false;
 }
 
+void Demuxer::PESPacket::truncate()
+{
+  init(packetType);
+}
+
 int Demuxer::PESPacket::write(UCHAR *buf, int len)
 {
   if (closed) return 0;
index 5cd081973451f2625cf1efe8253b9d266297067f..0baa8154eb9539611d937a3a8a6e2fc8318a398c 100644 (file)
--- a/demuxer.h
+++ b/demuxer.h
@@ -48,6 +48,7 @@ protected:
     public:
       PESPacket();
       void init(UCHAR type);
+      void truncate();
       int  write(UCHAR* buf, int len);
       int  submit();
     protected:
diff --git a/demuxerts.cc b/demuxerts.cc
new file mode 100644 (file)
index 0000000..b4bcd2a
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+    Copyright 2006 Mark Calderbank
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "demuxerts.h"
+
+DemuxerTS::DemuxerTS(int p_vID = 0, int p_aID = 0)
+{
+  vID = p_vID;
+  aID = p_aID;
+}
+
+void DemuxerTS::flush()
+{
+  partPacket = 0;
+  Demuxer::flush();
+  vPacket.init(0xE0);
+  aPacket.init(0xC0);
+}
+
+int DemuxerTS::scan(UCHAR *buf, int len)
+{
+  // Temporarily, just look for the lowest audio stream and return it
+
+  UINT LoPattern = 0x100 | PESTYPE_AUD0,
+       HiPattern = 0x100 | PESTYPE_AUDMAX;
+  int ret = 0;
+
+  while (len >= 4)
+  {
+    UINT pattern = *(UINT*)buf;
+    buf++; len--;
+
+    if (pattern < LoPattern || pattern > HiPattern) continue;
+    ret = pattern & 0xFF;
+    HiPattern = pattern;
+    if (HiPattern == LoPattern) break;
+  }
+  return ret;
+}
+
+void DemuxerTS::setVID(int p_vID)
+{
+  vID = p_vID;
+}
+
+void DemuxerTS::setAID(int p_aID)
+{
+  aID = p_aID;
+}
+
+int DemuxerTS::findPTS(UCHAR* buf, int len, ULLONG* dest)
+{
+  UINT LoPattern = 0x100 | PESTYPE_VID0,
+       HiPattern = 0x100 | PESTYPE_VIDMAX;
+
+  while (len >= 14)
+  {
+    UINT pattern = *(UINT*)buf;
+    buf++; len--;
+    if (pattern < LoPattern || pattern > HiPattern) continue;
+
+    UINT framelength = ((UINT)buf[3] << 8) | buf[4];
+    buf += 5; len -= 5;
+
+    if ( buf[1] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
+    {
+      *dest = ( (ULLONG)(buf[3] & 0x0E) << 29 ) |
+              ( (ULLONG)(buf[4])        << 22 ) |
+              ( (ULLONG)(buf[5] & 0xFE) << 14 ) |
+              ( (ULLONG)(buf[6])        <<  7 ) |
+              ( (ULLONG)(buf[7] & 0xFE) >>  1 );
+      return 1;
+    }
+
+    buf += framelength; len -= framelength;
+  }
+  // No PTS found.
+  return 0;
+}
+
+int DemuxerTS::put(UCHAR* buf, int len)
+{
+  int ret = 0;    // return number of bytes consumed
+
+  while (partPacket)
+  {
+    if (len >= TS_SIZE + 1 - partPacket)
+    { // Remainder of partial packet is available, plus one
+      memcpy(store+partPacket, buf, TS_SIZE - partPacket);
+      ret += TS_SIZE - partPacket;
+      buf += TS_SIZE - partPacket;
+      len -= TS_SIZE - partPacket;
+      partPacket = TS_SIZE;
+      if (*buf == TS_SIG)
+      { // Packet is properly terminated
+        int rc = processTS(store);
+        if (rc)
+          partPacket = 0; // Successfully processed
+        else
+          return ret;     // Try again later.
+      }
+      else
+      { // Packet not terminated. Find another candidate, and shift store
+        Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!");
+        int search = 1;
+        while (search < partPacket && store[search] != TS_SIG)
+          search++;
+        partPacket -= search;
+        if (partPacket) memcpy(store, store+search, partPacket);
+      }
+    }
+    else
+    { // Still don't have complete packet. Consume what we do have.
+      memcpy(store+partPacket, buf, len);
+      partPacket += len;
+      ret += len;
+      return ret;
+    }
+  }
+
+  // Position ourselves at a candidate TS packet
+  while (*buf != TS_SIG && len)
+  {
+    Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!");
+    buf++; ret++; len--;
+  }
+
+  while (len)
+  {
+    if (len < TS_SIZE + 1)
+    { // Not enough data. Store what we have.
+      memcpy(store, buf, len);
+      partPacket = len;
+      ret += len;
+      return ret;
+    }
+
+    if (buf[TS_SIZE] != TS_SIG)
+    { // Not terminated correctly.
+      while (*buf != TS_SIG && len)
+      {
+        buf++; ret++; len--;
+      }
+    }
+    else
+    {
+      int rc = processTS(buf);
+      if (rc)
+      { // Successfully processed
+        buf += TS_SIZE; ret += TS_SIZE; len -= TS_SIZE;
+      }
+      else
+      { // Processing failed.
+        return ret;
+      }
+    }
+  }
+  return ret;
+}
+
+int DemuxerTS::processTS(UCHAR* buf)
+{
+  int datalen = TS_SIZE - 4;
+  int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];
+  UCHAR payload = buf[1] & 0x40;
+
+  if (buf[3] & 0x20) // Adaptation field is present
+    datalen -= (buf[4] + 1);
+  if (datalen < 0) // Error in stream TODO log this
+    return 1;
+  if (datalen == 0) // Null packet
+    return 1;
+  buf += (TS_SIZE - datalen);
+
+  if (payload)
+  {
+    int rc = 1;
+
+    if (pid == vID) rc = vPacket.submit();
+    if (pid == aID) rc = aPacket.submit();
+    if (rc == 0) return 0;
+
+    if (pid == vID)
+    {
+      vPacket.init(0xE0);
+      buf += 6; datalen -= 6;
+    }
+    if (pid == aID)
+    {
+      aPacket.init(0xC0);
+      buf += 6; datalen -= 6;
+    }
+//    int pesID = -1;
+//    if (datalen >= 4) pesID = buf[3];
+//    switch (pesID)
+//    {
+//    case PESTYPE_VID0 ... PESTYPE_VIDMAX:
+//      if (video_current == -1) video_current = pesID;
+//      if (video_current == pesID)
+//      {
+//        vPID = pid;
+//        vPacket.init(pesID);
+//        buf += 6; datalen -= 6;
+//      }
+//      break;
+//    case PESTYPE_AUD0 ... PESTYPE_AUDMAX:
+//      if (audio_current == -1) audio_current = pesID;
+//      if (audio_current == pesID)
+//      {
+//        aPID = pid;
+//        aPacket.init(pesID);
+//        buf += 6; datalen -= 6;
+//      }
+//      break;
+//    }
+  }
+
+  PESPacket* packet = NULL;
+  if (pid == vID) packet = &vPacket;
+  if (pid == aID) packet = &aPacket;
+  if (packet != NULL)
+  {
+    if (packet->write(buf, datalen) == 0)
+    { // Writing to packet failed. It has overflowed.
+      Log::getInstance()->log("TS Demuxer", Log::DEBUG, "Packet overflow, pid %d", pid);
+      if (packet->submit() == 0)
+        return 0;
+      packet->truncate();
+      packet->write((UCHAR*)"\200\000\000", 3);
+      packet->write(buf, datalen);
+    }
+  }
+
+  return 1;
+}
diff --git a/demuxerts.h b/demuxerts.h
new file mode 100644 (file)
index 0000000..0303917
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+    Copyright 2006 Mark Calderbank
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef DEMUXERTS_H
+#define DEMUXERTS_H
+
+#include "demuxer.h"
+#include "defines.h"
+
+#define TS_SIZE 188
+#define TS_SIG  0x47
+
+class DemuxerTS : public Demuxer
+{
+  public:
+    DemuxerTS(int p_vID = 0, int p_aID = 0);
+    void flush();
+    int scan(UCHAR* buf, int len);
+    int findPTS(UCHAR* buf, int len, ULLONG* dest);
+    void setVID(int p_vID);
+    void setAID(int p_aID);
+    int put(UCHAR* buf, int len);
+
+  private:
+    int processTS(UCHAR* buf);
+
+    UCHAR store[TS_SIZE]; // Storage for partial packets
+    int partPacket;    // Length of partial packet stored from previous put()
+    PESPacket vPacket; // Video PES packet under construction
+    PESPacket aPacket; // Audio PES packet under construction
+    int vID, aID;      // TS IDs for video/audio
+};
+
+#endif
index 039988ecb818a11f1239ffb4d77e117e33d0234c..08cf8f809c1d6c8965b06181ce047c14c3d2a5d2 100644 (file)
@@ -3,15 +3,15 @@ OBJECTS1 = command.o log.o tcp.o dsock.o thread.o timers.o i18n.o mutex.o     \
            vdr.o recman.o recording.o recinfo.o channel.o rectimer.o event.o  \\r
            directory.o mark.o                                                 \\r
            player.o playerradio.o vfeed.o afeed.o                             \\r
-           demuxer.o demuxervdr.o stream.o draintarget.o                      \\r
+           demuxer.o demuxervdr.o demuxerts.o stream.o draintarget.o          \\r
            viewman.o box.o region.o colour.o view.o                           \\r
            vinfo.o vquestion.o vwallpaper.o vrecordinglist.o vlivebanner.o    \\r
-                                        vmute.o vvolume.o voptions.o                                       \\r
+           vmute.o vvolume.o voptions.o                                       \\r
            vtimerlist.o vtimeredit.o voptionsmenu.o vrecordingmenu.o          \\r
            vchannellist.o vwelcome.o vvideolive.o vvideorec.o vepgsettimer.o  \\r
            vchannelselect.o vserverselect.o vconnect.o vepg.o vrecmove.o      \\r
            vradiorec.o vaudioselector.o                                       \\r
            widget.o wselectlist.o wjpeg.o wsymbol.o wbutton.o                 \\r
-                                        woptionbox.o wtextbox.o wwss.o                                     \\r
+           woptionbox.o wtextbox.o wwss.o                                     \\r
            fonts/helvB24.o fonts/helvB18.o                                    \\r
            remote.o led.o mtd.o video.o audio.o osd.o surface.o\r
index e613ca25c16608e112c633510e15c03a31e13a33..20ed763e69db7ef34f2b7b10caeb3570d48e7007 100644 (file)
--- a/player.cc
+++ b/player.cc
@@ -64,7 +64,10 @@ int Player::init()
   mutex=CreateMutex(NULL,FALSE,NULL);
 #endif
 
-  demuxer = new DemuxerVDR();
+  if (isRecording)
+    demuxer = new DemuxerVDR();
+  else
+    demuxer = new DemuxerTS();
   if (!demuxer) return 0;
 
   if (!demuxer->init(this, audio, video, 2097152, 524288))
@@ -157,11 +160,21 @@ void Player::setAudioChannel(int newChannel)
 
 // ----------------------------------- Externally called events
 
+void Player::play(ULONG Vpid, ULONG Apid)
+{
+  // TS mode
+  DemuxerTS* dts = (DemuxerTS*)demuxer;
+  dts->setVID(Vpid);
+  dts->setAID(Apid);
+  play();
+}
+
 void Player::play()
 {
   if (!initted) return;
   if (state == S_PLAY) return;
   lock();
+
   bool doUnlock = false;
   if (state == S_PAUSE_P) doUnlock = true;
   switchState(S_PLAY);
@@ -901,8 +914,11 @@ void Player::threadFeedLive()
       thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
       writeLength += thisWrite;
 
+//      logger->log("Player", Log::DEBUG, "Player put %u to demuxer", thisWrite);
+
       if (!thisWrite)
       {
+//        logger->log("Player", Log::DEBUG, "Demuxer full");
         // demuxer is full and can't take anymore
         threadLock();
         threadWaitForSignal();
index 2731d377183000afd4ea8801b4a54e29bbe98ffe..c76eece3af5abbee37fb2776168e3a310f934f07 100644 (file)
--- a/player.h
+++ b/player.h
@@ -31,6 +31,7 @@
 #include "audio.h"
 #include "video.h"
 #include "demuxervdr.h"
+#include "demuxerts.h"
 #include "vfeed.h"
 #include "afeed.h"
 #include "remote.h"
@@ -58,7 +59,8 @@ class Player : public Thread_TYPE, public Callback
     void setLengthFrames(ULONG length);
     void setAudioChannel(int newChannel);
 
-    void play();
+    void play();                         // Recording
+    void play(ULONG vpid, ULONG apid);   // Live TV
     void stop();
     void pause();
     void fastForward();
index 7b88c8710145b54eaf8821d03bc0e2ba67192cdd..dfe79cf9bf00e9c8ce155761f2fa4eec1b72e14a 100644 (file)
@@ -64,7 +64,10 @@ int PlayerRadio::init(ULLONG tlengthBytes, ULONG tlengthPackets)
   mutex=CreateMutex(NULL,FALSE,NULL);
 #endif
 
-  demuxer = new DemuxerVDR();
+  if (isRecording)
+    demuxer = new DemuxerVDR();
+  else
+    demuxer = new DemuxerTS();
   if (!demuxer) return 0;
 
   if (!demuxer->init(this, audio, NULL, 0, 40000))
@@ -190,6 +193,14 @@ ULONG PlayerRadio::getCurrentSeconds()
 
 // ----------------------------------- Externally called events
 
+void PlayerRadio::play(ULONG Apid)
+{
+  // TS mode
+  DemuxerTS* dts = (DemuxerTS*)demuxer;
+  dts->setAID(Apid);
+  play();
+}
+
 void PlayerRadio::play()
 {
   if (!initted) return;
index f70ec1877cb34ce20be5fbd8ce0ede3185d538f2..ea6ac125893d78f3db59a2c177726e67fc9eceec 100644 (file)
@@ -31,6 +31,7 @@
 #include "audio.h"
 #include "video.h"
 #include "demuxervdr.h"
+#include "demuxerts.h"
 #include "afeed.h"
 #include "remote.h"
 #include "vdr.h"
@@ -55,6 +56,7 @@ class PlayerRadio : public Thread_TYPE, public Callback
     void setStartBytes(ULLONG startBytes);
 
     void play();
+    void play(ULONG apid);               // Live radio
     void stop();
     void pause();
     void jumpToPercent(int percent);
diff --git a/vdr.cc b/vdr.cc
index b98c9fc022a63042adff3af23c8933879260517a..b0934f59aa43f0847ce0ed11a28c3c83a3eecaff 100644 (file)
--- a/vdr.cc
+++ b/vdr.cc
@@ -1187,3 +1187,54 @@ MarkList* VDR::getMarks(char* fileName)
 
   return markList;
 }
+
+void VDR::getChannelPids(Channel* channel)
+{
+  UCHAR buffer[12];
+
+  *(unsigned long*)&buffer[0] = htonl(8);
+  *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELPIDS);
+  *(unsigned long*)&buffer[8] = htonl(channel->number);
+
+  MUTEX_LOCK(&mutex);
+  if (!connected) { MUTEX_UNLOCK(&mutex); return ; }
+
+  int a = tcp->sendPacket(buffer, 12);
+
+  if (a != 12)
+  {
+    disconnect();
+    MUTEX_UNLOCK(&mutex);
+    return ;
+  }
+
+  if (!getPacket())
+  {
+    MUTEX_UNLOCK(&mutex);
+    return ;
+  }
+
+  // Format of response
+  // vpid
+  // number of apids
+  // {
+  //    apid
+  //    lang string
+  // }
+
+  channel->vpid = extractULONG();
+  channel->numAPids = extractULONG();
+
+  for (ULONG i = 0; i < channel->numAPids; i++)
+  {
+    apid newapid;
+    newapid.pid = extractULONG();
+    newapid.name = extractString();
+    channel->apids.push_back(newapid);
+  }
+
+  freePacket();
+  MUTEX_UNLOCK(&mutex);
+
+  return ;
+}
diff --git a/vdr.h b/vdr.h
index bb1a16e58365c1ecb26037ceaeebb4eb7babe1e8..4e0e64ce67aa89a5e283f9e81136a357d017578a 100644 (file)
--- a/vdr.h
+++ b/vdr.h
@@ -126,6 +126,7 @@ class VDR
 
     ChannelList* getChannelsList(ULONG type);
     int          streamChannel(ULONG number);
+    void         getChannelPids(Channel* channel);
 
     UCHAR*     getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived);
     int        stopStreaming();
@@ -189,6 +190,7 @@ class VDR
     const static ULONG VDR_GETNEXTIFRAME       = 19;
     const static ULONG VDR_GETRECINFO          = 20;
     const static ULONG VDR_GETMARKS            = 21;
+    const static ULONG VDR_GETCHANNELPIDS      = 22;
 
     int  getPacket();
     void freePacket();
index a7a885f1dffd6c434fbebd012a2f373a806c964c..c73bd64f1193705bbc1e3fd44856d041086db270 100644 (file)
--- a/vfeed.cc
+++ b/vfeed.cc
@@ -64,7 +64,6 @@ void VFeed::threadMethod()
 
     if (vlen)
     {
- //     Log::getInstance()->log("VFeed", Log::DEBUG, "Written %i", vlen);
       cb.call(this);
     }
     else
index e477a859d9312ef5c8066068bf4b13011fd1df9e..2d5c05d1e309d59124e248d9eec5d94cd335280c 100644 (file)
@@ -392,13 +392,19 @@ void VVideoLive::play(int noShowVLB)
   {
     if (!noShowVLB) doBanner(false);
 
+    // FIXME - change this streamType thingy to the new system using getPids
+    // FIXME - upgrade PlayerRadio to new getPids
+
+    Channel* toPlay = (*chanList)[currentChannel];
+    toPlay->loadPids();
+
     if (streamType == VDR::RADIO)
     {
-      ((PlayerRadio*)player)->play();
+      ((PlayerRadio*)player)->play(toPlay->apids[0].pid);
     }
     else
     {
-      ((Player*)player)->play();
+      ((Player*)player)->play(toPlay->vpid, toPlay->apids[0].pid);
     }
   }
 }