MythTV  master
pespacket.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 // Copyright (c) 2003-2004, Daniel Thor Kristjansson
5 #include "pespacket.h"
6 #include "mpegtables.h"
7 
8 extern "C" {
9 #include "libmythbase/mythconfig.h"
10 #include "libavcodec/avcodec.h"
11 #include "libavformat/avformat.h"
12 #include "libavutil/crc.h"
13 #include "libavutil/bswap.h"
14 }
15 
16 #include <vector>
17 #include <map>
18 
19 // return true if complete or broken
20 bool PESPacket::AddTSPacket(const TSPacket* packet, int cardid, bool &broken)
21 {
22  broken = true;
23  if (!tsheader()->PayloadStart())
24  {
25  LOG(VB_RECORD, LOG_ERR,
26  "Error: We started a PES packet, without a payloadStart!");
27  return true;
28  }
29  if (!IsClone())
30  {
31  LOG(VB_RECORD, LOG_ERR,
32  "Error: Must clone initially to use addPackets()");
33  return false;
34  }
35 
36  const int cc = packet->ContinuityCounter();
37  const int ccExp = (m_ccLast + 1) & 0xf;
38  uint payloadSize = TSPacket::kPayloadSize;
39  uint payloadStart = TSPacket::kHeaderSize;
40 
41  // If the next TS has an offset, we need to strip it out.
42  // The offset will be used when a new PESPacket is created.
43  if (packet->PayloadStart())
44  {
45  payloadSize--;
46  payloadStart++;
47  }
48  else
49  {
50  // Skip past the adaptation field if present
51  if (packet->HasAdaptationField())
52  {
53  uint delta = packet->AdaptationFieldSize() + 1;
54 
55  // Adaptation field size is max 182 (control is '11') or 183 (control is '10').
56  // Do not skip beyond end of packet when the adaptation field size is wrong.
57  if (delta > TSPacket::kPayloadSize)
58  {
59  delta = TSPacket::kPayloadSize;
60  LOG(VB_GENERAL, LOG_ERR, QString("PESPacket[%1] Invalid adaptation field size:%2 control:%3")
61  .arg(cardid).arg(packet->AdaptationFieldSize()).arg(packet->AdaptationFieldControl()));
62  }
63  payloadSize -= delta;
64  payloadStart += delta;
65  }
66  }
67 
68  if (ccExp == cc)
69  {
70  if (m_pesDataSize + payloadSize >= m_allocSize)
71  {
72  uint sz = (((m_allocSize * 2) + 4095) / 4096) * 4096;
73  unsigned char *nbuf = pes_alloc(sz);
74  memcpy(nbuf, m_fullBuffer, m_pesDataSize);
76  m_fullBuffer = nbuf;
78  m_allocSize = sz;
79  }
80 
81  memcpy(m_fullBuffer + m_pesDataSize,
82  packet->data() + payloadStart,
83  payloadSize);
84 
85  m_ccLast = cc;
86  m_pesDataSize += payloadSize;
87  }
88  else if (int(m_ccLast) == cc)
89  {
90  // Do nothing with repeats
91  if (VERBOSE_LEVEL_CHECK(VB_RECORD, LOG_DEBUG))
92  {
93  LOG(VB_RECORD, LOG_ERR,
94  QString("AddTSPacket[%1]: Repeat packet!! ").arg(cardid) +
95  QString("PID: 0x%1, continuity counter: %2 ").arg(packet->PID(),0,16).arg(cc) +
96  QString("(expected %1)").arg(ccExp));
97  }
98  return true;
99  }
100  else
101  {
102  // Even if the packet is out of sync it is still the last packet received
103  m_ccLast = cc;
104 
105  LOG(VB_RECORD, LOG_ERR,
106  QString("AddTSPacket[%1]: Out of sync!!! Need to wait for next payloadStart ").arg(cardid) +
107  QString("PID: 0x%1, continuity counter: %2 ").arg(packet->PID(),0,16).arg(cc) +
108  QString("(expected %1)").arg(ccExp));
109  return true;
110  }
111 
112  // packet is correct or incomplete
113  broken = false;
114  // check if it's safe to call Length
115  if ((m_psiOffset + 1 + 3) <= m_pesDataSize)
116  {
117  // +3 = first 3 bytes of pespacket header, not included in Length()
118  uint tlen = Length() + (m_pesData - m_fullBuffer) +3;
119 
120  if (m_pesDataSize >= tlen)
121  {
122  m_badPacket = !VerifyCRC(cardid, packet->PID());
123  return true;
124  }
125  }
126 
127  return false;
128 }
129 
133 void PESPacket::GetAsTSPackets(std::vector<TSPacket> &output, uint cc) const
134 {
135  uint last_byte_of_pesdata = Length() + 4 - 1;
136  uint size = last_byte_of_pesdata + m_pesData - m_fullBuffer;
137 
138  if (m_pesData == m_fullBuffer)
139  {
140  LOG(VB_GENERAL, LOG_ERR, "WriteAsTSPackets m_pesData == m_fullBuffer");
141  output.resize(0);
142  return;
143  }
144 
145  output.resize(1);
146  memcpy(output[0].data(), m_fullBuffer, TSPacket::kSize);
147  output[0].data()[3] = (output[0].data()[3] & 0xf0) | cc;
148  if (size <= TSPacket::kSize)
149  return;
150 
151  TSHeader header;
152  header.data()[1] = 0x00;
153  header.data()[2] = 0x00;
154  header.data()[3] = 0x10; // adaptation field control == payload only
155  header.SetPID(tsheader()->PID());
156 
157  const unsigned char *data = m_fullBuffer + TSPacket::kSize;
158  size -= TSPacket::kSize;
159  while (size > 0)
160  {
161  cc = (cc + 1) & 0xF;
162  header.SetContinuityCounter(cc);
163  output.resize(output.size()+1);
164  output[output.size()-1].InitHeader(header.data());
165  uint write_size = std::min(size, TSPacket::kPayloadSize);
166  output[output.size()-1].InitPayload(data, write_size);
167  data += write_size;
168  size -= write_size;
169  }
170 }
171 
173 {
174  if (Length() < 1)
175  return kTheMagicNoCRCCRC;
176  return av_bswap32(av_crc(av_crc_get_table(AV_CRC_32_IEEE), UINT32_MAX,
177  m_pesData, Length() - 1));
178 }
179 
180 bool PESPacket::VerifyCRC(void) const
181 {
182  bool ret = !HasCRC() || (CalcCRC() == CRC());
183  if (!ret)
184  {
185  LOG(VB_SIPARSER, LOG_INFO,
186  QString("PESPacket: Failed CRC check 0x%1 != 0x%2 "
187  "for StreamID = 0x%3")
188  .arg(CRC(),8,16,QLatin1Char('0')).arg(CalcCRC(),8,16,QLatin1Char('0')).arg(StreamID(),0,16));
189  }
190  return ret;
191 }
192 
193 bool PESPacket::VerifyCRC(int cardid, int pid) const
194 {
195  bool ret = !HasCRC() || (CalcCRC() == CRC());
196  if (!ret)
197  {
198  LOG(VB_RECORD, LOG_INFO,
199  QString("PESPacket[%1] pid(0x%2): ").arg(cardid).arg(pid,0,16) +
200  QString("Failed CRC check 0x%1 != 0x%2 for ID = 0x%3")
201  .arg(CRC(),8,16,QLatin1Char('0')).arg(CalcCRC(),8,16,QLatin1Char('0')).arg(StreamID(),0,16));
202  }
203  return ret;
204 }
205 
206 // These are pixel aspect ratios
208 {
209  0.0000F, 1.0000F, 0.6735F, 0.7031F,
210  0.7615F, 0.8055F, 0.8437F, 0.8935F,
211  0.9157F, 0.9815F, 1.0255F, 1.0695F,
212  1.0950F, 1.1575F, 1.2015F, 0.0000F,
213 };
214 
218 {
219  0.0000F, 1.0000F, -3.0F/4.0F, -9.0F/16.0F,
220  -1.0F/2.21F, 0.0000F, 0.0000F, 0.0000F,
221  0.0000F, 0.0000F, 0.0000F, 0.0000F,
222  0.0000F, 0.0000F, 0.0000F, 0.0000F,
223 };
224 
226 {
227  0.0F, 24000/1001.0F, 24.0F, 25.0F,
228  30000/1001.0F, 30.0F, 50.0F, 60000/1001.0F,
229  60.0F, 1.0F, 1.0F, 1.0F,
230  1.0F, 1.0F, 1.0F, 1.0F,
231 };
232 
234 float SequenceHeader::aspect(bool mpeg1) const
235 {
236  if (!height())
237  return 1.0F; // avoid segfaults on broken seq data
238 
239  uint index = aspectNum();
240  float aspect = (mpeg1) ? kMpeg1Aspect[index] : kMpeg2Aspect[index];
241 
242  float retval = 0.0F;
243  retval = (aspect > 0.0F) ? width() / (aspect * height()) : retval;
244  retval = (aspect < 0.0F) ? -1.0F / aspect : retval;
245  retval = (retval <= 0.0F) ? width() * 1.0F / height() : retval;
246  return retval;
247 }
248 
249 
250 
252 // Memory allocator to avoid malloc global lock and waste less memory. //
254 
255 #ifndef USING_VALGRIND
256 static std::vector<unsigned char*> mem188;
257 static std::vector<unsigned char*> free188;
258 static std::map<unsigned char*, bool> alloc188;
259 
260 static std::vector<unsigned char*> mem4096;
261 static std::vector<unsigned char*> free4096;
262 static std::map<unsigned char*, bool> alloc4096;
263 
264 static constexpr size_t BLOCKS188 { 512 };
265 static unsigned char* get_188_block()
266 {
267  if (free188.empty())
268  {
269  mem188.push_back((unsigned char*) malloc(188_UZ * BLOCKS188));
270  free188.reserve(BLOCKS188);
271  unsigned char* block_start = mem188.back();
272  for (size_t i = 0; i < BLOCKS188; ++i)
273  free188.push_back((i * 188_UZ) + block_start);
274  }
275 
276  unsigned char *ptr = free188.back();
277  free188.pop_back();
278  alloc188[ptr] = true;
279  return ptr;
280 }
281 
282 static bool is_188_block(unsigned char* ptr)
283 {
284  return alloc188.find(ptr) != alloc188.end();
285 }
286 
287 static void return_188_block(unsigned char* ptr)
288 {
289  alloc188.erase(ptr);
290  free188.push_back(ptr);
291  // free the allocator only if more than 1 block was used
292  if (alloc188.empty() && mem188.size() > 1)
293  {
294  std::vector<unsigned char*>::iterator it;
295  for (it = mem188.begin(); it != mem188.end(); ++it)
296  free(*it);
297  mem188.clear();
298  free188.clear();
299 #if 0
300  LOG(VB_GENERAL, LOG_DEBUG, "freeing all 188 blocks");
301 #endif
302  }
303 }
304 
305 static constexpr size_t BLOCKS4096 { 128 };
306 static unsigned char* get_4096_block()
307 {
308  if (free4096.empty())
309  {
310  mem4096.push_back((unsigned char*) malloc(4096_UZ * BLOCKS4096));
311  free4096.reserve(BLOCKS4096);
312  unsigned char* block_start = mem4096.back();
313  for (size_t i = 0; i < BLOCKS4096; ++i)
314  free4096.push_back((i * 4096_UZ) + block_start);
315  }
316 
317  unsigned char *ptr = free4096.back();
318  free4096.pop_back();
319  alloc4096[ptr] = true;
320  return ptr;
321 }
322 
323 static bool is_4096_block(unsigned char* ptr)
324 {
325  return alloc4096.find(ptr) != alloc4096.end();
326 }
327 
328 static void return_4096_block(unsigned char* ptr)
329 {
330  alloc4096.erase(ptr);
331  free4096.push_back(ptr);
332 
333 #if 0 // enable this to debug memory leaks
334  LOG(VB_GENERAL, LOG_DEBUG, QString("%1 4096 blocks remain")
335  .arg(alloc4096.size()));
336  map<unsigned char*, bool>::iterator it;
337  for (it = alloc4096.begin(); it != alloc4096.end(); ++it)
338  {
339  TSPacket *ts = (TSPacket*) it->first;
340  LGO(VB_GENERAL, LOG_DEBUG, QString("PES Packet: pid(0x%1)")
341  .arg(ts->PID(),0,16));
342  if (ts->PID() == 0x1ffb)
343  {
344  LOG(VB_GENERAL, LOG_DEBUG, QString(" tid(0x%1) ext(0x%2)")
345  .arg(PSIPTable(*ts).TableID(),0,16)
346  .arg(PSIPTable(*ts).TableIDExtension(),0,16));
347  }
348  }
349 #endif
350 
351  // free the allocator only if more than 1 block was used
352  if (alloc4096.empty() && mem4096.size() > 1)
353  {
354  std::vector<unsigned char*>::iterator it;
355  for (it = mem4096.begin(); it != mem4096.end(); ++it)
356  free(*it);
357  mem4096.clear();
358  free4096.clear();
359 #if 0
360  LOG(VB_GENERAL, LOG_DEBUG, "freeing all 4096 blocks");
361 #endif
362  }
363 }
364 #endif
365 
366 static QMutex pes_alloc_mutex;
367 
368 unsigned char *pes_alloc(uint size)
369 {
370  QMutexLocker locker(&pes_alloc_mutex);
371 #ifndef USING_VALGRIND
372  if (size <= 188)
373  return get_188_block();
374  if (size <= 4096)
375  return get_4096_block();
376 #endif // USING_VALGRIND
377  return (unsigned char*) malloc(size);
378 }
379 
380 void pes_free(unsigned char *ptr)
381 {
382  QMutexLocker locker(&pes_alloc_mutex);
383 #ifndef USING_VALGRIND
384  if (is_188_block(ptr))
385  return_188_block(ptr);
386  else if (is_4096_block(ptr))
387  return_4096_block(ptr);
388  else
389 #endif // USING_VALGRIND
390  free(ptr);
391 }
PESPacket::m_pesData
unsigned char * m_pesData
Pointer to PES data in full buffer.
Definition: pespacket.h:219
mem4096
static std::vector< unsigned char * > mem4096
Definition: pespacket.cpp:260
PESPacket::m_pesDataSize
uint m_pesDataSize
Number of data bytes (TS header + PES data)
Definition: pespacket.h:224
TSHeader::PayloadStart
bool PayloadStart(void) const
Definition: tspacket.h:89
TSHeader::AdaptationFieldSize
size_t AdaptationFieldSize(void) const
Definition: tspacket.h:114
get_4096_block
static unsigned char * get_4096_block()
Definition: pespacket.cpp:306
SequenceHeader::kMpeg1Aspect
static const AspectArray kMpeg1Aspect
Definition: pespacket.h:251
PESPacket::IsClone
bool IsClone() const
Definition: pespacket.h:83
alloc4096
static std::map< unsigned char *, bool > alloc4096
Definition: pespacket.cpp:262
PESPacket::tsheader
const TSHeader * tsheader() const
Definition: pespacket.h:90
TSHeader::PID
unsigned int PID(void) const
Definition: tspacket.h:93
VERBOSE_LEVEL_CHECK
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
PESPacket::m_allocSize
uint m_allocSize
Total number of bytes we allocated.
Definition: pespacket.h:225
PESPacket::CalcCRC
uint CalcCRC(void) const
Definition: pespacket.cpp:172
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
SequenceHeader::height
uint height(void) const
Definition: pespacket.h:240
free188
static std::vector< unsigned char * > free188
Definition: pespacket.cpp:257
PESPacket::StreamID
uint StreamID() const
Definition: pespacket.h:98
PESPacket::m_badPacket
bool m_badPacket
true if a CRC is not good yet
Definition: pespacket.h:226
TSHeader::HasAdaptationField
bool HasAdaptationField(void) const
Definition: tspacket.h:113
TSHeader::ContinuityCounter
unsigned int ContinuityCounter(void) const
Definition: tspacket.h:109
TSHeader::SetContinuityCounter
void SetContinuityCounter(unsigned int cc)
Definition: tspacket.h:170
PSIPTable
A PSIP table is a variant of a PES packet containing an MPEG, ATSC or DVB table.
Definition: mpegtables.h:409
TSHeader::kHeaderSize
static constexpr unsigned int kHeaderSize
Definition: tspacket.h:177
PESPacket::data
const unsigned char * data() const
Definition: pespacket.h:167
mythlogging.h
alloc188
static std::map< unsigned char *, bool > alloc188
Definition: pespacket.cpp:258
TSPacket
Used to access the data of a Transport Stream packet.
Definition: tspacket.h:207
get_188_block
static unsigned char * get_188_block()
Definition: pespacket.cpp:265
BLOCKS4096
static constexpr size_t BLOCKS4096
Definition: pespacket.cpp:305
SequenceHeader::kMpeg2Fps
static const AspectArray kMpeg2Fps
Definition: pespacket.h:253
pes_alloc_mutex
static QMutex pes_alloc_mutex
Definition: pespacket.cpp:366
PESPacket::Length
uint Length() const
Definition: pespacket.h:99
mpegtables.h
pes_free
void pes_free(unsigned char *ptr)
Definition: pespacket.cpp:380
PESPacket::VerifyCRC
bool VerifyCRC(void) const
Definition: pespacket.cpp:180
sizetliteral.h
SequenceHeader::aspect
float aspect(bool mpeg1) const
Returns the screen aspect ratio.
Definition: pespacket.cpp:234
BLOCKS188
static constexpr size_t BLOCKS188
Definition: pespacket.cpp:264
TSPacket::kPayloadSize
static constexpr unsigned int kPayloadSize
Definition: tspacket.h:262
pespacket.h
is_188_block
static bool is_188_block(unsigned char *ptr)
Definition: pespacket.cpp:282
PESPacket::kTheMagicNoCRCCRC
static const uint kTheMagicNoCRCCRC
Definition: pespacket.h:230
AspectArray
std::array< float, 16 > AspectArray
Definition: pespacket.h:13
SequenceHeader::width
uint width(void) const
Definition: pespacket.h:239
SequenceHeader::kMpeg2Aspect
static const AspectArray kMpeg2Aspect
The negative values are screen aspect ratios, while the positive ones are pixel aspect ratios.
Definition: pespacket.h:252
pes_alloc
unsigned char * pes_alloc(uint size)
Definition: pespacket.cpp:368
TSHeader::AdaptationFieldControl
unsigned int AdaptationFieldControl(void) const
Definition: tspacket.h:103
PESPacket::CRC
uint CRC(void) const
Definition: pespacket.h:189
return_4096_block
static void return_4096_block(unsigned char *ptr)
Definition: pespacket.cpp:328
SequenceHeader::aspectNum
uint aspectNum(void) const
Definition: pespacket.h:241
PSIPTable::TableID
uint TableID(void) const
Definition: mpegtables.h:496
PSIPTable::TableIDExtension
uint TableIDExtension(void) const
Definition: mpegtables.h:515
return_188_block
static void return_188_block(unsigned char *ptr)
Definition: pespacket.cpp:287
TSHeader::SetPID
void SetPID(unsigned int pid)
Definition: tspacket.h:160
TSHeader
Used to access header of a TSPacket.
Definition: tspacket.h:46
PESPacket::AddTSPacket
bool AddTSPacket(const TSPacket *tspacket, int cardid, bool &broken)
Definition: pespacket.cpp:20
PESPacket::GetAsTSPackets
void GetAsTSPackets(std::vector< TSPacket > &output, uint cc) const
Returns payload only PESPacket as series of TSPackets.
Definition: pespacket.cpp:133
mem188
static std::vector< unsigned char * > mem188
Definition: pespacket.cpp:256
PESPacket::HasCRC
virtual bool HasCRC() const
1 bit Cyclic Redundancy Check present
Definition: pespacket.h:130
PESPacket::m_fullBuffer
unsigned char * m_fullBuffer
Pointer to allocated data.
Definition: pespacket.h:220
output
#define output
Definition: synaesthesia.cpp:223
TSHeader::data
const unsigned char * data(void) const
Definition: tspacket.h:174
is_4096_block
static bool is_4096_block(unsigned char *ptr)
Definition: pespacket.cpp:323
PESPacket::m_ccLast
uint m_ccLast
Continuity counter of last inserted TS Packet.
Definition: pespacket.h:223
free4096
static std::vector< unsigned char * > free4096
Definition: pespacket.cpp:261
uint
unsigned int uint
Definition: freesurround.h:24
TSPacket::kSize
static constexpr unsigned int kSize
Definition: tspacket.h:261
PESPacket::m_psiOffset
uint m_psiOffset
AFCOffset + StartOfFieldPointer.
Definition: pespacket.h:222