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, int nostreaminfo)
34 m_streaminfo.load((std::string(filename) + ".ap").c_str());
36 if (!m_streaminfo.empty())
40 // eDebug("no recorded stream information available");
46 if (m_file.open(filename, 1) < 0)
51 void eDVBTSTools::closeFile()
56 void eDVBTSTools::setSyncPID(int pid)
61 void eDVBTSTools::setSearchRange(int maxrange)
63 m_maxrange = maxrange;
66 /* getPTS extracts a pts value from any PID at a given offset. */
67 int eDVBTSTools::getPTS(off_t &offset, pts_t &pts, int fixed)
70 return m_streaminfo.getPTS(offset, pts);
75 offset -= offset % 188;
77 if (m_file.lseek(offset, SEEK_SET) < 0)
80 int left = m_maxrange;
84 unsigned char packet[188];
85 if (m_file.read(packet, 188) != 188)
93 if (packet[0] != 0x47)
98 if (packet[i] == 0x47)
102 offset = m_file.lseek(i - 188, SEEK_CUR);
106 int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
107 int pusi = !!(packet[1] & 0x40);
109 // printf("PID %04x, PUSI %d\n", pid, pusi);
111 unsigned char *payload;
113 /* check for adaption field */
114 if (packet[3] & 0x20)
116 if (packet[4] >= 183)
120 if (packet[5] & 0x10) /* PCR present */
122 pts = ((unsigned long long)(packet[ 6]&0xFF)) << 25;
123 pts |= ((unsigned long long)(packet[ 7]&0xFF)) << 17;
124 pts |= ((unsigned long long)(packet[ 8]&0xFE)) << 9;
125 pts |= ((unsigned long long)(packet[ 9]&0xFF)) << 1;
126 pts |= ((unsigned long long)(packet[10]&0x80)) >> 7;
128 eDebug("PCR found: %16llx", pts);
129 if (fixed && fixupPTS(offset, pts))
134 payload = packet + packet[4] + 4 + 1;
136 payload = packet + 4;
146 /* somehow not a startcode. (this is invalid, since pusi was set.) ignore it. */
147 if (payload[0] || payload[1] || (payload[2] != 1))
150 /* drop non-audio, non-video packets because other streams
151 can be non-compliant.*/
152 if (((payload[3] & 0xE0) != 0xC0) && // audio
153 ((payload[3] & 0xF0) != 0xE0)) // video
156 if (payload[7] & 0x80) /* PTS */
158 pts = ((unsigned long long)(payload[ 9]&0xE)) << 29;
159 pts |= ((unsigned long long)(payload[10]&0xFF)) << 22;
160 pts |= ((unsigned long long)(payload[11]&0xFE)) << 14;
161 pts |= ((unsigned long long)(payload[12]&0xFF)) << 7;
162 pts |= ((unsigned long long)(payload[13]&0xFE)) >> 1;
165 eDebug("found pts %08llx at %08llx pid %02x stream: %02x", pts, offset, pid, payload[3]);
167 /* convert to zero-based */
168 if (fixed && fixupPTS(offset, pts))
177 int eDVBTSTools::fixupPTS(const off_t &offset, pts_t &now)
179 if (m_use_streaminfo)
181 return m_streaminfo.fixupPTS(offset, now);
184 /* for the simple case, we assume one epoch, with up to one wrap around in the middle. */
188 eDebug("begin not valid, can't fixup");
192 pts_t pos = m_pts_begin;
193 if ((now < pos) && ((pos - now) < 90000 * 10))
199 if (now < pos) /* wrap around */
200 now = now + 0x200000000LL - pos;
207 int eDVBTSTools::getOffset(off_t &offset, pts_t &pts)
209 if (m_use_streaminfo)
211 offset = m_streaminfo.getAccessPoint(pts);
215 eDebug("get offset: pts=%llx", pts);
216 calcBegin(); calcEnd();
223 if (!m_samples_taken)
226 if (!m_samples.empty())
233 /* search entry before and after */
234 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(pts);
235 std::map<pts_t, off_t>::const_iterator u = l;
237 if (l != m_samples.begin())
240 /* we could have seeked beyond the end */
241 if (u == m_samples.end())
243 /* use last segment for interpolation. */
244 if (l != m_samples.begin())
251 /* if we don't have enough points */
252 if (u == m_samples.end())
255 pts_t pts_diff = u->first - l->first;
256 off_t offset_diff = u->second - l->second;
258 eDebug("using: %llx:%llx -> %llx:%llx", l->first, u->first, l->second, u->second);
263 bitrate = offset_diff * 90000 * 8 / pts_diff;
268 offset += ((pts - l->first) * (pts_t)bitrate) / 8ULL / 90000ULL;
269 offset -= offset % 188;
273 eDebug("so next guess at %llx", offset);
275 if (!takeSample(offset, p))
277 int diff = (p - pts) / 90;
279 eDebug("calculated diff %d ms", diff);
282 eDebug("diff to big, refining");
286 eDebug("no sample taken, refinement not possible.");
291 /* if even the first sample couldn't be taken, fall back. */
292 /* otherwise, return most refined result. */
300 eDebug("falling back");
301 int bitrate = calcBitrate();
302 offset = pts * (pts_t)bitrate / 8ULL / 90000ULL;
303 offset -= offset % 188;
309 int eDVBTSTools::getNextAccessPoint(pts_t &ts, const pts_t &start, int direction)
311 if (m_use_streaminfo)
312 return m_streaminfo.getNextAccessPoint(ts, start, direction);
315 eDebug("can't get next access point without streaminfo");
320 void eDVBTSTools::calcBegin()
325 if (!(m_begin_valid || m_futile))
328 if (!getPTS(m_offset_begin, m_pts_begin))
335 void eDVBTSTools::calcEnd()
340 off_t end = m_file.lseek(0, SEEK_END);
342 if (abs(end - m_last_filelength) > 1*1024*1024)
344 m_last_filelength = end;
348 // eDebug("file size changed, recalc length");
353 m_offset_end = m_last_filelength;
355 while (!(m_end_valid || m_futile))
363 m_offset_end -= m_maxrange;
364 if (m_offset_end < 0)
367 /* restore offset if getpts fails */
368 off_t off = m_offset_end;
370 if (!getPTS(m_offset_end, m_pts_end))
383 int eDVBTSTools::calcLen(pts_t &len)
385 calcBegin(); calcEnd();
386 if (!(m_begin_valid && m_end_valid))
388 len = m_pts_end - m_pts_begin;
391 len += 0x200000000LL;
395 int eDVBTSTools::calcBitrate()
397 calcBegin(); calcEnd();
398 if (!(m_begin_valid && m_end_valid))
401 pts_t len_in_pts = m_pts_end - m_pts_begin;
405 len_in_pts += 0x200000000LL;
406 off_t len_in_bytes = m_offset_end - m_offset_begin;
411 unsigned long long bitrate = len_in_bytes * 90000 * 8 / len_in_pts;
412 if ((bitrate < 10000) || (bitrate > 100000000))
419 void eDVBTSTools::takeSamples()
424 if (calcLen(dummy) == -1)
428 off_t bytes_per_sample = (m_offset_end - m_offset_begin) / (long long)nr_samples;
429 if (bytes_per_sample < 40*1024*1024)
430 bytes_per_sample = 40*1024*1024;
432 bytes_per_sample -= bytes_per_sample % 188;
434 for (off_t offset = m_offset_begin; offset < m_offset_end; offset += bytes_per_sample)
437 takeSample(offset, p);
439 m_samples[0] = m_offset_begin;
440 m_samples[m_pts_end - m_pts_begin] = m_offset_end;
442 // eDebug("begin, end: %llx %llx", m_offset_begin, m_offset_end);
445 /* returns 0 when a sample was taken. */
446 int eDVBTSTools::takeSample(off_t off, pts_t &p)
448 eDebug("take sample: %llx", off);
449 if (!eDVBTSTools::getPTS(off, p, 1))
451 eDebug("took sample: %llx, %llx", off, p);
458 int eDVBTSTools::findPMT(int &pmt_pid, int &service_id)
460 /* FIXME: this will be factored out soon! */
463 eDebug(" file not valid");
467 if (m_file.lseek(0, SEEK_SET) < 0)
469 eDebug("seek failed");
473 int left = 5*1024*1024;
477 unsigned char packet[188];
478 if (m_file.read(packet, 188) != 188)
480 eDebug("read error");
485 if (packet[0] != 0x47)
490 if (packet[i] == 0x47)
494 m_file.lseek(i - 188, SEEK_CUR);
498 int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
500 int pusi = !!(packet[1] & 0x40);
505 /* ok, now we have a PES header or section header*/
508 /* check for adaption field */
509 if (packet[3] & 0x20)
511 if (packet[4] >= 183)
513 sec = packet + packet[4] + 4 + 1;
517 if (sec[0]) /* table pointer, assumed to be 0 */
520 if (sec[1] == 0x02) /* program map section */
523 service_id = (sec[4] << 8) | sec[5];