1 #define _ISOC99_SOURCE /* for llabs */
2 #include <lib/dvb/tstools.h>
3 #include <lib/base/eerror.h>
9 eDVBTSTools::eDVBTSTools()
12 m_maxrange = 256*1024;
20 m_last_filelength = 0;
25 eDVBTSTools::~eDVBTSTools()
30 int eDVBTSTools::openFile(const char *filename, int nostreaminfo)
35 m_streaminfo.load((std::string(filename) + ".ap").c_str());
37 if (!m_streaminfo.empty())
41 // eDebug("no recorded stream information available");
47 if (m_file.open(filename, 1) < 0)
52 void eDVBTSTools::closeFile()
57 void eDVBTSTools::setSyncPID(int pid)
62 void eDVBTSTools::setSearchRange(int maxrange)
64 m_maxrange = maxrange;
67 /* getPTS extracts a pts value from any PID at a given offset. */
68 int eDVBTSTools::getPTS(off_t &offset, pts_t &pts, int fixed)
71 return m_streaminfo.getPTS(offset, pts);
76 offset -= offset % 188;
78 if (m_file.lseek(offset, SEEK_SET) < 0)
80 eDebug("lseek failed");
84 int left = m_maxrange;
88 unsigned char packet[188];
89 if (m_file.read(packet, 188) != 188)
97 if (packet[0] != 0x47)
103 if (packet[i] == 0x47)
107 offset = m_file.lseek(i - 188, SEEK_CUR);
111 int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
112 int pusi = !!(packet[1] & 0x40);
114 // printf("PID %04x, PUSI %d\n", pid, pusi);
116 unsigned char *payload;
118 /* check for adaption field */
119 if (packet[3] & 0x20)
121 if (packet[4] >= 183)
125 if (packet[5] & 0x10) /* PCR present */
127 pts = ((unsigned long long)(packet[ 6]&0xFF)) << 25;
128 pts |= ((unsigned long long)(packet[ 7]&0xFF)) << 17;
129 pts |= ((unsigned long long)(packet[ 8]&0xFE)) << 9;
130 pts |= ((unsigned long long)(packet[ 9]&0xFF)) << 1;
131 pts |= ((unsigned long long)(packet[10]&0x80)) >> 7;
133 eDebug("PCR found at %llx: %16llx", offset, pts);
134 if (fixed && fixupPTS(offset, pts))
139 payload = packet + packet[4] + 4 + 1;
141 payload = packet + 4;
151 /* somehow not a startcode. (this is invalid, since pusi was set.) ignore it. */
152 if (payload[0] || payload[1] || (payload[2] != 1))
155 /* drop non-audio, non-video packets because other streams
156 can be non-compliant.*/
157 if (((payload[3] & 0xE0) != 0xC0) && // audio
158 ((payload[3] & 0xF0) != 0xE0)) // video
161 if (payload[7] & 0x80) /* PTS */
163 pts = ((unsigned long long)(payload[ 9]&0xE)) << 29;
164 pts |= ((unsigned long long)(payload[10]&0xFF)) << 22;
165 pts |= ((unsigned long long)(payload[11]&0xFE)) << 14;
166 pts |= ((unsigned long long)(payload[12]&0xFF)) << 7;
167 pts |= ((unsigned long long)(payload[13]&0xFE)) >> 1;
170 // eDebug("found pts %08llx at %08llx pid %02x stream: %02x", pts, offset, pid, payload[3]);
172 /* convert to zero-based */
173 if (fixed && fixupPTS(offset, pts))
182 int eDVBTSTools::fixupPTS(const off_t &offset, pts_t &now)
184 if (m_use_streaminfo)
186 return m_streaminfo.fixupPTS(offset, now);
189 /* for the simple case, we assume one epoch, with up to one wrap around in the middle. */
193 eDebug("begin not valid, can't fixup");
197 pts_t pos = m_pts_begin;
198 if ((now < pos) && ((pos - now) < 90000 * 10))
204 if (now < pos) /* wrap around */
205 now = now + 0x200000000LL - pos;
212 int eDVBTSTools::getOffset(off_t &offset, pts_t &pts, int marg)
214 if (m_use_streaminfo)
216 if (pts >= m_pts_end && marg > 0 && m_end_valid)
217 offset = m_offset_end;
219 offset = m_streaminfo.getAccessPoint(pts, marg);
223 calcBegin(); calcEnd();
230 if (!m_samples_taken)
233 if (!m_samples.empty())
240 /* search entry before and after */
241 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(pts);
242 std::map<pts_t, off_t>::const_iterator u = l;
244 if (l != m_samples.begin())
247 /* we could have seeked beyond the end */
248 if (u == m_samples.end())
250 /* use last segment for interpolation. */
251 if (l != m_samples.begin())
258 /* if we don't have enough points */
259 if (u == m_samples.end())
262 pts_t pts_diff = u->first - l->first;
263 off_t offset_diff = u->second - l->second;
267 eDebug("something went wrong when taking samples.");
273 eDebug("using: %llx:%llx -> %llx:%llx", l->first, u->first, l->second, u->second);
278 bitrate = offset_diff * 90000 * 8 / pts_diff;
283 offset += ((pts - l->first) * (pts_t)bitrate) / 8ULL / 90000ULL;
284 offset -= offset % 188;
288 if (!takeSample(offset, p))
290 int diff = (p - pts) / 90;
292 eDebug("calculated diff %d ms", diff);
295 eDebug("diff to big, refining");
299 eDebug("no sample taken, refinement not possible.");
304 /* if even the first sample couldn't be taken, fall back. */
305 /* otherwise, return most refined result. */
309 eDebug("aborting. Taking %llx as offset for %lld", offset, pts);
314 int bitrate = calcBitrate();
315 offset = pts * (pts_t)bitrate / 8ULL / 90000ULL;
316 eDebug("fallback, bitrate=%d, results in %016llx", bitrate, offset);
317 offset -= offset % 188;
323 int eDVBTSTools::getNextAccessPoint(pts_t &ts, const pts_t &start, int direction)
325 if (m_use_streaminfo)
326 return m_streaminfo.getNextAccessPoint(ts, start, direction);
329 eDebug("can't get next access point without streaminfo");
334 void eDVBTSTools::calcBegin()
339 if (!(m_begin_valid || m_futile))
342 if (!getPTS(m_offset_begin, m_pts_begin))
349 void eDVBTSTools::calcEnd()
354 off_t end = m_file.lseek(0, SEEK_END);
356 if (llabs(end - m_last_filelength) > 1*1024*1024)
358 m_last_filelength = end;
362 // eDebug("file size changed, recalc length");
367 m_offset_end = m_last_filelength;
369 while (!(m_end_valid || m_futile))
377 m_offset_end -= m_maxrange;
378 if (m_offset_end < 0)
381 /* restore offset if getpts fails */
382 off_t off = m_offset_end;
384 if (!getPTS(m_offset_end, m_pts_end))
397 int eDVBTSTools::calcLen(pts_t &len)
399 calcBegin(); calcEnd();
400 if (!(m_begin_valid && m_end_valid))
402 len = m_pts_end - m_pts_begin;
405 len += 0x200000000LL;
409 int eDVBTSTools::calcBitrate()
411 calcBegin(); calcEnd();
412 if (!(m_begin_valid && m_end_valid))
415 pts_t len_in_pts = m_pts_end - m_pts_begin;
419 len_in_pts += 0x200000000LL;
420 off_t len_in_bytes = m_offset_end - m_offset_begin;
425 unsigned long long bitrate = len_in_bytes * 90000 * 8 / len_in_pts;
426 if ((bitrate < 10000) || (bitrate > 100000000))
433 void eDVBTSTools::takeSamples()
438 if (calcLen(dummy) == -1)
442 off_t bytes_per_sample = (m_offset_end - m_offset_begin) / (long long)nr_samples;
443 if (bytes_per_sample < 40*1024*1024)
444 bytes_per_sample = 40*1024*1024;
446 bytes_per_sample -= bytes_per_sample % 188;
448 for (off_t offset = m_offset_begin; offset < m_offset_end; offset += bytes_per_sample)
451 takeSample(offset, p);
453 m_samples[0] = m_offset_begin;
454 m_samples[m_pts_end - m_pts_begin] = m_offset_end;
456 // eDebug("begin, end: %llx %llx", m_offset_begin, m_offset_end);
459 /* returns 0 when a sample was taken. */
460 int eDVBTSTools::takeSample(off_t off, pts_t &p)
462 if (!eDVBTSTools::getPTS(off, p, 1))
464 /* as we are happily mixing PTS and PCR values (no comment, please), we might
465 end up with some "negative" segments.
467 so check if this new sample is between the previous and the next field*/
469 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(p);
470 std::map<pts_t, off_t>::const_iterator u = l;
472 if (l != m_samples.begin())
475 if (u != m_samples.end())
477 if ((l->second > off) || (u->second < off))
479 eDebug("ignoring sample %llx %llx %llx (%lld %lld %lld)",
480 l->second, off, u->second, l->first, p, u->first);
493 int eDVBTSTools::findPMT(int &pmt_pid, int &service_id)
495 /* FIXME: this will be factored out soon! */
498 eDebug(" file not valid");
502 if (m_file.lseek(0, SEEK_SET) < 0)
504 eDebug("seek failed");
508 int left = 5*1024*1024;
512 unsigned char packet[188];
513 if (m_file.read(packet, 188) != 188)
515 eDebug("read error");
520 if (packet[0] != 0x47)
525 if (packet[i] == 0x47)
529 m_file.lseek(i - 188, SEEK_CUR);
533 int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
535 int pusi = !!(packet[1] & 0x40);
540 /* ok, now we have a PES header or section header*/
543 /* check for adaption field */
544 if (packet[3] & 0x20)
546 if (packet[4] >= 183)
548 sec = packet + packet[4] + 4 + 1;
552 if (sec[0]) /* table pointer, assumed to be 0 */
555 if (sec[1] == 0x02) /* program map section */
558 service_id = (sec[4] << 8) | sec[5];