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  }
92  else
93  {
94  LOG(VB_RECORD, LOG_ERR,
95  QString("AddTSPacket[%1]: Out of sync!!! Need to wait for next payloadStart ").arg(cardid) +
96  QString("PID: 0x%1, continuity counter: %2 ").arg(packet->PID(),0,16).arg(cc) +
97  QString("(expected %1)").arg(ccExp));
98  return true;
99  }
100 
101  // packet is correct or incomplete
102  broken = false;
103  // check if it's safe to call Length
104  if ((m_psiOffset + 1 + 3) <= m_pesDataSize)
105  {
106  // +3 = first 3 bytes of pespacket header, not included in Length()
107  uint tlen = Length() + (m_pesData - m_fullBuffer) +3;
108 
109  if (m_pesDataSize >= tlen)
110  {
111  m_badPacket = !VerifyCRC(cardid, packet->PID());
112  return true;
113  }
114  }
115 
116  return false;
117 }
118 
122 void PESPacket::GetAsTSPackets(std::vector<TSPacket> &output, uint cc) const
123 {
124  uint last_byte_of_pesdata = Length() + 4 - 1;
125  uint size = last_byte_of_pesdata + m_pesData - m_fullBuffer;
126 
127  if (m_pesData == m_fullBuffer)
128  {
129  LOG(VB_GENERAL, LOG_ERR, "WriteAsTSPackets m_pesData == m_fullBuffer");
130  output.resize(0);
131  return;
132  }
133 
134  output.resize(1);
135  memcpy(output[0].data(), m_fullBuffer, TSPacket::kSize);
136  output[0].data()[3] = (output[0].data()[3] & 0xf0) | cc;
137  if (size <= TSPacket::kSize)
138  return;
139 
140  TSHeader header;
141  header.data()[1] = 0x00;
142  header.data()[2] = 0x00;
143  header.data()[3] = 0x10; // adaptation field control == payload only
144  header.SetPID(tsheader()->PID());
145 
146  const unsigned char *data = m_fullBuffer + TSPacket::kSize;
147  size -= TSPacket::kSize;
148  while (size > 0)
149  {
150  cc = (cc + 1) & 0xF;
151  header.SetContinuityCounter(cc);
152  output.resize(output.size()+1);
153  output[output.size()-1].InitHeader(header.data());
154  uint write_size = std::min(size, TSPacket::kPayloadSize);
155  output[output.size()-1].InitPayload(data, write_size);
156  data += write_size;
157  size -= write_size;
158  }
159 }
160 
162 {
163  if (Length() < 1)
164  return kTheMagicNoCRCCRC;
165  return av_bswap32(av_crc(av_crc_get_table(AV_CRC_32_IEEE), UINT32_MAX,
166  m_pesData, Length() - 1));
167 }
168 
169 bool PESPacket::VerifyCRC(void) const
170 {
171  bool ret = !HasCRC() || (CalcCRC() == CRC());
172  if (!ret)
173  {
174  LOG(VB_SIPARSER, LOG_INFO,
175  QString("PESPacket: Failed CRC check 0x%1 != 0x%2 "
176  "for StreamID = 0x%3")
177  .arg(CRC(),8,16,QLatin1Char('0')).arg(CalcCRC(),8,16,QLatin1Char('0')).arg(StreamID(),0,16));
178  }
179  return ret;
180 }
181 
182 bool PESPacket::VerifyCRC(int cardid, int pid) const
183 {
184  bool ret = !HasCRC() || (CalcCRC() == CRC());
185  if (!ret)
186  {
187  LOG(VB_RECORD, LOG_INFO,
188  QString("PESPacket[%1] pid(0x%2): ").arg(cardid).arg(pid,0,16) +
189  QString("Failed CRC check 0x%1 != 0x%2 for ID = 0x%3")
190  .arg(CRC(),8,16,QLatin1Char('0')).arg(CalcCRC(),8,16,QLatin1Char('0')).arg(StreamID(),0,16));
191  }
192  return ret;
193 }
194 
195 // These are pixel aspect ratios
197 {
198  0.0000F, 1.0000F, 0.6735F, 0.7031F,
199  0.7615F, 0.8055F, 0.8437F, 0.8935F,
200  0.9157F, 0.9815F, 1.0255F, 1.0695F,
201  1.0950F, 1.1575F, 1.2015F, 0.0000F,
202 };
203 
207 {
208  0.0000F, 1.0000F, -3.0F/4.0F, -9.0F/16.0F,
209  -1.0F/2.21F, 0.0000F, 0.0000F, 0.0000F,
210  0.0000F, 0.0000F, 0.0000F, 0.0000F,
211  0.0000F, 0.0000F, 0.0000F, 0.0000F,
212 };
213 
215 {
216  0.0F, 24000/1001.0F, 24.0F, 25.0F,
217  30000/1001.0F, 30.0F, 50.0F, 60000/1001.0F,
218  60.0F, 1.0F, 1.0F, 1.0F,
219  1.0F, 1.0F, 1.0F, 1.0F,
220 };
221 
223 float SequenceHeader::aspect(bool mpeg1) const
224 {
225  if (!height())
226  return 1.0F; // avoid segfaults on broken seq data
227 
228  uint index = aspectNum();
229  float aspect = (mpeg1) ? kMpeg1Aspect[index] : kMpeg2Aspect[index];
230 
231  float retval = 0.0F;
232  retval = (aspect > 0.0F) ? width() / (aspect * height()) : retval;
233  retval = (aspect < 0.0F) ? -1.0F / aspect : retval;
234  retval = (retval <= 0.0F) ? width() * 1.0F / height() : retval;
235  return retval;
236 }
237 
238 
239 
241 // Memory allocator to avoid malloc global lock and waste less memory. //
243 
244 #ifndef USING_VALGRIND
245 static std::vector<unsigned char*> mem188;
246 static std::vector<unsigned char*> free188;
247 static std::map<unsigned char*, bool> alloc188;
248 
249 static std::vector<unsigned char*> mem4096;
250 static std::vector<unsigned char*> free4096;
251 static std::map<unsigned char*, bool> alloc4096;
252 
253 static constexpr size_t BLOCKS188 { 512 };
254 static unsigned char* get_188_block()
255 {
256  if (free188.empty())
257  {
258  mem188.push_back((unsigned char*) malloc(188_UZ * BLOCKS188));
259  free188.reserve(BLOCKS188);
260  unsigned char* block_start = mem188.back();
261  for (size_t i = 0; i < BLOCKS188; ++i)
262  free188.push_back(i * 188_UZ + block_start);
263  }
264 
265  unsigned char *ptr = free188.back();
266  free188.pop_back();
267  alloc188[ptr] = true;
268  return ptr;
269 }
270 
271 static bool is_188_block(unsigned char* ptr)
272 {
273  return alloc188.find(ptr) != alloc188.end();
274 }
275 
276 static void return_188_block(unsigned char* ptr)
277 {
278  alloc188.erase(ptr);
279  free188.push_back(ptr);
280  // free the allocator only if more than 1 block was used
281  if (alloc188.empty() && mem188.size() > 1)
282  {
283  std::vector<unsigned char*>::iterator it;
284  for (it = mem188.begin(); it != mem188.end(); ++it)
285  free(*it);
286  mem188.clear();
287  free188.clear();
288 #if 0
289  LOG(VB_GENERAL, LOG_DEBUG, "freeing all 188 blocks");
290 #endif
291  }
292 }
293 
294 static constexpr size_t BLOCKS4096 { 128 };
295 static unsigned char* get_4096_block()
296 {
297  if (free4096.empty())
298  {
299  mem4096.push_back((unsigned char*) malloc(4096_UZ * BLOCKS4096));
300  free4096.reserve(BLOCKS4096);
301  unsigned char* block_start = mem4096.back();
302  for (size_t i = 0; i < BLOCKS4096; ++i)
303  free4096.push_back(i * 4096_UZ + block_start);
304  }
305 
306  unsigned char *ptr = free4096.back();
307  free4096.pop_back();
308  alloc4096[ptr] = true;
309  return ptr;
310 }
311 
312 static bool is_4096_block(unsigned char* ptr)
313 {
314  return alloc4096.find(ptr) != alloc4096.end();
315 }
316 
317 static void return_4096_block(unsigned char* ptr)
318 {
319  alloc4096.erase(ptr);
320  free4096.push_back(ptr);
321 
322 #if 0 // enable this to debug memory leaks
323  LOG(VB_GENERAL, LOG_DEBUG, QString("%1 4096 blocks remain")
324  .arg(alloc4096.size()));
325  map<unsigned char*, bool>::iterator it;
326  for (it = alloc4096.begin(); it != alloc4096.end(); ++it)
327  {
328  TSPacket *ts = (TSPacket*) it->first;
329  LGO(VB_GENERAL, LOG_DEBUG, QString("PES Packet: pid(0x%1)")
330  .arg(ts->PID(),0,16));
331  if (ts->PID() == 0x1ffb)
332  {
333  LOG(VB_GENERAL, LOG_DEBUG, QString(" tid(0x%1) ext(0x%2)")
334  .arg(PSIPTable(*ts).TableID(),0,16)
335  .arg(PSIPTable(*ts).TableIDExtension(),0,16));
336  }
337  }
338 #endif
339 
340  // free the allocator only if more than 1 block was used
341  if (alloc4096.empty() && mem4096.size() > 1)
342  {
343  std::vector<unsigned char*>::iterator it;
344  for (it = mem4096.begin(); it != mem4096.end(); ++it)
345  free(*it);
346  mem4096.clear();
347  free4096.clear();
348 #if 0
349  LOG(VB_GENERAL, LOG_DEBUG, "freeing all 4096 blocks");
350 #endif
351  }
352 }
353 #endif
354 
355 static QMutex pes_alloc_mutex;
356 
357 unsigned char *pes_alloc(uint size)
358 {
359  QMutexLocker locker(&pes_alloc_mutex);
360 #ifndef USING_VALGRIND
361  if (size <= 188)
362  return get_188_block();
363  if (size <= 4096)
364  return get_4096_block();
365 #endif // USING_VALGRIND
366  return (unsigned char*) malloc(size);
367 }
368 
369 void pes_free(unsigned char *ptr)
370 {
371  QMutexLocker locker(&pes_alloc_mutex);
372 #ifndef USING_VALGRIND
373  if (is_188_block(ptr))
374  return_188_block(ptr);
375  else if (is_4096_block(ptr))
376  return_4096_block(ptr);
377  else
378 #endif // USING_VALGRIND
379  free(ptr);
380 }
PESPacket::m_pesData
unsigned char * m_pesData
Pointer to PES data in full buffer.
Definition: pespacket.h:221
mem4096
static std::vector< unsigned char * > mem4096
Definition: pespacket.cpp:249
PESPacket::m_pesDataSize
uint m_pesDataSize
Number of data bytes (TS header + PES data)
Definition: pespacket.h:226
TSHeader::PayloadStart
bool PayloadStart(void) const
Definition: tspacket.h:87
TSHeader::AdaptationFieldSize
size_t AdaptationFieldSize(void) const
Definition: tspacket.h:112
get_4096_block
static unsigned char * get_4096_block()
Definition: pespacket.cpp:295
SequenceHeader::kMpeg1Aspect
static const AspectArray kMpeg1Aspect
Definition: pespacket.h:250
PESPacket::IsClone
bool IsClone() const
Definition: pespacket.h:85
alloc4096
static std::map< unsigned char *, bool > alloc4096
Definition: pespacket.cpp:251
PESPacket::tsheader
const TSHeader * tsheader() const
Definition: pespacket.h:92
TSHeader::PID
unsigned int PID(void) const
Definition: tspacket.h:91
cc
Definition: cc.h:9
PESPacket::m_allocSize
uint m_allocSize
Total number of bytes we allocated.
Definition: pespacket.h:227
PESPacket::CalcCRC
uint CalcCRC(void) const
Definition: pespacket.cpp:161
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
SequenceHeader::height
uint height(void) const
Definition: pespacket.h:239
free188
static std::vector< unsigned char * > free188
Definition: pespacket.cpp:246
PESPacket::StreamID
uint StreamID() const
Definition: pespacket.h:100
PESPacket::m_badPacket
bool m_badPacket
true if a CRC is not good yet
Definition: pespacket.h:228
TSHeader::HasAdaptationField
bool HasAdaptationField(void) const
Definition: tspacket.h:111
TSHeader::ContinuityCounter
unsigned int ContinuityCounter(void) const
Definition: tspacket.h:107
TSHeader::SetContinuityCounter
void SetContinuityCounter(unsigned int cc)
Definition: tspacket.h:168
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:175
PESPacket::data
const unsigned char * data() const
Definition: pespacket.h:169
mythlogging.h
alloc188
static std::map< unsigned char *, bool > alloc188
Definition: pespacket.cpp:247
TSPacket
Used to access the data of a Transport Stream packet.
Definition: tspacket.h:205
get_188_block
static unsigned char * get_188_block()
Definition: pespacket.cpp:254
BLOCKS4096
static constexpr size_t BLOCKS4096
Definition: pespacket.cpp:294
SequenceHeader::kMpeg2Fps
static const AspectArray kMpeg2Fps
Definition: pespacket.h:252
pes_alloc_mutex
static QMutex pes_alloc_mutex
Definition: pespacket.cpp:355
PESPacket::Length
uint Length() const
Definition: pespacket.h:101
mpegtables.h
pes_free
void pes_free(unsigned char *ptr)
Definition: pespacket.cpp:369
PESPacket::VerifyCRC
bool VerifyCRC(void) const
Definition: pespacket.cpp:169
sizetliteral.h
uint
unsigned int uint
Definition: compat.h:79
SequenceHeader::aspect
float aspect(bool mpeg1) const
Returns the screen aspect ratio.
Definition: pespacket.cpp:223
BLOCKS188
static constexpr size_t BLOCKS188
Definition: pespacket.cpp:253
TSPacket::kPayloadSize
static constexpr unsigned int kPayloadSize
Definition: tspacket.h:260
pespacket.h
is_188_block
static bool is_188_block(unsigned char *ptr)
Definition: pespacket.cpp:271
PESPacket::kTheMagicNoCRCCRC
static const uint kTheMagicNoCRCCRC
Definition: pespacket.h:232
AspectArray
std::array< float, 16 > AspectArray
Definition: pespacket.h:13
SequenceHeader::width
uint width(void) const
Definition: pespacket.h:238
SequenceHeader::kMpeg2Aspect
static const AspectArray kMpeg2Aspect
The negative values are screen aspect ratios, while the positive ones are pixel aspect ratios.
Definition: pespacket.h:251
pes_alloc
unsigned char * pes_alloc(uint size)
Definition: pespacket.cpp:357
TSHeader::AdaptationFieldControl
unsigned int AdaptationFieldControl(void) const
Definition: tspacket.h:101
PESPacket::CRC
uint CRC(void) const
Definition: pespacket.h:191
return_4096_block
static void return_4096_block(unsigned char *ptr)
Definition: pespacket.cpp:317
SequenceHeader::aspectNum
uint aspectNum(void) const
Definition: pespacket.h:240
PSIPTable::TableID
uint TableID(void) const
Definition: mpegtables.h:515
PSIPTable::TableIDExtension
uint TableIDExtension(void) const
Definition: mpegtables.h:532
return_188_block
static void return_188_block(unsigned char *ptr)
Definition: pespacket.cpp:276
TSHeader::SetPID
void SetPID(unsigned int pid)
Definition: tspacket.h:158
TSHeader
Used to access header of a TSPacket.
Definition: tspacket.h:44
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:122
mem188
static std::vector< unsigned char * > mem188
Definition: pespacket.cpp:245
PESPacket::HasCRC
virtual bool HasCRC() const
1 bit Cyclic Redundancy Check present
Definition: pespacket.h:132
PESPacket::m_fullBuffer
unsigned char * m_fullBuffer
Pointer to allocated data.
Definition: pespacket.h:222
output
#define output
Definition: synaesthesia.cpp:220
TSHeader::data
const unsigned char * data(void) const
Definition: tspacket.h:172
is_4096_block
static bool is_4096_block(unsigned char *ptr)
Definition: pespacket.cpp:312
PESPacket::m_ccLast
uint m_ccLast
Continuity counter of last inserted TS Packet.
Definition: pespacket.h:225
free4096
static std::vector< unsigned char * > free4096
Definition: pespacket.cpp:250
TSPacket::kSize
static constexpr unsigned int kSize
Definition: tspacket.h:259
PESPacket::m_psiOffset
uint m_psiOffset
AFCOffset + StartOfFieldPointer.
Definition: pespacket.h:224