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 using namespace std;
19 
20 // return true if complete or broken
21 bool PESPacket::AddTSPacket(const TSPacket* packet, bool &broken)
22 {
23  broken = true;
24  if (!tsheader()->PayloadStart())
25  {
26  LOG(VB_RECORD, LOG_ERR,
27  "Error: We started a PES packet, without a payloadStart!");
28  return true;
29  }
30  if (!IsClone())
31  {
32  LOG(VB_RECORD, LOG_ERR,
33  "Error: Must clone initially to use addPackets()");
34  return false;
35  }
36 
37  const int cc = packet->ContinuityCounter();
38  const int ccExp = (_ccLast + 1) & 0xf;
39  uint payloadSize = TSPacket::kPayloadSize;
40  uint payloadStart = TSPacket::kHeaderSize;
41 
42  // If the next TS has an offset, we need to strip it out.
43  // The offset will be used when a new PESPacket is created.
44  if (packet->PayloadStart())
45  {
46  payloadSize--;
47  payloadStart++;
48  }
49 
50  if (ccExp == cc)
51  {
52  if (_pesdataSize + payloadSize >= _allocSize)
53  {
54  uint sz = (((_allocSize * 2) + 4095) / 4096) * 4096;
55  unsigned char *nbuf = pes_alloc(sz);
56  memcpy(nbuf, _fullbuffer, _pesdataSize);
57  pes_free(_fullbuffer);
58  _fullbuffer = nbuf;
59  _pesdata = _fullbuffer + _psiOffset + 1;
60  _allocSize = sz;
61  }
62 
63  memcpy(_fullbuffer + _pesdataSize,
64  packet->data() + payloadStart,
65  payloadSize);
66 
67  _ccLast = cc;
68  _pesdataSize += payloadSize;
69  }
70  else if (int(_ccLast) == cc)
71  {
72  // do nothing with repeats
73  }
74  else
75  {
76  LOG(VB_RECORD, LOG_ERR,
77  "AddTSPacket: Out of sync!!! Need to wait for next payloadStart" +
78  QString(" PID: 0x%1, continuity counter: %2 (expected %3).")
79  .arg(packet->PID(),0,16).arg(cc).arg(ccExp));
80  return true;
81  }
82 
83  // packet is correct or incomplete
84  broken = false;
85  // check if it's safe to call Length
86  if ((_psiOffset + 1 + 3) <= _pesdataSize)
87  {
88  // +3 = first 3 bytes of pespacket header, not included in Length()
89  uint tlen = Length() + (_pesdata - _fullbuffer) +3;
90 
91  if (_pesdataSize >= tlen)
92  {
93  _badPacket = !VerifyCRC();
94  return true;
95  }
96  }
97 
98  return false;
99 }
100 
104 void PESPacket::GetAsTSPackets(vector<TSPacket> &output, uint cc) const
105 {
106 #define INCR_CC(_CC_) do { (_CC_) = ((_CC_) + 1) & 0xf; } while (false)
107  uint last_byte_of_pesdata = Length() + 4 - 1;
108  uint size = last_byte_of_pesdata + _pesdata - _fullbuffer;
109 
110  if (_pesdata == _fullbuffer)
111  {
112  LOG(VB_GENERAL, LOG_ERR, "WriteAsTSPackets _pesdata == _fullbuffer");
113  output.resize(0);
114  return;
115  }
116 
117  output.resize(1);
118  memcpy(output[0].data(), _fullbuffer, TSPacket::kSize);
119  output[0].data()[3] = (output[0].data()[3] & 0xf0) | cc;
120  if (size <= TSPacket::kSize)
121  return;
122 
123  TSHeader header;
124  header.data()[1] = 0x00;
125  header.data()[2] = 0x00;
126  header.data()[3] = 0x10; // adaptation field control == payload only
127  header.SetPID(tsheader()->PID());
128 
129  const unsigned char *data = _fullbuffer + TSPacket::kSize;
130  size -= TSPacket::kSize;
131  while (size > 0)
132  {
133  INCR_CC(cc);
134  header.SetContinuityCounter(cc);
135  output.resize(output.size()+1);
136  output[output.size()-1].InitHeader(header.data());
137  uint write_size = min(size, TSPacket::kPayloadSize);
138  output[output.size()-1].InitPayload(data, write_size);
139  data += write_size;
140  size -= write_size;
141  }
142 #undef INCR_CC
143 }
144 
146 {
147  if (Length() < 1)
148  return kTheMagicNoCRCCRC;
149  return av_bswap32(av_crc(av_crc_get_table(AV_CRC_32_IEEE), (uint32_t) -1,
150  _pesdata, Length() - 1));
151 }
152 
153 bool PESPacket::VerifyCRC(void) const
154 {
155  bool ret = !HasCRC() || (CalcCRC() == CRC());
156  if (!ret)
157  {
158  LOG(VB_SIPARSER, LOG_INFO,
159  QString("PESPacket: Failed CRC check 0x%1 != 0x%2 "
160  "for StreamID = 0x%3")
161  .arg(CRC(),8,16,QLatin1Char('0')).arg(CalcCRC(),8,16,QLatin1Char('0')).arg(StreamID(),0,16));
162  }
163  return ret;
164 }
165 
166 // These are pixel aspect ratios
167 const float SequenceHeader::mpeg1_aspect[16] =
168 {
169  0.0000F, 1.0000F, 0.6735F, 0.7031F,
170  0.7615F, 0.8055F, 0.8437F, 0.8935F,
171  0.9157F, 0.9815F, 1.0255F, 1.0695F,
172  1.0950F, 1.1575F, 1.2015F, 0.0000F,
173 };
174 
177 const float SequenceHeader::mpeg2_aspect[16] =
178 {
179  0.0000F, 1.0000F, -3.0F/4.0F, -9.0F/16.0F,
180  -1.0F/2.21F, 0.0000F, 0.0000F, 0.0000F,
181  0.0000F, 0.0000F, 0.0000F, 0.0000F,
182  0.0000F, 0.0000F, 0.0000F, 0.0000F,
183 };
184 
185 const float SequenceHeader::mpeg2_fps[16] =
186 {
187  0.0F, 24000/1001.0F, 24.0F, 25.0F,
188  30000/1001.0F, 30.0F, 50.0F, 60000/1001.0F,
189  60.0F, 1.0F, 1.0F, 1.0F,
190  1.0F, 1.0F, 1.0F, 1.0F,
191 };
192 
194 float SequenceHeader::aspect(bool mpeg1) const
195 {
196  if (!height())
197  return 1.0F; // avoid segfaults on broken seq data
198 
199  uint index = aspectNum();
200  float aspect = (mpeg1) ? mpeg1_aspect[index] : mpeg2_aspect[index];
201 
202  float retval = 0.0F;
203  retval = (aspect > 0.0F) ? width() / (aspect * height()) : retval;
204  retval = (aspect < 0.0F) ? -1.0F / aspect : retval;
205  retval = (retval <= 0.0F) ? width() * 1.0F / height() : retval;
206  return retval;
207 }
208 
209 
210 
212 // Memory allocator to avoid malloc global lock and waste less memory. //
214 
215 #ifndef USING_VALGRIND
216 static vector<unsigned char*> mem188;
217 static vector<unsigned char*> free188;
218 static map<unsigned char*, bool> alloc188;
219 
220 static vector<unsigned char*> mem4096;
221 static vector<unsigned char*> free4096;
222 static map<unsigned char*, bool> alloc4096;
223 
224 #define BLOCKS188 512
225 static unsigned char* get_188_block()
226 {
227  if (free188.empty())
228  {
229  mem188.push_back((unsigned char*) malloc(188 * BLOCKS188));
230  free188.reserve(BLOCKS188);
231  unsigned char* block_start = mem188.back();
232  for (uint i = 0; i < BLOCKS188; ++i)
233  free188.push_back(i*188 + block_start);
234  }
235 
236  unsigned char *ptr = free188.back();
237  free188.pop_back();
238  alloc188[ptr] = true;
239  return ptr;
240 }
241 #undef BLOCKS188
242 
243 static bool is_188_block(unsigned char* ptr)
244 {
245  return alloc188.find(ptr) != alloc188.end();
246 }
247 
248 static void return_188_block(unsigned char* ptr)
249 {
250  alloc188.erase(ptr);
251  free188.push_back(ptr);
252  // free the allocator only if more than 1 block was used
253  if (alloc188.empty() && mem188.size() > 1)
254  {
255  vector<unsigned char*>::iterator it;
256  for (it = mem188.begin(); it != mem188.end(); ++it)
257  free(*it);
258  mem188.clear();
259  free188.clear();
260 #if 0
261  LOG(VB_GENERAL, LOG_DEBUG, "freeing all 188 blocks");
262 #endif
263  }
264 }
265 
266 #define BLOCKS4096 128
267 static unsigned char* get_4096_block()
268 {
269  if (free4096.empty())
270  {
271  mem4096.push_back((unsigned char*) malloc(4096 * BLOCKS4096));
272  free4096.reserve(BLOCKS4096);
273  unsigned char* block_start = mem4096.back();
274  for (uint i = 0; i < BLOCKS4096; ++i)
275  free4096.push_back(i*4096 + block_start);
276  }
277 
278  unsigned char *ptr = free4096.back();
279  free4096.pop_back();
280  alloc4096[ptr] = true;
281  return ptr;
282 }
283 #undef BLOCKS4096
284 
285 static bool is_4096_block(unsigned char* ptr)
286 {
287  return alloc4096.find(ptr) != alloc4096.end();
288 }
289 
290 static void return_4096_block(unsigned char* ptr)
291 {
292  alloc4096.erase(ptr);
293  free4096.push_back(ptr);
294 
295 #if 0 // enable this to debug memory leaks
296  LOG(VB_GENERAL, LOG_DEBUG, QString("%1 4096 blocks remain")
297  .arg(alloc4096.size()));
298  map<unsigned char*, bool>::iterator it;
299  for (it = alloc4096.begin(); it != alloc4096.end(); ++it)
300  {
301  TSPacket *ts = (TSPacket*) it->first;
302  LGO(VB_GENERAL, LOG_DEBUG, QString("PES Packet: pid(0x%1)")
303  .arg(ts->PID(),0,16));
304  if (ts->PID() == 0x1ffb)
305  {
306  LOG(VB_GENERAL, LOG_DEBUG, QString(" tid(0x%1) ext(0x%2)")
307  .arg(PSIPTable(*ts).TableID(),0,16)
308  .arg(PSIPTable(*ts).TableIDExtension(),0,16));
309  }
310  }
311 #endif
312 
313  // free the allocator only if more than 1 block was used
314  if (alloc4096.empty() && mem4096.size() > 1)
315  {
316  vector<unsigned char*>::iterator it;
317  for (it = mem4096.begin(); it != mem4096.end(); ++it)
318  free(*it);
319  mem4096.clear();
320  free4096.clear();
321 #if 0
322  LOG(VB_GENERAL, LOG_DEBUG, "freeing all 4096 blocks");
323 #endif
324  }
325 }
326 #endif
327 
328 static QMutex pes_alloc_mutex;
329 
330 unsigned char *pes_alloc(uint size)
331 {
332  QMutexLocker locker(&pes_alloc_mutex);
333 #ifndef USING_VALGRIND
334  if (size <= 188)
335  return get_188_block();
336  if (size <= 4096)
337  return get_4096_block();
338 #endif // USING_VALGRIND
339  return (unsigned char*) malloc(size);
340 }
341 
342 void pes_free(unsigned char *ptr)
343 {
344  QMutexLocker locker(&pes_alloc_mutex);
345 #ifndef USING_VALGRIND
346  if (is_188_block(ptr))
347  return_188_block(ptr);
348  else if (is_4096_block(ptr))
349  return_4096_block(ptr);
350  else
351 #endif // USING_VALGRIND
352  free(ptr);
353 }
Used to access the data of a Transport Stream packet.
Definition: tspacket.h:166
static const unsigned int kHeaderSize
Definition: tspacket.h:155
static bool is_188_block(unsigned char *ptr)
Definition: pespacket.cpp:243
static vector< unsigned char * > free188
Definition: pespacket.cpp:217
Definition: cc.h:13
#define BLOCKS4096
Definition: pespacket.cpp:266
static unsigned char * get_188_block()
Definition: pespacket.cpp:225
uint TableIDExtension(void) const
Definition: mpegtables.h:496
static map< unsigned char *, bool > alloc188
Definition: pespacket.cpp:218
static void return_188_block(unsigned char *ptr)
Definition: pespacket.cpp:248
unsigned int ContinuityCounter(void) const
Definition: tspacket.h:87
static vector< unsigned char * > mem188
Definition: pespacket.cpp:216
unsigned char * pes_alloc(uint size)
Definition: pespacket.cpp:330
uint CalcCRC(void) const
Definition: pespacket.cpp:145
void SetContinuityCounter(unsigned int cc)
Definition: tspacket.h:148
Used to access header of a TSPacket.
Definition: tspacket.h:24
static const unsigned int kPayloadSize
Definition: tspacket.h:221
bool PayloadStart(void) const
Definition: tspacket.h:67
A PSIP table is a variant of a PES packet containing an MPEG, ATSC or DVB table.
Definition: mpegtables.h:371
bool AddTSPacket(const TSPacket *tspacket, bool &broken)
Definition: pespacket.cpp:21
#define BLOCKS188
Definition: pespacket.cpp:224
static QMutex pes_alloc_mutex
Definition: pespacket.cpp:328
unsigned int uint
Definition: compat.h:140
static vector< unsigned char * > mem4096
Definition: pespacket.cpp:220
static const float mpeg1_aspect[16]
Definition: pespacket.h:246
#define INCR_CC(_CC_)
const unsigned char * data(void) const
Definition: tspacket.h:152
float aspect(bool mpeg1) const
Returns the screen aspect ratio.
Definition: pespacket.cpp:194
void SetPID(unsigned int pid)
Definition: tspacket.h:138
static bool is_4096_block(unsigned char *ptr)
Definition: pespacket.cpp:285
uint TableID(void) const
Definition: mpegtables.h:479
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
static const unsigned int kSize
Definition: tspacket.h:220
void pes_free(unsigned char *ptr)
Definition: pespacket.cpp:342
unsigned int PID(void) const
Definition: tspacket.h:71
void GetAsTSPackets(vector< TSPacket > &output, uint cc) const
Returns payload only PESPacket as series of TSPackets.
Definition: pespacket.cpp:104
static const float mpeg2_aspect[16]
The negative values are screen aspect ratios, while the positive ones are pixel aspect ratios.
Definition: pespacket.h:247
bool VerifyCRC(void) const
Definition: pespacket.cpp:153
Contains listing of PMT Stream ID's for various A/V Stream types.
Definition: mpegtables.h:106
static map< unsigned char *, bool > alloc4096
Definition: pespacket.cpp:222
static unsigned char * get_4096_block()
Definition: pespacket.cpp:267
static vector< unsigned char * > free4096
Definition: pespacket.cpp:221
static const float mpeg2_fps[16]
Definition: pespacket.h:248
#define output
static void return_4096_block(unsigned char *ptr)
Definition: pespacket.cpp:290