Mailing List archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[vdr] AC3 over DVB-s is possible - Part2



Hello,

as I promised last week,
now the patch for AC-3 over Digital Output (SPDIF) of DVB-s is reality
(recordings and DVD playback).
Of course if the recording doesn't include any AC-3 data the SDPIF
output will be operate like before (raw PCM).

It's time to through away the soundcard and forget the -a switch.
Nevertheless I'll modified very carefully the code and minimized the
patch effort. Therefore all previous AC-3 playmodes (-a switch) should
also operate like before

How does it work ?
The secret is the IEC 61937 paper which desribes the wrapping of AC-3,
MP3, DTS, ... into raw 16 bit PCM data area. Finally the wonderful LPCM
transport feature of the DVB driver was the key to realise it.

The patch is related to Klaus's latest update (vdr-0.99) to get a chance
to be integrated if the test phase should be successfully. Since two
days I've check it by myself with different AC3 recordings and DVD's. Up
to now all start/stop actions seems to be right, no AC-3 dropouts seems
to be happened. Please test it also very stressfully.

Enabling the feature:

Please compile VDR with the switch AC3=1 (in addition with your
favourite switches), that's all. Afterwards all AC-3 information will be
tranported over the digital output. (before make clean!!)
On the other side without this switch the situation is like before (only
PCM over digital output).
Unfortunatly I can't use a free web space for storing the patch.
Therefore I've include the files -((((
If it makes to much effort to extract the patches perhaps anybody could
help me by serving this.

You have to modify following files:

1../VDR/dvbapi.c -> dvbapi.diff
2. /VDR/Makefile -> Makefile1.diff
3. /VDR/ac3dec/decode.c -> decode.diff
4./VDR/ac3dec/Makefile -> Makefile2.diff

(call "patch -p1 original diff-file")

1111111111111 -> dvbapi.diff
snip----------------------------------snip

--- ./VDR_ref/VDR/dvbapi.c Sat Feb  2 14:04:00 2002
+++ ./VDR_patch/dvbapi.c Mon Feb 18 21:02:34 2002
@@ -689,6 +689,26 @@
   return i;
 }

+
+// all class defines should moved to dvbapi.h !!!!!!!!!!!!!!!!!!
+// --- cAC3toPCM
-------------------------------------------------------------
+#define PCM_FRAME_SIZE 1536
+
+class cAC3toPCM {
+private:
+  enum { AC3_STOP, AC3_START, AC3_PLAY } ac3stat;
+  uchar *ac3data;
+  int ac3inp;
+  int ac3outp;
+public:
+  cAC3toPCM(void);
+  ~cAC3toPCM();
+  void Clear(void);
+  void Put(unsigned char *sector, int length);
+  cFrame *Get(int size, uchar PTSflags = 0, uchar *PTSdata = 0);
+  };
+
+
 // --- cPlayBuffer
---------------------------------------------------------

 #define MAX_VIDEO_SLOWMOTION 63 // max. arg to pass to VIDEO_SLOWMOTION
// TODO is this value correct?
@@ -696,6 +716,7 @@
 class cPlayBuffer : public cRingBufferFrame {
 private:
   cBackTrace backTrace;
+  cAC3toPCM AC3toPCM;
 protected:
   enum ePlayModes { pmPlay, pmPause, pmSlow, pmFast, pmStill };
   enum ePlayDirs { pdForward, pdBackward };
@@ -719,6 +740,7 @@
   virtual void Output(void);
   void putFrame(cFrame *Frame);
   void putFrame(unsigned char *Data, int Length, eFrameType Type =
ftUnknown);
+  void ExtractAC3Stream(uchar *data, int length, int index);
 public:
   cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev);
   virtual ~cPlayBuffer();
@@ -733,7 +755,8 @@
   bool GetReplayMode(bool &Play, bool &Forward, int &Speed);
   bool CanToggleAudioTrack(void) { return canToggleAudioTrack; };
   virtual void ToggleAudioTrack(void);
-  };
+  bool IsAC3Stream;
+ };

 #define NORMAL_SPEED  4 // the index of the '1' entry in the following
array
 #define MAX_SPEEDS    3 // the offset of the maximum speed from normal
speed in either direction
@@ -754,7 +777,8 @@
   canDoTrickMode = false;
   canToggleAudioTrack = false;
   skipAC3bytes = false;
