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;
262 eDebug("using: %llx:%llx -> %llx:%llx", l->first, u->first, l->second, u->second);
267 bitrate = offset_diff * 90000 * 8 / pts_diff;
272 offset += ((pts - l->first) * (pts_t)bitrate) / 8ULL / 90000ULL;
273 offset -= offset % 188;
277 if (!takeSample(offset, p))
279 int diff = (p - pts) / 90;
281 eDebug("calculated diff %d ms", diff);
284 eDebug("diff to big, refining");
288 eDebug("no sample taken, refinement not possible.");
293 /* if even the first sample couldn't be taken, fall back. */
294 /* otherwise, return most refined result. */
302 int bitrate = calcBitrate();
303 offset = pts * (pts_t)bitrate / 8ULL / 90000ULL;
304 offset -= offset % 188;
310 int eDVBTSTools::getNextAccessPoint(pts_t &ts, const pts_t &start, int direction)
312 if (m_use_streaminfo)
313 return m_streaminfo.getNextAccessPoint(ts, start, direction);
316 eDebug("can't get next access point without streaminfo");
321 void eDVBTSTools::calcBegin()
326 if (!(m_begin_valid || m_futile))
329 if (!getPTS(m_offset_begin, m_pts_begin))
336 void eDVBTSTools::calcEnd()
341 off_t end = m_file.lseek(0, SEEK_END);
343 if (llabs(end - m_last_filelength) > 1*1024*1024)
345 m_last_filelength = end;
349 // eDebug("file size changed, recalc length");
354 m_offset_end = m_last_filelength;
356 while (!(m_end_valid || m_futile))
364 m_offset_end -= m_maxrange;
365 if (m_offset_end < 0)
368 /* restore offset if getpts fails */
369 off_t off = m_offset_end;
371 if (!getPTS(m_offset_end, m_pts_end))
384 int eDVBTSTools::calcLen(pts_t &len)
386 calcBegin(); calcEnd();
387 if (!(m_begin_valid && m_end_valid))
389 len = m_pts_end - m_pts_begin;
392 len += 0x200000000LL;
396 int eDVBTSTools::calcBitrate()
398 calcBegin(); calcEnd();
399 if (!(m_begin_valid && m_end_valid))
402 pts_t len_in_pts = m_pts_end - m_pts_begin;
406 len_in_pts += 0x200000000LL;
407 off_t len_in_bytes = m_offset_end - m_offset_begin;
412 unsigned long long bitrate = len_in_bytes * 90000 * 8 / len_in_pts;
413 if ((bitrate < 10000) || (bitrate > 100000000))
420 void eDVBTSTools::takeSamples()
425 if (calcLen(dummy) == -1)
429 off_t bytes_per_sample = (m_offset_end - m_offset_begin) / (long long)nr_samples;
430 if (bytes_per_sample < 40*1024*1024)
431 bytes_per_sample = 40*1024*1024;
433 bytes_per_sample -= bytes_per_sample % 188;
435 for (off_t offset = m_offset_begin; offset < m_offset_end; offset += bytes_per_sample)
438 takeSample(offset, p);
440 m_samples[0] = m_offset_begin;
441 m_samples[m_pts_end - m_pts_begin] = m_offset_end;
443 // eDebug("begin, end: %llx %llx", m_offset_begin, m_offset_end);
446 /* returns 0 when a sample was taken. */
447 int eDVBTSTools::takeSample(off_t off, pts_t &p)
449 if (!eDVBTSTools::getPTS(off, p, 1))
457 int eDVBTSTools::findPMT(int &pmt_pid, int &service_id)
459 /* FIXME: this will be factored out soon! */
462 eDebug(" file not valid");
466 if (m_file.lseek(0, SEEK_SET) < 0)
468 eDebug("seek failed");
472 int left = 5*1024*1024;
476 unsigned char packet[188];
477 if (m_file.read(packet, 188) != 188)
479 eDebug("read error");
484 if (packet[0] != 0x47)
489 if (packet[i] == 0x47)
493 m_file.lseek(i - 188, SEEK_CUR);
497 int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
499 int pusi = !!(packet[1] & 0x40);
504 /* ok, now we have a PES header or section header*/
507 /* check for adaption field */
508 if (packet[3] & 0x20)
510 if (packet[4] >= 183)
512 sec = packet + packet[4] + 4 + 1;
516 if (sec[0]) /* table pointer, assumed to be 0 */
519 if (sec[1] == 0x02) /* program map section */
522 service_id = (sec[4] << 8) | sec[5];