Hi, Reinhard Nissl schrieb: > I'm sorry for the trouble but the patches miss a check, whether > audioIndexer exists when VDR calls cRemux::Clear(). So VDR may segfault > for non radio channels. Am I blind? audioIndexer was not initialized to NULL for non radio channels. Attached are updated patches for VDR 1.5.10 and 1.4.7. Bye. -- Dipl.-Inform. (FH) Reinhard Nissl mailto:rnissl@xxxxxx
--- ../vdr-1.5.10-orig/remux.c 2007-09-22 14:08:22.000000000 +0200 +++ remux.c 2007-10-25 21:35:02.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,7 @@ cRemux::cRemux(int VPid, const int *APid while (*SPids && numTracks < MAXTRACKS && n < MAXSPIDS) ts2pes[numTracks++] = new cTS2PES(*SPids++, resultBuffer, IPACKS, 0x00, 0x20 + n++); } + audioIndexer = (noVideo ? new cAudioIndexer : NULL); } cRemux::~cRemux() @@ -1920,6 +2023,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 +2214,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 +2247,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 +2256,8 @@ void cRemux::Clear(void) for (int t = 0; t < numTracks; t++) ts2pes[t]->Clear(); resultBuffer->Clear(); + if (audioIndexer) + audioIndexer->Clear(); synced = false; skipped = 0; resultSkipped = 0; --- ../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.4.7-orig/remux.c 2006-12-01 15:46:25.000000000 +0100 +++ remux.c 2007-10-25 21:36:15.000000000 +0200 @@ -19,6 +19,7 @@ #include "channels.h" #include "thread.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; @@ -1849,6 +1899,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) @@ -1895,6 +1997,7 @@ cRemux::cRemux(int VPid, const int *APid ts2pes[numTracks++] = new cTS2PES(*SPids++, resultBuffer, IPACKS, 0x00, 0x28 + n++); } */ + audioIndexer = (isRadio ? new cAudioIndexer : NULL); } cRemux::~cRemux() @@ -1902,6 +2005,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) @@ -2081,16 +2196,19 @@ uchar *cRemux::Get(int &Count, uchar *Pi if (l < 0) return resultData; if (isRadio) { + 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) { @@ -2111,6 +2229,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) @@ -2118,6 +2238,8 @@ void cRemux::Clear(void) for (int t = 0; t < numTracks; t++) ts2pes[t]->Clear(); resultBuffer->Clear(); + if (audioIndexer) + audioIndexer->Clear(); synced = false; skipped = 0; resultSkipped = 0; --- ../vdr-1.4.7-orig/remux.h 2006-03-25 13:27:30.000000000 +0100 +++ remux.h 2007-10-25 13:21:48.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 mailing list vdr@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr