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)
214 if (m_use_streaminfo)
216 offset = m_streaminfo.getAccessPoint(pts);
220 calcBegin(); calcEnd();
227 if (!m_samples_taken)
230 if (!m_samples.empty())
237 /* search entry before and after */
238 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(pts);
239 std::map<pts_t, off_t>::const_iterator u = l;
241 if (l != m_samples.begin())
244 /* we could have seeked beyond the end */
245 if (u == m_samples.end())
247 /* use last segment for interpolation. */
248 if (l != m_samples.begin())
255 /* if we don't have enough points */
256 if (u == m_samples.end())
259 pts_t pts_diff = u->first - l->first;
260 off_t offset_diff = u->second - l->second;
264 eDebug("something went wrong when taking samples.");
270 eDebug("using: %llx:%llx -> %llx:%llx", l->first, u->first, l->second, u->second);
275 bitrate = offset_diff * 90000 * 8 / pts_diff;
280 offset += ((pts - l->first) * (pts_t)bitrate) / 8ULL / 90000ULL;
281 offset -= offset % 188;
285 if (!takeSample(offset, p))
287 int diff = (p - pts) / 90;
289 eDebug("calculated diff %d ms", diff);
292 eDebug("diff to big, refining");
296 eDebug("no sample taken, refinement not possible.");
301 /* if even the first sample couldn't be taken, fall back. */
302 /* otherwise, return most refined result. */
306 eDebug("aborting. Taking %llx as offset for %lld", offset, pts);
311 int bitrate = calcBitrate();
312 offset = pts * (pts_t)bitrate / 8ULL / 90000ULL;
313 eDebug("fallback, bitrate=%d, results in %016llx", bitrate, offset);
314 offset -= offset % 188;
320 int eDVBTSTools::getNextAccessPoint(pts_t &ts, const pts_t &start, int direction)
322 if (m_use_streaminfo)
323 return m_streaminfo.getNextAccessPoint(ts, start, direction);
326 eDebug("can't get next access point without streaminfo");
331 void eDVBTSTools::calcBegin()
336 if (!(m_begin_valid || m_futile))
339 if (!getPTS(m_offset_begin, m_pts_begin))
346 void eDVBTSTools::calcEnd()
351 off_t end = m_file.lseek(0, SEEK_END);
353 if (llabs(end - m_last_filelength) > 1*1024*1024)
355 m_last_filelength = end;
359 // eDebug("file size changed, recalc length");
364 m_offset_end = m_last_filelength;
366 while (!(m_end_valid || m_futile))
374 m_offset_end -= m_maxrange;
375 if (m_offset_end < 0)
378 /* restore offset if getpts fails */
379 off_t off = m_offset_end;
381 if (!getPTS(m_offset_end, m_pts_end))
394 int eDVBTSTools::calcLen(pts_t &len)
396 calcBegin(); calcEnd();
397 if (!(m_begin_valid && m_end_valid))
399 len = m_pts_end - m_pts_begin;
402 len += 0x200000000LL;
406 int eDVBTSTools::calcBitrate()
408 calcBegin(); calcEnd();
409 if (!(m_begin_valid && m_end_valid))
412 pts_t len_in_pts = m_pts_end - m_pts_begin;
416 len_in_pts += 0x200000000LL;
417 off_t len_in_bytes = m_offset_end - m_offset_begin;
422 unsigned long long bitrate = len_in_bytes * 90000 * 8 / len_in_pts;
423 if ((bitrate < 10000) || (bitrate > 100000000))
430 void eDVBTSTools::takeSamples()
435 if (calcLen(dummy) == -1)
439 off_t bytes_per_sample = (m_offset_end - m_offset_begin) / (long long)nr_samples;
440 if (bytes_per_sample < 40*1024*1024)
441 bytes_per_sample = 40*1024*1024;
443 bytes_per_sample -= bytes_per_sample % 188;
445 for (off_t offset = m_offset_begin; offset < m_offset_end; offset += bytes_per_sample)
448 takeSample(offset, p);
450 m_samples[0] = m_offset_begin;
451 m_samples[m_pts_end - m_pts_begin] = m_offset_end;
453 // eDebug("begin, end: %llx %llx", m_offset_begin, m_offset_end);
456 /* returns 0 when a sample was taken. */
457 int eDVBTSTools::takeSample(off_t off, pts_t &p)
459 if (!eDVBTSTools::getPTS(off, p, 1))
461 /* as we are happily mixing PTS and PCR values (no comment, please), we might
462 end up with some "negative" segments.
464 so check if this new sample is between the previous and the next field*/
466 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(p);
467 std::map<pts_t, off_t>::const_iterator u = l;
469 if (l != m_samples.begin())
472 if (u != m_samples.end())
474 if ((l->second > off) || (u->second < off))
476 eDebug("ignoring sample %llx %llx %llx (%lld %lld %lld)",
477 l->second, off, u->second, l->first, p, u->first);
490 int eDVBTSTools::findPMT(int &pmt_pid, int &service_id)
492 /* FIXME: this will be factored out soon! */
495 eDebug(" file not valid");
499 if (m_file.lseek(0, SEEK_SET) < 0)
501 eDebug("seek failed");
505 int left = 5*1024*1024;
509 unsigned char packet[188];
510 if (m_file.read(packet, 188) != 188)
512 eDebug("read error");
517 if (packet[0] != 0x47)
522 if (packet[i] == 0x47)
526 m_file.lseek(i - 188, SEEK_CUR);
530 int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
532 int pusi = !!(packet[1] & 0x40);
537 /* ok, now we have a PES header or section header*/
540 /* check for adaption field */
541 if (packet[3] & 0x20)
543 if (packet[4] >= 183)
545 sec = packet + packet[4] + 4 + 1;
549 if (sec[0]) /* table pointer, assumed to be 0 */
552 if (sec[1] == 0x02) /* program map section */
555 service_id = (sec[4] << 8) | sec[5];