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)
36 eDebug("loading streaminfo for %s", filename);
37 m_streaminfo.load(filename);
40 if (!m_streaminfo.empty())
44 // eDebug("no recorded stream information available");
50 if (m_file.open(filename, 1) < 0)
55 void eDVBTSTools::closeFile()
60 void eDVBTSTools::setSyncPID(int pid)
65 void eDVBTSTools::setSearchRange(int maxrange)
67 m_maxrange = maxrange;
70 /* getPTS extracts a pts value from any PID at a given offset. */
71 int eDVBTSTools::getPTS(off_t &offset, pts_t &pts, int fixed)
74 if (!m_streaminfo.getPTS(offset, pts))
80 offset -= offset % 188;
82 if (m_file.lseek(offset, SEEK_SET) < 0)
84 eDebug("lseek failed");
88 int left = m_maxrange;
92 unsigned char packet[188];
93 if (m_file.read(packet, 188) != 188)
101 if (packet[0] != 0x47)
107 if (packet[i] == 0x47)
111 offset = m_file.lseek(i - 188, SEEK_CUR);
115 int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
116 int pusi = !!(packet[1] & 0x40);
118 // printf("PID %04x, PUSI %d\n", pid, pusi);
120 unsigned char *payload;
122 /* check for adaption field */
123 if (packet[3] & 0x20)
125 if (packet[4] >= 183)
129 if (packet[5] & 0x10) /* PCR present */
131 pts = ((unsigned long long)(packet[ 6]&0xFF)) << 25;
132 pts |= ((unsigned long long)(packet[ 7]&0xFF)) << 17;
133 pts |= ((unsigned long long)(packet[ 8]&0xFE)) << 9;
134 pts |= ((unsigned long long)(packet[ 9]&0xFF)) << 1;
135 pts |= ((unsigned long long)(packet[10]&0x80)) >> 7;
137 eDebug("PCR %16llx found at %lld pid %02x (%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x)", pts, offset, pid, packet[0], packet[1], packet[2], packet[3], packet[4], packet[5], packet[6], packet[7], packet[8], packet[9], packet[10]);
138 if (fixed && fixupPTS(offset, pts))
143 payload = packet + packet[4] + 4 + 1;
145 payload = packet + 4;
155 /* somehow not a startcode. (this is invalid, since pusi was set.) ignore it. */
156 if (payload[0] || payload[1] || (payload[2] != 1))
159 /* drop non-audio, non-video packets because other streams
160 can be non-compliant.*/
161 if (((payload[3] & 0xE0) != 0xC0) && // audio
162 ((payload[3] & 0xF0) != 0xE0)) // video
165 if (payload[7] & 0x80) /* PTS */
167 pts = ((unsigned long long)(payload[ 9]&0xE)) << 29;
168 pts |= ((unsigned long long)(payload[10]&0xFF)) << 22;
169 pts |= ((unsigned long long)(payload[11]&0xFE)) << 14;
170 pts |= ((unsigned long long)(payload[12]&0xFF)) << 7;
171 pts |= ((unsigned long long)(payload[13]&0xFE)) >> 1;
174 eDebug("PTS %16llx found at %lld pid %02x stream: %02x", pts, offset, pid, payload[3]);
176 /* convert to zero-based */
177 if (fixed && fixupPTS(offset, pts))
186 int eDVBTSTools::fixupPTS(const off_t &offset, pts_t &now)
188 if (m_use_streaminfo)
190 if (!m_streaminfo.fixupPTS(offset, now))
194 /* for the simple case, we assume one epoch, with up to one wrap around in the middle. */
198 eDebug("begin not valid, can't fixup");
202 pts_t pos = m_pts_begin;
203 if ((now < pos) && ((pos - now) < 90000 * 10))
209 if (now < pos) /* wrap around */
210 now = now + 0x200000000LL - pos;
215 eDebug("eDVBTSTools::fixupPTS failed!");
219 int eDVBTSTools::getOffset(off_t &offset, pts_t &pts, int marg)
221 eDebug("getOffset for pts 0x%llx", pts);
222 if (m_use_streaminfo)
224 if (pts >= m_pts_end && marg > 0 && m_end_valid)
225 offset = m_offset_end;
227 offset = m_streaminfo.getAccessPoint(pts, marg);
231 calcBegin(); calcEnd();
238 if (!m_samples_taken)
241 if (!m_samples.empty())
248 /* search entry before and after */
249 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(pts);
250 std::map<pts_t, off_t>::const_iterator u = l;
252 if (l != m_samples.begin())
255 /* we could have seeked beyond the end */
256 if (u == m_samples.end())
258 /* use last segment for interpolation. */
259 if (l != m_samples.begin())
266 /* if we don't have enough points */
267 if (u == m_samples.end())
270 pts_t pts_diff = u->first - l->first;
271 off_t offset_diff = u->second - l->second;
275 eDebug("something went wrong when taking samples.");
281 eDebug("using: %llx:%llx -> %llx:%llx", l->first, u->first, l->second, u->second);
286 bitrate = offset_diff * 90000 * 8 / pts_diff;
291 offset += ((pts - l->first) * (pts_t)bitrate) / 8ULL / 90000ULL;
292 offset -= offset % 188;
296 if (!takeSample(offset, p))
298 int diff = (p - pts) / 90;
300 eDebug("calculated diff %d ms", diff);
303 eDebug("diff to big, refining");
307 eDebug("no sample taken, refinement not possible.");
312 /* if even the first sample couldn't be taken, fall back. */
313 /* otherwise, return most refined result. */
317 eDebug("aborting. Taking %llx as offset for %lld", offset, pts);
322 int bitrate = calcBitrate();
323 offset = pts * (pts_t)bitrate / 8ULL / 90000ULL;
324 eDebug("fallback, bitrate=%d, results in %016llx", bitrate, offset);
325 offset -= offset % 188;
331 int eDVBTSTools::getNextAccessPoint(pts_t &ts, const pts_t &start, int direction)
333 if (m_use_streaminfo)
334 return m_streaminfo.getNextAccessPoint(ts, start, direction);
337 eDebug("can't get next access point without streaminfo");
342 void eDVBTSTools::calcBegin()
347 if (!(m_begin_valid || m_futile))
350 if (!getPTS(m_offset_begin, m_pts_begin))
357 void eDVBTSTools::calcEnd()
362 off_t end = m_file.lseek(0, SEEK_END);
364 if (llabs(end - m_last_filelength) > 1*1024*1024)
366 m_last_filelength = end;
370 // eDebug("file size changed, recalc length");
375 m_offset_end = m_last_filelength;
377 while (!(m_end_valid || m_futile))
385 m_offset_end -= m_maxrange;
386 if (m_offset_end < 0)
389 /* restore offset if getpts fails */
390 off_t off = m_offset_end;
392 if (!getPTS(m_offset_end, m_pts_end))
405 int eDVBTSTools::calcLen(pts_t &len)
407 calcBegin(); calcEnd();
408 if (!(m_begin_valid && m_end_valid))
410 len = m_pts_end - m_pts_begin;
413 len += 0x200000000LL;
417 int eDVBTSTools::calcBitrate()
419 calcBegin(); calcEnd();
420 if (!(m_begin_valid && m_end_valid))
423 pts_t len_in_pts = m_pts_end - m_pts_begin;
427 len_in_pts += 0x200000000LL;
428 off_t len_in_bytes = m_offset_end - m_offset_begin;
433 unsigned long long bitrate = len_in_bytes * 90000 * 8 / len_in_pts;
434 if ((bitrate < 10000) || (bitrate > 100000000))
441 void eDVBTSTools::takeSamples()
448 if (calcLen(dummy) == -1)
452 off_t bytes_per_sample = (m_offset_end - m_offset_begin) / (long long)nr_samples;
453 if (bytes_per_sample < 40*1024*1024)
454 bytes_per_sample = 40*1024*1024;
456 bytes_per_sample -= bytes_per_sample % 188;
458 eDebug("samples step %lld, pts begin %llx, pts end %llx, offs begin %lld, offs end %lld:",
459 bytes_per_sample, m_pts_begin, m_pts_end, m_offset_begin, m_offset_end);
461 for (off_t offset = m_offset_begin; offset < m_offset_end;)
464 if (takeSample(offset, p) && retries--)
467 offset += bytes_per_sample;
469 m_samples[0] = m_offset_begin;
470 m_samples[m_pts_end - m_pts_begin] = m_offset_end;
473 /* returns 0 when a sample was taken. */
474 int eDVBTSTools::takeSample(off_t off, pts_t &p)
476 off_t offset_org = off;
478 if (!eDVBTSTools::getPTS(off, p, 1))
480 /* as we are happily mixing PTS and PCR values (no comment, please), we might
481 end up with some "negative" segments.
483 so check if this new sample is between the previous and the next field*/
485 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(p);
486 std::map<pts_t, off_t>::const_iterator u = l;
488 if (l != m_samples.begin())
491 if (u != m_samples.end())
493 if ((l->second > off) || (u->second < off))
495 eDebug("ignoring sample %lld %lld %lld (%llx %llx %llx)",
496 l->second, off, u->second, l->first, p, u->first);
502 eDebug("adding sample %lld: pts 0x%llx -> pos %lld (diff %lld bytes)", offset_org, p, off, off-offset_org);
509 int eDVBTSTools::findPMT(int &pmt_pid, int &service_id)
511 /* FIXME: this will be factored out soon! */
514 eDebug(" file not valid");
518 if (m_file.lseek(0, SEEK_SET) < 0)
520 eDebug("seek failed");
524 int left = 5*1024*1024;
528 unsigned char packet[188];
529 if (m_file.read(packet, 188) != 188)
531 eDebug("read error");
536 if (packet[0] != 0x47)
541 if (packet[i] == 0x47)
545 m_file.lseek(i - 188, SEEK_CUR);
549 int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
551 int pusi = !!(packet[1] & 0x40);
556 /* ok, now we have a PES header or section header*/
559 /* check for adaption field */
560 if (packet[3] & 0x20)
562 if (packet[4] >= 183)
564 sec = packet + packet[4] + 4 + 1;
568 if (sec[0]) /* table pointer, assumed to be 0 */
571 if (sec[1] == 0x02) /* program map section */
574 service_id = (sec[4] << 8) | sec[5];
582 int eDVBTSTools::findFrame(off_t &_offset, size_t &len, int &direction, int frame_types)
584 off_t offset = _offset;
586 // eDebug("trying to find iFrame at %llx", offset);
588 if (!m_use_streaminfo)
590 // eDebug("can't get next iframe without streaminfo");
594 /* let's find the iframe before the given offset */
595 unsigned long long data;
602 if (m_streaminfo.getStructureEntry(offset, data, (direction == 0) ? 1 : 0))
604 eDebug("getting structure info for origin offset failed.");
607 if (offset == 0x7fffffffffffffffLL) /* eof */
609 eDebug("reached eof");
612 /* data is usually the start code in the lower 8 bit, and the next byte <<8. we extract the picture type from there */
613 /* we know that we aren't recording startcode 0x09 for mpeg2, so this is safe */
614 /* TODO: check frame_types */
615 int is_start = (data & 0xE0FF) == 0x0009; /* H.264 NAL unit access delimiter with I-frame*/
616 is_start |= (data & 0x3800FF) == 0x080000; /* MPEG2 picture start code with I-frame */
618 int is_frame = ((data & 0xFF) == 0x0009) || ((data & 0xFF) == 0x00); /* H.264 UAD or MPEG2 start code */
627 // eDebug("%08llx@%llx -> %d, %d", data, offset, is_start, nr_frames);
632 --offset; /* move to previous entry */
633 else if (direction == +1)
636 /* let's find the next frame after the given offset */
637 off_t start = offset;
640 if (m_streaminfo.getStructureEntry(offset, data, 1))
642 eDebug("get next failed");
645 if (offset == 0x7fffffffffffffffLL) /* eof */
647 eDebug("reached eof (while looking for end of iframe)");
650 // eDebug("%08llx@%llx (next)", data, offset);
651 } while (((data & 0xFF) != 9) && ((data & 0xFF) != 0x00)); /* next frame */
653 /* align to TS pkt start */
654 // start = start - (start % 188);
655 // offset = offset - (offset % 188);
657 len = offset - start;
659 direction = nr_frames;
660 // eDebug("result: offset=%llx, len: %ld", offset, (int)len);
664 int eDVBTSTools::findNextPicture(off_t &offset, size_t &len, int &distance, int frame_types)
666 int nr_frames, direction;
667 // eDebug("trying to move %d frames at %llx", distance, offset);
669 frame_types = frametypeI; /* TODO: intelligent "allow IP frames when not crossing an I-Frame */
671 off_t new_offset = offset;
672 size_t new_len = len;
681 distance = -distance+1;
686 if (findFrame(new_offset, new_len, dir, frame_types))
688 // eDebug("findFrame failed!\n");
692 distance -= abs(dir);
694 // eDebug("we moved %d, %d to go frames (now at %llx)", dir, distance, new_offset);
696 if (distance >= 0 || direction == 0)
701 nr_frames += abs(dir);
707 nr_frames += abs(dir) + distance; // never jump forward during rewind
711 distance = (direction < 0) ? -nr_frames : nr_frames;
712 // eDebug("in total, we moved %d frames", nr_frames);