1 #include <lib/dvb/tstools.h>
2 #include <lib/base/eerror.h>
8 eDVBTSTools::eDVBTSTools()
11 m_maxrange = 256*1024;
19 m_last_filelength = 0;
24 eDVBTSTools::~eDVBTSTools()
29 int eDVBTSTools::openFile(const char *filename)
33 m_streaminfo.load((std::string(filename) + ".ap").c_str());
35 if (!m_streaminfo.empty())
39 // eDebug("no recorded stream information available");
45 if (m_file.open(filename, 1) < 0)
50 void eDVBTSTools::closeFile()
55 void eDVBTSTools::setSyncPID(int pid)
60 void eDVBTSTools::setSearchRange(int maxrange)
62 m_maxrange = maxrange;
65 /* getPTS extracts a pts value from any PID at a given offset. */
66 int eDVBTSTools::getPTS(off_t &offset, pts_t &pts, int fixed)
69 return m_streaminfo.getPTS(offset, pts);
74 offset -= offset % 188;
76 if (m_file.lseek(offset, SEEK_SET) < 0)
79 int left = m_maxrange;
83 unsigned char block[188];
84 if (m_file.read(block, 188) != 188)
101 offset = m_file.lseek(i - 188, SEEK_CUR);
105 int pid = ((block[1] << 8) | block[2]) & 0x1FFF;
106 int pusi = !!(block[1] & 0x40);
108 // printf("PID %04x, PUSI %d\n", pid, pusi);
116 /* ok, now we have a PES header */
119 /* check for adaption field */
121 pes = block + block[4] + 4 + 1;
125 /* somehow not a startcode. (this is invalid, since pusi was set.) ignore it. */
126 if (pes[0] || pes[1] || (pes[2] != 1))
129 if (pes[7] & 0x80) /* PTS */
131 pts = ((unsigned long long)(pes[ 9]&0xE)) << 29;
132 pts |= ((unsigned long long)(pes[10]&0xFF)) << 22;
133 pts |= ((unsigned long long)(pes[11]&0xFE)) << 14;
134 pts |= ((unsigned long long)(pes[12]&0xFF)) << 7;
135 pts |= ((unsigned long long)(pes[13]&0xFE)) >> 1;
138 // eDebug("found pts %08llx at %08llx", pts, offset);
140 /* convert to zero-based */
142 fixupPTS(offset, pts);
150 int eDVBTSTools::fixupPTS(const off_t &offset, pts_t &now)
152 if (m_use_streaminfo)
154 return m_streaminfo.fixupPTS(offset, now);
157 /* for the simple case, we assume one epoch, with up to one wrap around in the middle. */
161 eDebug("begin not valid, can't fixup");
165 pts_t pos = m_pts_begin;
166 if ((now < pos) && ((pos - now) < 90000 * 10))
172 if (now < pos) /* wrap around */
173 now = now + 0x200000000LL - pos;
180 int eDVBTSTools::getOffset(off_t &offset, pts_t &pts)
182 if (m_use_streaminfo)
184 offset = m_streaminfo.getAccessPoint(pts);
188 // eDebug("get offset");
189 if (!m_samples_taken)
192 if (!m_samples.empty())
194 // eDebug("ok, samples ok");
195 /* search entry before and after */
196 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(pts);
197 std::map<pts_t, off_t>::const_iterator u = l;
199 if (l != m_samples.begin())
202 if ((u != m_samples.end()) && (l != m_samples.end()))
204 pts_t pts_diff = u->first - l->first;
205 off_t offset_diff = u->second - l->second;
206 // eDebug("using: %llx:%llx -> %llx:%llx", l->first, u->first, l->second, u->second);
210 int bitrate = offset_diff * 90000 * 8 / pts_diff;
214 offset += ((pts - l->first) * (pts_t)bitrate) / 8ULL / 90000ULL;
215 offset -= offset % 188;
222 eDebug("falling back");
223 int bitrate = calcBitrate();
224 offset = pts * (pts_t)bitrate / 8ULL / 90000ULL;
225 offset -= offset % 188;
231 int eDVBTSTools::getNextAccessPoint(pts_t &ts, const pts_t &start, int direction)
233 if (m_use_streaminfo)
234 return m_streaminfo.getNextAccessPoint(ts, start, direction);
237 eDebug("can't get next access point without streaminfo");
242 void eDVBTSTools::calcBegin()
247 if (!(m_begin_valid || m_futile))
250 if (!getPTS(m_offset_begin, m_pts_begin))
257 void eDVBTSTools::calcEnd()
262 off_t end = m_file.lseek(0, SEEK_END);
264 if (abs(end - m_last_filelength) > 1*1024*1024)
266 m_last_filelength = end;
270 // eDebug("file size changed, recalc length");
275 m_offset_end = m_last_filelength;
277 while (!(m_end_valid || m_futile))
285 m_offset_end -= m_maxrange;
286 if (m_offset_end < 0)
289 /* restore offset if getpts fails */
290 off_t off = m_offset_end;
292 if (!getPTS(m_offset_end, m_pts_end))
305 int eDVBTSTools::calcLen(pts_t &len)
307 calcBegin(); calcEnd();
308 if (!(m_begin_valid && m_end_valid))
310 len = m_pts_end - m_pts_begin;
313 len += 0x200000000LL;
317 int eDVBTSTools::calcBitrate()
319 calcBegin(); calcEnd();
320 if (!(m_begin_valid && m_end_valid))
323 pts_t len_in_pts = m_pts_end - m_pts_begin;
327 len_in_pts += 0x200000000LL;
328 off_t len_in_bytes = m_offset_end - m_offset_begin;
333 unsigned long long bitrate = len_in_bytes * 90000 * 8 / len_in_pts;
334 if ((bitrate < 10000) || (bitrate > 100000000))
341 void eDVBTSTools::takeSamples()
346 if (calcLen(dummy) == -1)
350 off_t bytes_per_sample = (m_offset_end - m_offset_begin) / (long long)nr_samples;
351 if (bytes_per_sample < 40*1024*1024)
352 bytes_per_sample = 40*1024*1024;
354 bytes_per_sample -= bytes_per_sample % 188;
356 for (off_t offset = m_offset_begin; offset < m_offset_end; offset += bytes_per_sample)
360 if (!eDVBTSTools::getPTS(o, p, 1))
362 // eDebug("sample: %llx, %llx", o, p);
366 m_samples[m_pts_begin] = m_offset_begin;
367 m_samples[m_pts_end] = m_offset_end;
368 // eDebug("begin, end: %llx %llx", m_offset_begin, m_offset_end);
371 int eDVBTSTools::findPMT(int &pmt_pid, int &service_id)
373 /* FIXME: this will be factored out soon! */
376 eDebug(" file not valid");
380 if (m_file.lseek(0, SEEK_SET) < 0)
382 eDebug("seek failed");
386 int left = 5*1024*1024;
390 unsigned char block[188];
391 if (m_file.read(block, 188) != 188)
393 eDebug("read error");
398 if (block[0] != 0x47)
403 if (block[i] == 0x47)
407 m_file.lseek(i - 188, SEEK_CUR);
411 int pid = ((block[1] << 8) | block[2]) & 0x1FFF;
413 int pusi = !!(block[1] & 0x40);
418 /* ok, now we have a PES header or section header*/
421 /* check for adaption field */
423 sec = block + block[4] + 4 + 1;
427 if (sec[0]) /* table pointer, assumed to be 0 */
430 if (sec[1] == 0x02) /* program map section */
433 service_id = (sec[4] << 8) | sec[5];