[ANNOUNCE] AudioIndexer.patch for VDR-1.5.10 provides correct length for new radio recordings

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

 



Hi,

you may have noticed that radio recordings report a length which is much
larger than the actual playtime of the recording. This is a result of
VDR generating an index entry for every audio frame, but audio frames
provide most often only 24 ms of music while VDR's recording length
calculation is based on 40 ms per index entry.

The attached patch fixes cRemux to only generate an index entry whenever
the recorded amount of music crosses a 40 ms boundary.

Bye.
-- 
Dipl.-Inform. (FH) Reinhard Nissl
mailto:rnissl@xxxxxx
--- ../vdr-1.5.10-orig/remux.h	2007-09-02 12:19:06.000000000 +0200
+++ remux.h	2007-10-24 23:45:55.000000000 +0200
@@ -33,6 +33,7 @@ ePesHeader AnalyzePesHeader(const uchar 
 #define MAXTRACKS 64
 
 class cTS2PES;
+class cAudioIndexer;
 
 class cRemux {
 private:
@@ -45,6 +46,7 @@ private:
   int numTracks;
   cRingBufferLinear *resultBuffer;
   int resultSkipped;
+  cAudioIndexer *audioIndexer;
   int GetPid(const uchar *Data);
 public:
   cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false);
@@ -79,6 +81,7 @@ public:
   static void SetBrokenLink(uchar *Data, int Length);
   static int GetPacketLength(const uchar *Data, int Count, int Offset);
   static int ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType);
+  static int GetAudioFrameDuration(const uchar *Data, int Count, int *TrackIndex = NULL);
   };
 
 #endif // __REMUX_H
--- ../vdr-1.5.10-orig/remux.c	2007-09-22 14:08:22.000000000 +0200
+++ remux.c	2007-10-24 23:45:55.000000000 +0200
@@ -19,6 +19,7 @@
 #include "channels.h"
 #include "shutdown.h"
 #include "tools.h"
+#include "recording.h"
 
 ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
 {
@@ -690,12 +691,13 @@ private:
   int frameTodo;
   int frameSize;
   int cid;
-  static bool IsValidAudioHeader(uint32_t Header, bool Mpeg2, int *FrameSize = NULL);
+  static bool IsValidAudioHeader(uint32_t Header, bool Mpeg2, int *FrameSize = NULL, int *FrameDuration = NULL);
 public:
   cAudioRepacker(int Cid);
   virtual void Reset(void);
   virtual void Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count);
   virtual int BreakAt(const uchar *Data, int Count);
+  static int GetFrameDuration(const uchar *Data, int Count, int *TrackIndex = NULL);
   };
 
 int cAudioRepacker::bitRates[2][3][16] = { // all values are specified as kbits/s
@@ -711,6 +713,25 @@ int cAudioRepacker::bitRates[2][3][16] =
   }
   };
 
+int cAudioRepacker::GetFrameDuration(const uchar *Data, int Count, int *TrackIndex)
+{
+  int PesPayloadOffset = 0;
+  ePesHeader PH = AnalyzePesHeader(Data, Count, PesPayloadOffset);
+  if (PH < phMPEG1)
+     return -1;
+
+  const uchar *Payload = Data + PesPayloadOffset;
+  const int PayloadCount = Count - PesPayloadOffset;
+
+  int FrameDuration = -1;
+  if ((Data[3] & 0xE0) == 0xC0 && PayloadCount >= 4) {
+     if (IsValidAudioHeader(((Payload[0] << 8 | Payload[1]) << 8 | Payload[2]) << 8 | Payload[3], PH == phMPEG2, NULL, &FrameDuration) && TrackIndex)
+        *TrackIndex = Data[3] - 0xC0;
+     }
+
+  return FrameDuration;
+}
+
 cAudioRepacker::cAudioRepacker(int Cid)
 {
   cid = Cid;
@@ -726,7 +747,7 @@ void cAudioRepacker::Reset(void)
   frameSize = 0;
 }
 
