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