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
8extern "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
20bool 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 {
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
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
133void 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);
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
180bool 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
193bool 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
234float 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#if !CONFIG_VALGRIND
256static std::vector<unsigned char*> mem188;
257static std::vector<unsigned char*> free188;
258static std::map<unsigned char*, bool> alloc188;
259
260static std::vector<unsigned char*> mem4096;
261static std::vector<unsigned char*> free4096;
262static std::map<unsigned char*, bool> alloc4096;
263
264static constexpr size_t BLOCKS188 { 512 };
265static 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
282static bool is_188_block(unsigned char* ptr)
283{
284 return alloc188.find(ptr) != alloc188.end();
285}
286
287static 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
305static constexpr size_t BLOCKS4096 { 128 };
306static 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
323static bool is_4096_block(unsigned char* ptr)
324{
325 return alloc4096.find(ptr) != alloc4096.end();
326}
327
328static 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
366static QMutex pes_alloc_mutex;
367
368unsigned char *pes_alloc(uint size)
369{
370 QMutexLocker locker(&pes_alloc_mutex);
371#if !CONFIG_VALGRIND
372 if (size <= 188)
373 return get_188_block();
374 if (size <= 4096)
375 return get_4096_block();
376#endif // CONFIG_VALGRIND
377 return (unsigned char*) malloc(size);
378}
379
380void pes_free(unsigned char *ptr)
381{
382 QMutexLocker locker(&pes_alloc_mutex);
383#if !CONFIG_VALGRIND
384 if (is_188_block(ptr))
385 return_188_block(ptr);
386 else if (is_4096_block(ptr))
388 else
389#endif // CONFIG_VALGRIND
390 free(ptr);
391}
bool VerifyCRC(void) const
Definition: pespacket.cpp:180
bool AddTSPacket(const TSPacket *tspacket, int cardid, bool &broken)
Definition: pespacket.cpp:20
const unsigned char * data() const
Definition: pespacket.h:167
static const uint kTheMagicNoCRCCRC
Definition: pespacket.h:230
unsigned char * m_pesData
Pointer to PES data in full buffer.
Definition: pespacket.h:219
uint CalcCRC(void) const
Definition: pespacket.cpp:172
uint m_psiOffset
AFCOffset + StartOfFieldPointer.
Definition: pespacket.h:222
uint m_pesDataSize
Number of data bytes (TS header + PES data)
Definition: pespacket.h:224
void GetAsTSPackets(std::vector< TSPacket > &output, uint cc) const
Returns payload only PESPacket as series of TSPackets.
Definition: pespacket.cpp:133
const TSHeader * tsheader() const
Definition: pespacket.h:90
uint m_allocSize
Total number of bytes we allocated.
Definition: pespacket.h:225
bool m_badPacket
true if a CRC is not good yet
Definition: pespacket.h:226
virtual bool HasCRC() const
1 bit Cyclic Redundancy Check present
Definition: pespacket.h:130
uint StreamID() const
Definition: pespacket.h:98
unsigned char * m_fullBuffer
Pointer to allocated data.
Definition: pespacket.h:220
uint m_ccLast
Continuity counter of last inserted TS Packet.
Definition: pespacket.h:223
bool IsClone() const
Definition: pespacket.h:83
uint CRC(void) const
Definition: pespacket.h:189
uint Length() const
Definition: pespacket.h:99
A PSIP table is a variant of a PES packet containing an MPEG, ATSC or DVB table.
Definition: mpegtables.h:410
uint TableID(void) const
Definition: mpegtables.h:496
uint TableIDExtension(void) const
Definition: mpegtables.h:515
uint width(void) const
Definition: pespacket.h:239
static const AspectArray kMpeg2Aspect
The negative values are screen aspect ratios, while the positive ones are pixel aspect ratios.
Definition: pespacket.h:252
static const AspectArray kMpeg1Aspect
Definition: pespacket.h:251
float aspect(bool mpeg1) const
Returns the screen aspect ratio.
Definition: pespacket.cpp:234
uint height(void) const
Definition: pespacket.h:240
uint aspectNum(void) const
Definition: pespacket.h:241
static const AspectArray kMpeg2Fps
Definition: pespacket.h:253
Used to access header of a TSPacket.
Definition: tspacket.h:47
bool HasAdaptationField(void) const
Definition: tspacket.h:113
unsigned int ContinuityCounter(void) const
Definition: tspacket.h:109
unsigned int PID(void) const
Definition: tspacket.h:93
static constexpr unsigned int kHeaderSize
Definition: tspacket.h:177
bool PayloadStart(void) const
Definition: tspacket.h:89
unsigned int AdaptationFieldControl(void) const
Definition: tspacket.h:103
void SetContinuityCounter(unsigned int cc)
Definition: tspacket.h:170
void SetPID(unsigned int pid)
Definition: tspacket.h:160
const unsigned char * data(void) const
Definition: tspacket.h:174
size_t AdaptationFieldSize(void) const
Definition: tspacket.h:114
Used to access the data of a Transport Stream packet.
Definition: tspacket.h:208
static constexpr unsigned int kPayloadSize
Definition: tspacket.h:262
static constexpr unsigned int kSize
Definition: tspacket.h:261
unsigned int uint
Definition: compat.h:68
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
static std::vector< unsigned char * > mem4096
Definition: pespacket.cpp:260
static bool is_188_block(unsigned char *ptr)
Definition: pespacket.cpp:282
void pes_free(unsigned char *ptr)
Definition: pespacket.cpp:380
static std::vector< unsigned char * > free188
Definition: pespacket.cpp:257
static unsigned char * get_188_block()
Definition: pespacket.cpp:265
static void return_4096_block(unsigned char *ptr)
Definition: pespacket.cpp:328
static bool is_4096_block(unsigned char *ptr)
Definition: pespacket.cpp:323
static constexpr size_t BLOCKS188
Definition: pespacket.cpp:264
static std::map< unsigned char *, bool > alloc188
Definition: pespacket.cpp:258
static std::map< unsigned char *, bool > alloc4096
Definition: pespacket.cpp:262
static std::vector< unsigned char * > free4096
Definition: pespacket.cpp:261
static constexpr size_t BLOCKS4096
Definition: pespacket.cpp:305
static unsigned char * get_4096_block()
Definition: pespacket.cpp:306
unsigned char * pes_alloc(uint size)
Definition: pespacket.cpp:368
static QMutex pes_alloc_mutex
Definition: pespacket.cpp:366
static std::vector< unsigned char * > mem188
Definition: pespacket.cpp:256
static void return_188_block(unsigned char *ptr)
Definition: pespacket.cpp:287
std::array< float, 16 > AspectArray
Definition: pespacket.h:13
#define output