00001
00002
00003 #include "mythlogging.h"
00004 #include "pespacket.h"
00005 #include "mpegtables.h"
00006
00007 extern "C" {
00008 #include "mythconfig.h"
00009 #include "libavcodec/avcodec.h"
00010 #include "libavformat/avformat.h"
00011 #include "libavutil/crc.h"
00012 #include "libavutil/bswap.h"
00013 }
00014
00015 #include <vector>
00016 #include <map>
00017
00018 using namespace std;
00019
00020
00021 bool PESPacket::AddTSPacket(const TSPacket* packet, bool &broken)
00022 {
00023 broken = true;
00024 if (!tsheader()->PayloadStart())
00025 {
00026 LOG(VB_RECORD, LOG_ERR,
00027 "Error: We started a PES packet, without a payloadStart!");
00028 return true;
00029 }
00030 else if (!IsClone())
00031 {
00032 LOG(VB_RECORD, LOG_ERR,
00033 "Error: Must clone initially to use addPackets()");
00034 return false;
00035 }
00036
00037 const int cc = packet->ContinuityCounter();
00038 const int ccExp = (_ccLast + 1) & 0xf;
00039 uint payloadSize = TSPacket::kPayloadSize;
00040 uint payloadStart = TSPacket::kHeaderSize;
00041
00042
00043
00044 if (packet->PayloadStart())
00045 {
00046 payloadSize--;
00047 payloadStart++;
00048 }
00049
00050 if (ccExp == cc)
00051 {
00052 if (_pesdataSize + payloadSize >= _allocSize)
00053 {
00054 uint sz = (((_allocSize * 2) + 4095) / 4096) * 4096;
00055 unsigned char *nbuf = pes_alloc(sz);
00056 memcpy(nbuf, _fullbuffer, _pesdataSize);
00057 pes_free(_fullbuffer);
00058 _fullbuffer = nbuf;
00059 _pesdata = _fullbuffer + _psiOffset + 1;
00060 _allocSize = sz;
00061 }
00062
00063 memcpy(_fullbuffer + _pesdataSize,
00064 packet->data() + payloadStart,
00065 payloadSize);
00066
00067 _ccLast = cc;
00068 _pesdataSize += payloadSize;
00069 }
00070 else if (int(_ccLast) == cc)
00071 {
00072
00073 }
00074 else
00075 {
00076 LOG(VB_RECORD, LOG_ERR,
00077 "AddTSPacket: Out of sync!!! Need to wait for next payloadStart" +
00078 QString(" PID: 0x%1, continuity counter: %2 (expected %3).")
00079 .arg(packet->PID(),0,16).arg(cc).arg(ccExp));
00080 return true;
00081 }
00082
00083
00084 broken = false;
00085
00086 if ((_psiOffset + 1 + 3) <= _pesdataSize)
00087 {
00088
00089 uint tlen = Length() + (_pesdata - _fullbuffer) +3;
00090
00091 if (_pesdataSize >= tlen)
00092 {
00093 _badPacket = !VerifyCRC();
00094 return true;
00095 }
00096 }
00097
00098 return false;
00099 }
00100
00104 void PESPacket::GetAsTSPackets(vector<TSPacket> &output, uint cc) const
00105 {
00106 #define INCR_CC(_CC_) do { _CC_ = (_CC_ + 1) & 0xf; } while (0)
00107 uint last_byte_of_pesdata = Length() + 4 - 1;
00108 uint size = last_byte_of_pesdata + _pesdata - _fullbuffer;
00109
00110 if (_pesdata == _fullbuffer)
00111 {
00112 LOG(VB_GENERAL, LOG_ERR, "WriteAsTSPackets _pesdata == _fullbuffer");
00113 output.resize(0);
00114 return;
00115 }
00116
00117 output.resize(1);
00118 memcpy(output[0].data(), _fullbuffer, TSPacket::kSize);
00119 output[0].data()[3] = (output[0].data()[3] & 0xf0) | cc;
00120 if (size <= TSPacket::kSize)
00121 return;
00122
00123 TSHeader header;
00124 header.data()[1] = 0x00;
00125 header.data()[2] = 0x00;
00126 header.data()[3] = 0x10;
00127 header.SetPID(tsheader()->PID());
00128
00129 const unsigned char *data = _fullbuffer + TSPacket::kSize;
00130 size -= TSPacket::kSize;
00131 while (size > 0)
00132 {
00133 INCR_CC(cc);
00134 header.SetContinuityCounter(cc);
00135 output.resize(output.size()+1);
00136 output[output.size()-1].InitHeader(header.data());
00137 uint write_size = min(size, TSPacket::kPayloadSize);
00138 output[output.size()-1].InitPayload(data, write_size);
00139 data += write_size;
00140 size -= write_size;
00141 }
00142 #undef INCR_CC
00143 }
00144
00145 uint PESPacket::CalcCRC(void) const
00146 {
00147 if (Length() < 1)
00148 return 0xffffffff;
00149 return av_bswap32(av_crc(av_crc_get_table(AV_CRC_32_IEEE), (uint32_t) -1,
00150 _pesdata, Length() - 1));
00151 }
00152
00153 bool PESPacket::VerifyCRC(void) const
00154 {
00155 bool ret = !HasCRC() || (CalcCRC() == CRC());
00156 if (!ret)
00157 {
00158 LOG(VB_SIPARSER, LOG_INFO,
00159 QString("PESPacket: Failed CRC check 0x%1 != 0x%2 "
00160 "for StreamID = 0x%3")
00161 .arg(CRC(),0,16).arg(CalcCRC(),0,16).arg(StreamID(),0,16));
00162 }
00163 return ret;
00164 }
00165
00166
00167 const float SequenceHeader::mpeg1_aspect[16] =
00168 {
00169 0.0000f, 1.0000f, 0.6735f, 0.7031f,
00170 0.7615f, 0.8055f, 0.8437f, 0.8935f,
00171 0.9157f, 0.9815f, 1.0255f, 1.0695f,
00172 1.0950f, 1.1575f, 1.2015f, 0.0000f,
00173 };
00174
00177 const float SequenceHeader::mpeg2_aspect[16] =
00178 {
00179 0.0000f, 1.0000f, -3.0/4.0, -9.0/16.0,
00180 -1.0/2.21, 0.0000f, 0.0000f, 0.0000f,
00181 0.0000f, 0.0000f, 0.0000f, 0.0000f,
00182 0.0000f, 0.0000f, 0.0000f, 0.0000f,
00183 };
00184
00185 const float SequenceHeader::mpeg2_fps[16] =
00186 {
00187 0.0f, 24000/1001.0f, 24.0f, 25.0f,
00188 30000/1001.0f, 30.0f, 50.0f, 60000/1001.0f,
00189 60.0f, 1.0f, 1.0f, 1.0f,
00190 1.0f, 1.0f, 1.0f, 1.0f,
00191 };
00192
00194 float SequenceHeader::aspect(bool mpeg1) const
00195 {
00196 if (!height())
00197 return 1.0f;
00198
00199 uint index = aspectNum();
00200 float aspect = (mpeg1) ? mpeg1_aspect[index] : mpeg2_aspect[index];
00201
00202 float retval = 0.0f;
00203 retval = (aspect > 0.0f) ? width() / (aspect * height()) : retval;
00204 retval = (aspect < 0.0f) ? -1.0f / aspect : retval;
00205 retval = (retval <= 0.0f) ? width() * 1.0f / height() : retval;
00206 return retval;
00207 }
00208
00209
00210
00212
00214
00215 static vector<unsigned char*> mem188;
00216 static vector<unsigned char*> free188;
00217 static map<unsigned char*, bool> alloc188;
00218
00219 static vector<unsigned char*> mem4096;
00220 static vector<unsigned char*> free4096;
00221 static map<unsigned char*, bool> alloc4096;
00222
00223 #define BLOCKS188 512
00224 static unsigned char* get_188_block()
00225 {
00226 if (free188.empty())
00227 {
00228 mem188.push_back((unsigned char*) malloc(188 * BLOCKS188));
00229 free188.reserve(BLOCKS188);
00230 unsigned char* block_start = mem188.back();
00231 for (uint i = 0; i < BLOCKS188; ++i)
00232 free188.push_back(i*188 + block_start);
00233 }
00234
00235 unsigned char *ptr = free188.back();
00236 free188.pop_back();
00237 alloc188[ptr] = true;
00238 return ptr;
00239 }
00240 #undef BLOCKS188
00241
00242 static bool is_188_block(unsigned char* ptr)
00243 {
00244 return alloc188.find(ptr) != alloc188.end();
00245 }
00246
00247 static void return_188_block(unsigned char* ptr)
00248 {
00249 alloc188.erase(ptr);
00250 free188.push_back(ptr);
00251
00252 if (alloc188.empty() && mem188.size() > 1)
00253 {
00254 vector<unsigned char*>::iterator it;
00255 for (it = mem188.begin(); it != mem188.end(); ++it)
00256 free(*it);
00257 mem188.clear();
00258 free188.clear();
00259 #if 0
00260 LOG(VB_GENERAL, LOG_DEBUG, "freeing all 188 blocks");
00261 #endif
00262 }
00263 }
00264
00265 #define BLOCKS4096 128
00266 static unsigned char* get_4096_block()
00267 {
00268 if (free4096.empty())
00269 {
00270 mem4096.push_back((unsigned char*) malloc(4096 * BLOCKS4096));
00271 free4096.reserve(BLOCKS4096);
00272 unsigned char* block_start = mem4096.back();
00273 for (uint i = 0; i < BLOCKS4096; ++i)
00274 free4096.push_back(i*4096 + block_start);
00275 }
00276
00277 unsigned char *ptr = free4096.back();
00278 free4096.pop_back();
00279 alloc4096[ptr] = true;
00280 return ptr;
00281 }
00282 #undef BLOCKS4096
00283
00284 static bool is_4096_block(unsigned char* ptr)
00285 {
00286 return alloc4096.find(ptr) != alloc4096.end();
00287 }
00288
00289 static void return_4096_block(unsigned char* ptr)
00290 {
00291 alloc4096.erase(ptr);
00292 free4096.push_back(ptr);
00293
00294 #if 0 // enable this to debug memory leaks
00295 LOG(VB_GENERAL, LOG_DEBUG, QString("%1 4096 blocks remain")
00296 .arg(alloc4096.size()));
00297 map<unsigned char*, bool>::iterator it;
00298 for (it = alloc4096.begin(); it != alloc4096.end(); ++it)
00299 {
00300 TSPacket *ts = (TSPacket*) it->first;
00301 LGO(VB_GENERAL, LOG_DEBUG, QString("PES Packet: pid(0x%1)")
00302 .arg(ts->PID(),0,16));
00303 if (ts->PID() == 0x1ffb)
00304 {
00305 LOG(VB_GENERAL, LOG_DEBUG, QString(" tid(0x%1) ext(0x%2)")
00306 .arg(PSIPTable::View(*ts).TableID(),0,16)
00307 .arg(PSIPTable::View(*ts).TableIDExtension(),0,16));
00308 }
00309 }
00310 #endif
00311
00312
00313 if (alloc4096.empty() && mem4096.size() > 1)
00314 {
00315 vector<unsigned char*>::iterator it;
00316 for (it = mem4096.begin(); it != mem4096.end(); ++it)
00317 free(*it);
00318 mem4096.clear();
00319 free4096.clear();
00320 #if 0
00321 LOG(VB_GENERAL, LOG_DEBUG, "freeing all 4096 blocks");
00322 #endif
00323 }
00324 }
00325
00326 static QMutex pes_alloc_mutex;
00327
00328 unsigned char *pes_alloc(uint size)
00329 {
00330 QMutexLocker locker(&pes_alloc_mutex);
00331 #ifndef USING_VALGRIND
00332 if (size <= 188)
00333 return get_188_block();
00334 else if (size <= 4096)
00335 return get_4096_block();
00336 #endif // USING_VALGRIND
00337 return (unsigned char*) malloc(size);
00338 }
00339
00340 void pes_free(unsigned char *ptr)
00341 {
00342 QMutexLocker locker(&pes_alloc_mutex);
00343 #ifndef USING_VALGRIND
00344 if (is_188_block(ptr))
00345 return_188_block(ptr);
00346 else if (is_4096_block(ptr))
00347 return_4096_block(ptr);
00348 else
00349 #endif // USING_VALGRIND
00350 free(ptr);
00351 }