-  audioTrack = 0xC0;
+  audioTrack = 0xC0;
+  IsAC3Stream = false;
   if (cDvbApi::AudioCommand()) {
      if (!dolbyDev.Open(cDvbApi::AudioCommand(), "w"))
         esyslog(LOG_ERR, "ERROR: can't open pipe to audio command
'%s'", cDvbApi::AudioCommand());
@@ -764,6 +788,49 @@
 cPlayBuffer::~cPlayBuffer()
 {
 }
+
+void cPlayBuffer::ExtractAC3Stream(uchar *data, int length, int index)
+{
+ // search for AC3 data
+ for (int i=0; i < length - 6; i++) {
+  if (data[i] == 0x00 && data[i+1] == 0x00 && data[i+2] == 0x01) {
+   int l = data[i+4] * 256 + data[i+5] + 6; // total length of PES unit

+
+   if (data[i+3] == 0xBD) { //private stream 1
+    // extract if PTS info
+    uchar PTSflags = data[i+7] >> 6;
+    uchar *PTSdata = &data[i+9];
+    int PTSlength = data[i+8];
+
+    //skip to raw AC3 data
+    int written = PTSlength + 9;
+    int n = min(l-written, length-i);
+    //printf("\nAC3toPCM.Put: %d",n);
+    AC3toPCM.Put(&data[written+i], n);
+    IsAC3Stream = true;
+
+    cFrame *frame;
+    if (ac3_buffersize() <= 100) {
+     if ((frame = AC3toPCM.Get(PCM_FRAME_SIZE, PTSflags, PTSdata)) !=
NULL) {
+      //printf("\nAC3toPCM.Get 1: %d", frame->Count());
+      cFrame *outFrame = new cFrame (frame->Data(), frame->Count(),
ftUnknown, index);
+      putFrame(outFrame);
+      delete frame;
+     }
+    }
+    while ((frame = AC3toPCM.Get(PCM_FRAME_SIZE))  != NULL) {
+     //printf("\nAC3toPCM.Get 2: %d",frame->Count());
+     cFrame *outFrame = new cFrame (frame->Data(), frame->Count(),
ftUnknown, index);
+     putFrame(outFrame);
+     delete frame;
+    }
+   }
+   if (l)
+    i += l - 1;
+  }
+ }
+}
+

 void cPlayBuffer::PlayExternalDolby(const uchar *b, int MaxLength)
 {
@@ -801,8 +868,8 @@
         if (frame) {
            if (frame->Type() == ftDolby)
               PlayExternalDolby(frame->Data(), frame->Count());
-           else {
-              StripAudioPackets((uchar *)frame->Data(), frame->Count(),
(playMode == pmFast || playMode == pmSlow) ? 0x00 : audioTrack);//XXX
+     else {
+     StripAudioPackets((uchar *)frame->Data(), frame->Count(),
(playMode == pmFast || playMode == pmSlow) ? 0x00 : audioTrack);//XXX
               const uchar *p = frame->Data();
               int r = frame->Count();
               while (r > 0 && Busy() && !blockOutput) {
@@ -1134,9 +1201,15 @@
               }
            else // allows replay even if the index file is missing
               r = read(replayFile, b, sizeof(b));
-           if (r > 0)
-              putFrame(new cFrame(b, r, ftUnknown, readIndex));
-           else if (r == 0)
+   if (r > 0) {
+#ifdef AC3OUT
+    // analys each PES stream for private stream1 == AC3 and wrap AC3
into LPCM format for Digital output
+    ExtractAC3Stream(b,r, readIndex);
+#endif
+    putFrame(new cFrame(b, r, ftUnknown, readIndex));
+   }
+
+     else if (r == 0)
               eof = true;
            else if (r < 0 && FATALERRNO) {
               LOG_ERROR;
@@ -1157,20 +1230,31 @@
          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;
+   // check if there is a LPCM feature (AC3 embedded)
+   int header = b[i+8] + 9;
+   //analyse LPCM substream ID
+   bool LPCMsubID = (c == 0xBD) && (b[i+header] == aLPCM) &&
(b[i+header+1] == 0x00) && (b[i+header+2] == 0x00)
+    && (b[i+header+3] == 0x00) && (b[i+header+4] == 0x00) &&
(b[i+header+5] == 0x00) && (b[i+header+6] == 0x00);
+   //printf("\nStrip Audio: 0x%x, LPCMsubID: %d, Except: 0x%x,
IsAC3Stream: %d",c,LPCMsubID,Except, IsAC3Stream);
+
+   if (IsAC3Stream)
+    Except = 0xff; // in case of LPCM clear all additional audio
streams !!!
+
             switch (c) {
               case 0xBD: // dolby
-                   if (Except && dolbyDev)
+                   if (Except && dolbyDev && !LPCMsubID)
                       PlayExternalDolby(&b[i], Length - i);
                    // continue with deleting the data - otherwise it
disturbs DVB replay
               case 0xC0 ... 0xC1: // audio
                    if (c == 0xC1)
                       canToggleAudioTrack = true;
-                   if (!Except || c != Except) {
-                      int n = l;
-                      for (int j = i; j < Length && n--; j++)
-                          b[j] = 0x00;
-                      }
-                   break;
+                   if (!Except || (c != Except && !LPCMsubID)){
+      //printf("\nClear Audio: %x, LPCMsubID: %d",c,LPCMsubID);
+      int n = l;
+      for (int j = i; j < Length && n--; j++)
+       b[j] = 0x00;
+     }
+     break;
               case 0xE0 ... 0xEF: // video
                    break;
               default:
@@ -1351,20 +1435,6 @@

 // --- cAC3toPCM
-------------------------------------------------------------

-class cAC3toPCM {
-private:
-  enum { AC3_STOP, AC3_START, AC3_PLAY } ac3stat;
-  uchar *ac3data;
-  int ac3inp;
-  int ac3outp;
-public:
-  cAC3toPCM(void);
-  ~cAC3toPCM();
-  void Clear(void);
-  void Put(unsigned char *sector, int length);
-  cFrame *Get(int size, uchar PTSflags = 0, uchar *PTSdata = 0);
-  };
-
 cAC3toPCM::cAC3toPCM(void)
 {
   ac3dec_init();
@@ -2001,7 +2071,6 @@

 void cDVDplayBuffer::handleAC3(unsigned char *sector, int length, uchar
PTSflags, uchar *PTSdata)
 {
-#define PCM_FRAME_SIZE 1536
   AC3toPCM.Put(sector, length);
   cFrame *frame;
   if (ac3_buffersize() <= 100) {

snip----------------------------------snip
END END END END END END END


222222222222222 -> Makefile1.diff
snip----------------------------------snip

--- ./VDR_ref/VDR/Makefile Fri Feb  1 15:40:09 2002
+++ ./VDR_patch/Makefile Sun Feb 17 16:13:28 2002
@@ -26,6 +26,12 @@
 DVDLIB    = -ldvdread
 endif

+ifdef AC3
+DEFINES += -DAC3OUT
+DEFINES_AC3 = AC3=1
+endif
+
+
 OBJS = config.o dvbapi.o dvbosd.o dvd.o eit.o font.o i18n.o interface.o
menu.o osd.o\
        recording.o remote.o remux.o ringbuffer.o svdrp.o thread.o
tools.o vdr.o\
        videodir.o
@@ -93,7 +99,7 @@
 # The ac3dec library:

 $(AC3LIB):
- make -C $(AC3DIR) all
+ make -C $(AC3DIR) $(DEFINES_AC3) all

 # The libdtv library:

snip----------------------------------snip
END END END END END END END



33333333333333 -> decode.diff
snip----------------------------------snip

--- ./VDR_ref/VDR/ac3dec/decode.c Sat Nov 24 15:41:56 2001
+++ ./VDR_patch/ac3dec/decode.c Mon Feb 18 21:05:53 2002
@@ -208,6 +208,27 @@

  while (decode_buffer_syncframe (&syncinfo, &data_start, data_end)) {
   parse_bsi (&bsi);
+
+#ifdef AC3OUT
+  data = (uint8_t *)s16_samples;
+  datasize = 0;
+
+  // prepare IEC 60958 data frame
+  memset(data, 0, 6144); // clear all buffer -- need to get payload
burst gap
+  data[0] = 0xf8;      // Pa1:sync
+  data[1] = 0x72;      // Pa2:sync
+  data[2] = 0x4e;      // Pb1:sync
+  data[3] = 0x1f;      // Pb2:sync
+  data[4] = 0x00 | bsi.bsmod;   // Pc1
+  data[5] = 0x01;      // Pc2 AC3 bitstream
+  data[6] = ((syncinfo.frame_size*16) >> 8 ) & 0xff;  // Pd1
+  data[7] = (syncinfo.frame_size*16) & 0xff;   // Pd2
+  data[8] = 0xb;       // AC-3 sync1
+  data[9] = 0x77;      // AC-3 sync2
+
+  // copy rest of AC-3 bitstream
+  memcpy(&data[10],&buffer[0], (syncinfo.frame_size*2)-2);
+#else

 #ifndef __OMS__
   if(!done_banner) {
@@ -283,6 +304,8 @@
 #endif
    is_output_initialized = 1;
   }
+
+#endif // AC3OUT

 #ifdef __OMS__
   output->write (s16_samples, 256 * 6 * 2 * 2);
@@ -292,8 +315,12 @@
   datasize = 0;
   while(datasize < 6144){
     if(((*input_pointer+1) % AC3_BUFFER_SIZE) != *output_pointer){
// There is room in the sync_buffer
-      ac3_data[*input_pointer]=data[datasize];
-      datasize++;
+#ifdef AC3OUT
+     ac3_data[*input_pointer ^ 1]=data[datasize]; // changed byte order
to be compatible to <dvpapi.c> parts
+#else
+     ac3_data[*input_pointer]=data[datasize];
+#endif
+     datasize++;
       *input_pointer = (*input_pointer+1) % AC3_BUFFER_SIZE;
     }
     else{

snip----------------------------------snip
END END END END END END END



444444444444 -> Makefile2.diff
snip----------------------------------snip

--- ./VDR_ref/VDR/ac3dec/Makefile Fri Aug 10 14:44:07 2001
+++ ./VDR_patch/ac3dec/Makefile Sun Feb 17 16:13:52 2002
@@ -12,6 +12,10 @@
        parse.o rematrix.o sanity_check.o srfft.o srfft_kni_c.o stats.o


+ifdef AC3
+DEFINES += -DAC3OUT
+endif
+
 DEFINES += -DDOLBY_SURROUND

 all: libac3.a

snip----------------------------------snip
END END END END END END END


Enjoy the liberty of digital music
Wolfi





Home | Main Index | Thread Index