diff -Nru vdr-1.5.13/remux.c vdr-1.5.13-audioindexer/remux.c --- vdr-1.5.13/remux.c 2008-01-18 19:03:28.000000000 +0100 +++ vdr-1.5.13-audioindexer/remux.c 2008-01-19 09:06:09.000000000 +0100 @@ -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 @@ 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::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 @@ 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 @@ 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 - }; + 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 br = 1000 * bitRates[mpegIndex][layerIndex][bitrate_index]; // bits/s - int sf = samplingFrequencies[mpegIndex][sampling_frequency]; + // 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 - 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 @@ 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 @@ 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 @@ 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; +} + // --- cRingBufferLinearPes -------------------------------------------------- class cRingBufferLinearPes : public cRingBufferLinear { @@ -1900,6 +2002,7 @@ { exitOnFailure = ExitOnFailure; noVideo = VPid == 0 || VPid == 1 || VPid == 0x1FFF; + audioIndexer = (noVideo ? new cAudioIndexer : NULL); numUPTerrors = 0; synced = false; skipped = 0; @@ -1943,6 +2046,18 @@ 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) @@ -2124,16 +2239,19 @@ 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) { @@ -2154,6 +2272,8 @@ void cRemux::Del(int Count) { resultBuffer->Del(Count); + if (audioIndexer && Count > 0) + audioIndexer->ProcessFrame(); } void cRemux::Clear(void) @@ -2161,6 +2281,8 @@ for (int t = 0; t < numTracks; t++) ts2pes[t]->Clear(); resultBuffer->Clear(); + if (audioIndexer) + audioIndexer->Clear(); synced = false; skipped = 0; resultSkipped = 0; diff -Nru vdr-1.5.13/remux.h vdr-1.5.13-audioindexer/remux.h --- vdr-1.5.13/remux.h 2008-01-18 19:03:28.000000000 +0100 +++ vdr-1.5.13-audioindexer/remux.h 2008-01-19 09:06:57.000000000 +0100 @@ -33,6 +33,7 @@ #define MAXTRACKS 64 class cTS2PES; +class cAudioIndexer; class cRemux { private: @@ -45,6 +46,7 @@ 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 @@ 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