1 #include <lib/dvb/tstools.h>
2 #include <lib/base/eerror.h>
8 eDVBTSTools::eDVBTSTools()
11 m_maxrange = 256*1024;
20 eDVBTSTools::~eDVBTSTools()
25 int eDVBTSTools::openFile(const char *filename)
29 m_streaminfo.load((std::string(filename) + ".ap").c_str());
31 if (!m_streaminfo.empty())
35 eDebug("no recorded stream information available");
41 if (m_file.open(filename, 1) < 0)
46 void eDVBTSTools::closeFile()
51 void eDVBTSTools::setSyncPID(int pid)
56 void eDVBTSTools::setSearchRange(int maxrange)
58 m_maxrange = maxrange;
61 /* getPTS extracts a pts value from any PID at a given offset. */
62 int eDVBTSTools::getPTS(off_t &offset, pts_t &pts, int fixed)
65 return m_streaminfo.getPTS(offset, pts);
70 offset -= offset % 188;
72 if (m_file.lseek(offset, SEEK_SET) < 0)
75 int left = m_maxrange;
79 unsigned char block[188];
80 if (m_file.read(block, 188) != 188)
97 offset = m_file.lseek(i - 188, SEEK_CUR);
101 int pid = ((block[1] << 8) | block[2]) & 0x1FFF;
102 int pusi = !!(block[1] & 0x40);
104 // printf("PID %04x, PUSI %d\n", pid, pusi);
112 /* ok, now we have a PES header */
115 /* check for adaption field */
117 pes = block + block[4] + 4 + 1;
121 /* somehow not a startcode. (this is invalid, since pusi was set.) ignore it. */
122 if (pes[0] || pes[1] || (pes[2] != 1))
125 if (pes[7] & 0x80) /* PTS */
127 pts = ((unsigned long long)(pes[ 9]&0xE)) << 29;
128 pts |= ((unsigned long long)(pes[10]&0xFF)) << 22;
129 pts |= ((unsigned long long)(pes[11]&0xFE)) << 14;
130 pts |= ((unsigned long long)(pes[12]&0xFF)) << 7;
131 pts |= ((unsigned long long)(pes[13]&0xFE)) >> 1;
134 // eDebug("found pts %08llx at %08llx", pts, offset);
136 /* convert to zero-based */
138 fixupPTS(offset, pts);
146 int eDVBTSTools::fixupPTS(const off_t &offset, pts_t &now)
148 if (m_use_streaminfo)
150 return m_streaminfo.fixupPTS(offset, now);
153 /* for the simple case, we assume one epoch, with up to one wrap around in the middle. */
157 eDebug("begin not valid, can't fixup");
161 pts_t pos = m_pts_begin;
162 if ((now < pos) && ((pos - now) < 90000 * 10))
168 if (now < pos) /* wrap around */
169 now = now + 0x200000000LL - pos;
176 int eDVBTSTools::getOffset(off_t &offset, pts_t &pts)
178 if (m_use_streaminfo)
180 offset = m_streaminfo.getAccessPoint(pts);
184 // eDebug("get offset");
185 if (!m_samples_taken)
188 if (!m_samples.empty())
190 // eDebug("ok, samples ok");
191 /* search entry before and after */
192 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(pts);
193 std::map<pts_t, off_t>::const_iterator u = l;
195 if (l != m_samples.begin())
198 if ((u != m_samples.end()) && (l != m_samples.end()))
200 pts_t pts_diff = u->first - l->first;
201 off_t offset_diff = u->second - l->second;
202 // eDebug("using: %llx:%llx -> %llx:%llx", l->first, u->first, l->second, u->second);
206 int bitrate = offset_diff * 90000 * 8 / pts_diff;
210 offset += ((pts - l->first) * (pts_t)bitrate) / 8ULL / 90000ULL;
211 offset -= offset % 188;
218 eDebug("falling back");
219 int bitrate = calcBitrate();
220 offset = pts * (pts_t)bitrate / 8ULL / 90000ULL;
221 offset -= offset % 188;
227 int eDVBTSTools::getNextAccessPoint(pts_t &ts, const pts_t &start, int direction)
229 if (m_use_streaminfo)
230 return m_streaminfo.getNextAccessPoint(ts, start, direction);
233 eDebug("can't get next access point without streaminfo");
238 void eDVBTSTools::calcBegin()
246 if (!getPTS(m_offset_begin, m_pts_begin))
251 void eDVBTSTools::calcEnd()
256 off_t end = m_file.lseek(0, SEEK_END);
258 if (abs(end - m_offset_end) > 1*1024*1024)
262 eDebug("file size changed, recalc length");
272 m_offset_end -= m_maxrange;
273 if (m_offset_end < 0)
275 if (!getPTS(m_offset_end, m_pts_end))
282 int eDVBTSTools::calcLen(pts_t &len)
284 calcBegin(); calcEnd();
285 if (!(m_begin_valid && m_end_valid))
287 len = m_pts_end - m_pts_begin;
290 len += 0x200000000LL;
294 int eDVBTSTools::calcBitrate()
296 calcBegin(); calcEnd();
297 if (!(m_begin_valid && m_end_valid))
300 pts_t len_in_pts = m_pts_end - m_pts_begin;
304 len_in_pts += 0x200000000LL;
305 off_t len_in_bytes = m_offset_end - m_offset_begin;
310 unsigned long long bitrate = len_in_bytes * 90000 * 8 / len_in_pts;
311 if ((bitrate < 10000) || (bitrate > 100000000))
318 void eDVBTSTools::takeSamples()
323 if (calcLen(dummy) == -1)
327 off_t bytes_per_sample = (m_offset_end - m_offset_begin) / (long long)nr_samples;
328 if (bytes_per_sample < 40*1024*1024)
329 bytes_per_sample = 40*1024*1024;
331 bytes_per_sample -= bytes_per_sample % 188;
333 for (off_t offset = m_offset_begin; offset < m_offset_end; offset += bytes_per_sample)
337 if (!eDVBTSTools::getPTS(o, p, 1))
339 // eDebug("sample: %llx, %llx", o, p);
343 m_samples[m_pts_begin] = m_offset_begin;
344 m_samples[m_pts_end] = m_offset_end;
345 // eDebug("begin, end: %llx %llx", m_offset_begin, m_offset_end);
348 int eDVBTSTools::findPMT(int &pmt_pid, int &service_id)
350 /* FIXME: this will be factored out soon! */
353 eDebug(" file not valid");
357 if (m_file.lseek(0, SEEK_SET) < 0)
359 eDebug("seek failed");
363 int left = 5*1024*1024;
367 unsigned char block[188];
368 if (m_file.read(block, 188) != 188)
370 eDebug("read error");
375 if (block[0] != 0x47)
380 if (block[i] == 0x47)
384 m_file.lseek(i - 188, SEEK_CUR);
388 int pid = ((block[1] << 8) | block[2]) & 0x1FFF;
390 int pusi = !!(block[1] & 0x40);
395 /* ok, now we have a PES header or section header*/
398 /* check for adaption field */
400 sec = block + block[4] + 4 + 1;
404 if (sec[0]) /* table pointer, assumed to be 0 */
407 if (sec[1] == 0x02) /* program map section */
410 service_id = (sec[4] << 8) | sec[5];