-bool cAudioRepacker::IsValidAudioHeader(uint32_t Header, bool Mpeg2, int *FrameSize)
+bool cAudioRepacker::IsValidAudioHeader(uint32_t Header, bool Mpeg2, int *FrameSize, int *FrameDuration)
 {
   int syncword           = (Header & 0xFFF00000) >> 20;
   int id                 = (Header & 0x00080000) >> 19;
@@ -760,32 +781,36 @@ bool cAudioRepacker::IsValidAudioHeader(
   if (emphasis == 2) // reserved
      return false;
 
-  if (FrameSize) {
-     if (bitrate_index == 0)
-        *FrameSize = 0;
-     else {
-        static int samplingFrequencies[2][4] = { // all values are specified in Hz
-          { 44100, 48000, 32000, -1 }, // MPEG 1
-          { 22050, 24000, 16000, -1 }  // MPEG 2
-          };
-
-        static int slots_per_frame[2][3] = {
-          { 12, 144, 144 }, // MPEG 1, Layer I, II, III
-          { 12, 144,  72 }  // MPEG 2, Layer I, II, III
-          };
-
-        int mpegIndex = 1 - id;
-        int layerIndex = 3 - layer;
-
-        // Layer I (i. e., layerIndex == 0) has a larger slot size
-        int slotSize = (layerIndex == 0) ? 4 : 1; // bytes
-
-        int br = 1000 * bitRates[mpegIndex][layerIndex][bitrate_index]; // bits/s
-        int sf = samplingFrequencies[mpegIndex][sampling_frequency];
-
-        int N = slots_per_frame[mpegIndex][layerIndex] * br / sf; // slots
+  if (FrameSize || FrameDuration) {
+     static int samplingFrequencies[2][4] = { // all values are specified in Hz
+       { 44100, 48000, 32000, -1 }, // MPEG 1
+       { 22050, 24000, 16000, -1 }  // MPEG 2
+       };
+
+     static int slots_per_frame[2][3] = {
+       { 12, 144, 144 }, // MPEG 1, Layer I, II, III
+       { 12, 144,  72 }  // MPEG 2, Layer I, II, III
+       };
+
+     int mpegIndex = 1 - id;
+     int layerIndex = 3 - layer;
+
+     // Layer I (i. e., layerIndex == 0) has a larger slot size
+     int slotSize = (layerIndex == 0) ? 4 : 1; // bytes
+     int sf = samplingFrequencies[mpegIndex][sampling_frequency];
+
+     if (FrameDuration)
+        *FrameDuration = 90000 * 8 * slotSize * slots_per_frame[mpegIndex][layerIndex] / sf;
+
+     if (FrameSize) {
+        if (bitrate_index == 0)
+           *FrameSize = 0;
+        else {
+           int br = 1000 * bitRates[mpegIndex][layerIndex][bitrate_index]; // bits/s
+           int N = slots_per_frame[mpegIndex][layerIndex] * br / sf; // slots
 
-        *FrameSize = (N + padding_bit) * slotSize; // bytes
+           *FrameSize = (N + padding_bit) * slotSize; // bytes
+           }
         }
      }
 
@@ -1086,6 +1111,7 @@ public:
   virtual void Reset(void);
   virtual void Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count);
   virtual int BreakAt(const uchar *Data, int Count);
+  static int GetFrameDuration(const uchar *Data, int Count, int *TrackIndex = NULL);
   };
 
 // frameSizes are in words, i. e. multiply them by 2 to get bytes
@@ -1112,6 +1138,30 @@ int cDolbyRepacker::frameSizes[] = {
      0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
   };
 
+int cDolbyRepacker::GetFrameDuration(const uchar *Data, int Count, int *TrackIndex)
+{
+  int PesPayloadOffset = 0;
+  ePesHeader PH = AnalyzePesHeader(Data, Count, PesPayloadOffset);
+  if (PH < phMPEG1)
+     return -1;
+
+  const uchar *Payload = Data + PesPayloadOffset;
+  const int PayloadCount = Count - PesPayloadOffset;
+
+  if (Data[3] == 0xBD && PayloadCount >= 9 && ((Payload[0] & 0xF0) == 0x80) && Payload[4] == 0x0B && Payload[5] == 0x77 && frameSizes[Payload[8]] > 0) {
+     if (TrackIndex)
+        *TrackIndex = Payload[0] - 0x80;
+
+     static int samplingFrequencies[4] = { // all values are specified in Hz
+       48000, 44100, 32000, -1
+       };
+
+     return 90000 * 1536 / samplingFrequencies[Payload[8] >> 6];
+     }
+
+  return -1;
+}
+
 cDolbyRepacker::cDolbyRepacker(void)
 {
   pesHeader[0] = 0x00;
@@ -1869,6 +1919,58 @@ void cTS2PES::ts_to_pes(const uint8_t *B
      instant_repack(Buf + 4 + off, TS_SIZE - 4 - off);
 }
 
+// --- cAudioIndexer ---------------------------------------------------------
+
+class cAudioIndexer {
+private:
+  int frameTrack;
+  int frameDuration;
+  int64_t trackTime[MAXAPIDS + MAXDPIDS];
+  int64_t nextIndexTime;
+  
+public:
+  cAudioIndexer(void);
+  void Clear(void);
+  void PrepareFrame(const uchar *Data, int Count, int Offset, uchar &PictureType);
+  void ProcessFrame(void);
+  };
+
+cAudioIndexer::cAudioIndexer(void)
+{
+  Clear();
+}
+
+void cAudioIndexer::Clear(void)
+{
+  memset(trackTime, 0, sizeof (trackTime));
+  nextIndexTime = 0;
+  frameTrack = -1;
+}
+
+void cAudioIndexer::PrepareFrame(const uchar *Data, int Count, int Offset, uchar &PictureType)
+{
+  frameDuration = cRemux::GetAudioFrameDuration(Data + Offset, Count - Offset, &frameTrack);
+  if (frameDuration <= 0)
+     return;
+
+  if (Data[Offset + 3] == 0xBD)
+     frameTrack += MAXAPIDS;
+
+  PictureType = (trackTime[frameTrack] >= nextIndexTime) ? I_FRAME : NO_PICTURE;
+}
+
+void cAudioIndexer::ProcessFrame(void)
+{
+  if (frameTrack < 0)
+     return;
+
+  if (trackTime[frameTrack] >= nextIndexTime)
+     nextIndexTime += 90000 / FRAMESPERSEC;
+
+  trackTime[frameTrack] += frameDuration;
+  frameTrack = -1;
+}
+
 // --- cRemux ----------------------------------------------------------------
 
 #define RESULTBUFFERSIZE KILOBYTE(256)
@@ -1913,6 +2015,8 @@ cRemux::cRemux(int VPid, const int *APid
      while (*SPids && numTracks < MAXTRACKS && n < MAXSPIDS)
            ts2pes[numTracks++] = new cTS2PES(*SPids++, resultBuffer, IPACKS, 0x00, 0x20 + n++);
      }
+  if (noVideo)
+     audioIndexer = new cAudioIndexer;
 }
 
 cRemux::~cRemux()
@@ -1920,6 +2024,18 @@ cRemux::~cRemux()
   for (int t = 0; t < numTracks; t++)
       delete ts2pes[t];
   delete resultBuffer;
+  delete audioIndexer;
+}
+
+int cRemux::GetAudioFrameDuration(const uchar *Data, int Count, int *TrackIndex)
+{
+  if (Count <= 4)
+     return -1;
+
+  if (Data[3] == 0xBD)
+     return cDolbyRepacker::GetFrameDuration(Data, Count, TrackIndex);
+
+  return cAudioRepacker::GetFrameDuration(Data, Count, TrackIndex);
 }
 
 int cRemux::GetPid(const uchar *Data)
@@ -2099,16 +2215,19 @@ uchar *cRemux::Get(int &Count, uchar *Pi
                if (l < 0)
                   return resultData;
                if (noVideo) {
+                  uchar pt = NO_PICTURE;
+                  if (audioIndexer && !Count)
+                     audioIndexer->PrepareFrame(data, resultCount, i, pt); 
                   if (!synced) {
                      if (PictureType)
-                        *PictureType = I_FRAME;
+                        *PictureType = pt;
                      resultSkipped = i; // will drop everything before this position
                      synced = true;
                      }
                   else if (Count)
                      return resultData;
                   else if (PictureType)
-                     *PictureType = I_FRAME;
+                     *PictureType = pt;
                   }
                }
             if (synced) {
@@ -2129,6 +2248,8 @@ uchar *cRemux::Get(int &Count, uchar *Pi
 void cRemux::Del(int Count)
 {
   resultBuffer->Del(Count);
+  if (audioIndexer && Count > 0)
+     audioIndexer->ProcessFrame();
 }
 
 void cRemux::Clear(void)
@@ -2136,6 +2257,7 @@ void cRemux::Clear(void)
   for (int t = 0; t < numTracks; t++)
       ts2pes[t]->Clear();
   resultBuffer->Clear();
+  audioIndexer->Clear();
   synced = false;
   skipped = 0;
   resultSkipped = 0;
_______________________________________________
vdr mailing list
vdr@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr

[Index of Archives]     [Linux Media]     [Asterisk]     [DCCP]     [Netdev]     [Xorg]     [Util Linux NG]     [Xfree86]     [Big List of Linux Books]     [Fedora Users]     [Fedora Women]     [ALSA Devel]     [Linux USB]

  Powered by Linux