From b313d88db13d1e90f81f9967af1fba8c8f84e59d Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 26 Mar 2017 13:07:01 +0200 Subject: [PATCH] Improved clearing the MTD buffer and syncing on TS packets --- device.c | 9 ++------- mtd.c | 23 ++++++++++++++++------- mtd.h | 4 ++-- remux.c | 22 +++++++++++++++------- remux.h | 11 ++++++++++- 5 files changed, 45 insertions(+), 24 deletions(-) diff --git a/device.c b/device.c index 6f3a155d..ccd0e20a 100644 --- a/device.c +++ b/device.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: device.c 4.9 2017/03/23 14:19:59 kls Exp $ + * $Id: device.c 4.10 2017/03/26 11:35:38 kls Exp $ */ #include "device.h" @@ -1570,13 +1570,8 @@ int cDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly) } else { while (Length >= TS_SIZE) { - if (Data[0] != TS_SYNC_BYTE) { - int Skipped = 1; - while (Skipped < Length && (Data[Skipped] != TS_SYNC_BYTE || Length - Skipped > TS_SIZE && Data[Skipped + TS_SIZE] != TS_SYNC_BYTE)) - Skipped++; - esyslog("ERROR: skipped %d bytes to sync on start of TS packet", Skipped); + if (int Skipped = TS_SYNC(Data, Length)) return Played + Skipped; - } int Pid = TsPid(Data); if (TsHasPayload(Data)) { // silently ignore TS packets w/o payload int PayloadOffset = TsPayloadOffset(Data); diff --git a/mtd.c b/mtd.c index 2fa55626..a170cbc9 100644 --- a/mtd.c +++ b/mtd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: mtd.c 1.5 2017/03/25 14:09:31 kls Exp $ + * $Id: mtd.c 1.6 2017/03/26 13:01:32 kls Exp $ */ #include "mtd.h" @@ -229,7 +229,6 @@ cMtdCamSlot::cMtdCamSlot(cCamSlot *MasterSlot, int Index) mtdBuffer = new cRingBufferLinear(MTD_BUFFER_SIZE, TS_SIZE, true, "MTD buffer"); mtdMapper = new cMtdMapper(Index + 1, MasterSlot->SlotNumber()); delivered = false; - clearBuffer = false; ciAdapter = MasterSlot->ciAdapter; // we don't pass the CI adapter in the constructor, to prevent this one from being inserted into CamSlots } @@ -279,8 +278,10 @@ void cMtdCamSlot::StopDecrypting(void) cCamSlot::StopDecrypting(); if (!MasterSlot()->IsDecrypting()) MasterSlot()->StopDecrypting(); + cMutexLock MutexLock(&mutex); mtdMapper->Clear(); - clearBuffer = true; + mtdBuffer->Clear(); + delivered = false; } uchar *cMtdCamSlot::Decrypt(uchar *Data, int &Count) @@ -297,18 +298,19 @@ uchar *cMtdCamSlot::Decrypt(uchar *Data, int &Count) else Count = 0; // Drop delivered data from previous call: + cMutexLock MutexLock(&mutex); if (delivered) { mtdBuffer->Del(TS_SIZE); delivered = false; } - if (clearBuffer) { - mtdBuffer->Clear(); - clearBuffer = false; - } // Receive data from buffer: int c = 0; uchar *d = mtdBuffer->Get(c); if (d) { + if (int Skipped = TS_SYNC(d, c)) { + mtdBuffer->Del(Skipped); + return NULL; + } if (c >= TS_SIZE) { TsSetPid(d, mtdMapper->UniqToRealPid(TsPid(d))); delivered = true; @@ -321,6 +323,13 @@ uchar *cMtdCamSlot::Decrypt(uchar *Data, int &Count) int cMtdCamSlot::PutData(const uchar *Data, int Count) { + cMutexLock MutexLock(&mutex); + int Free = mtdBuffer->Free(); + Free -= Free % TS_SIZE; + if (Free < TS_SIZE) + return 0; + if (Free < Count) + Count = Free; return mtdBuffer->Put(Data, Count); } diff --git a/mtd.h b/mtd.h index 15d29b83..ea62f426 100644 --- a/mtd.h +++ b/mtd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: mtd.h 1.4 2017/03/23 12:48:22 kls Exp $ + * $Id: mtd.h 1.5 2017/03/25 14:47:03 kls Exp $ */ #ifndef __MTD_H @@ -151,10 +151,10 @@ void MtdMapPid(uchar *p, cMtdMapper *MtdMapper); class cMtdCamSlot : public cCamSlot { private: + cMutex mutex; cMtdMapper *mtdMapper; cRingBufferLinear *mtdBuffer; bool delivered; - bool clearBuffer; protected: virtual const int *GetCaSystemIds(void); virtual void SendCaPmt(uint8_t CmdId); diff --git a/remux.c b/remux.c index cb694760..a2d2dd6c 100644 --- a/remux.c +++ b/remux.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remux.c 4.4 2017/01/09 15:05:05 kls Exp $ + * $Id: remux.c 4.5 2017/03/26 13:07:01 kls Exp $ */ #include "remux.h" @@ -144,6 +144,19 @@ void TsSetPcr(uchar *p, int64_t Pcr) } } +int TsSync(const uchar *Data, int Length, const char *File, const char *Function, int Line) +{ + int Skipped = 0; + while (Length > 0 && (*Data != TS_SYNC_BYTE || Length > TS_SIZE && Data[TS_SIZE] != TS_SYNC_BYTE)) { + Data++; + Length--; + Skipped++; + } + if (Skipped && File && Function && Line) + esyslog("ERROR: skipped %d bytes to sync on start of TS packet at %s/%s(%d)", Skipped, File, Function, Line); + return Skipped; +} + int64_t TsGetPts(const uchar *p, int l) { // Find the first packet with a PTS and use it: @@ -1557,13 +1570,8 @@ int cFrameDetector::Analyze(const uchar *Data, int Length) newFrame = independentFrame = false; while (Length >= MIN_TS_PACKETS_FOR_FRAME_DETECTOR * TS_SIZE) { // makes sure we are looking at enough data, in case the frame type is not stored in the first TS packet // Sync on TS packet borders: - if (Data[0] != TS_SYNC_BYTE) { - int Skipped = 1; - while (Skipped < Length && (Data[Skipped] != TS_SYNC_BYTE || Length - Skipped > TS_SIZE && Data[Skipped + TS_SIZE] != TS_SYNC_BYTE)) - Skipped++; - esyslog("ERROR: skipped %d bytes to sync on start of TS packet", Skipped); + if (int Skipped = TS_SYNC(Data, Length)) return Processed + Skipped; - } // Handle one TS packet: int Handled = TS_SIZE; if (TsHasPayload(Data) && !TsIsScrambled(Data)) { diff --git a/remux.h b/remux.h index 28dfde4b..7dd5b163 100644 --- a/remux.h +++ b/remux.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: remux.h 4.2 2017/02/27 16:11:57 kls Exp $ + * $Id: remux.h 4.3 2017/03/26 13:06:37 kls Exp $ */ #ifndef __REMUX_H @@ -144,6 +144,15 @@ inline int64_t TsGetPcr(const uchar *p) void TsHidePayload(uchar *p); void TsSetPcr(uchar *p, int64_t Pcr); +// Helper macro and function to quickly check whether Data points to the beginning +// of a TS packet. The return value is the number of bytes that need to be skipped +// to synchronize on the next TS packet (zero if already sync'd). TsSync() can be +// called directly, the macro just performs the initial check inline and adds some +// debug information for logging. + +#define TS_SYNC(Data, Length) (*Data == TS_SYNC_BYTE ? 0 : TsSync(Data, Length, __FILE__, __FUNCTION__, __LINE__)) +int TsSync(const uchar *Data, int Length, const char *File = NULL, const char *Function = NULL, int Line = 0); + // The following functions all take a pointer to a sequence of complete TS packets. int64_t TsGetPts(const uchar *p, int l);