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 void eDVBTSTools::closeSource()
30 eDVBTSTools::~eDVBTSTools()
35 int eDVBTSTools::openFile(const char *filename, int nostreaminfo)
37 eRawFile *f = new eRawFile();
38 ePtr<iTsSource> src = f;
40 if (f->open(filename, 1) < 0)
43 setSource(src, nostreaminfo ? NULL : filename);
48 void eDVBTSTools::setSource(ePtr<iTsSource> &source, const char *stream_info_filename)
54 if (stream_info_filename)
56 eDebug("loading streaminfo for %s", stream_info_filename);
57 m_streaminfo.load(stream_info_filename);
60 if (!m_streaminfo.empty())
64 // eDebug("no recorded stream information available");
71 void eDVBTSTools::closeFile()
77 void eDVBTSTools::setSyncPID(int pid)
82 void eDVBTSTools::setSearchRange(int maxrange)
84 m_maxrange = maxrange;
87 /* getPTS extracts a pts value from any PID at a given offset. */
88 int eDVBTSTools::getPTS(off_t &offset, pts_t &pts, int fixed)
91 if (!m_streaminfo.getPTS(offset, pts))
94 if (!m_source || !m_source->valid())
97 offset -= offset % 188;
99 int left = m_maxrange;
103 unsigned char packet[188];
104 if (m_source->read(offset, packet, 188) != 188)
106 eDebug("read error");
112 if (packet[0] != 0x47)
118 if (packet[i] == 0x47)
126 int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
127 int pusi = !!(packet[1] & 0x40);
129 // printf("PID %04x, PUSI %d\n", pid, pusi);
131 unsigned char *payload;
133 /* check for adaption field */
134 if (packet[3] & 0x20)
136 if (packet[4] >= 183)
140 if (packet[5] & 0x10) /* PCR present */
142 pts = ((unsigned long long)(packet[ 6]&0xFF)) << 25;
143 pts |= ((unsigned long long)(packet[ 7]&0xFF)) << 17;
144 pts |= ((unsigned long long)(packet[ 8]&0xFE)) << 9;
145 pts |= ((unsigned long long)(packet[ 9]&0xFF)) << 1;
146 pts |= ((unsigned long long)(packet[10]&0x80)) >> 7;
148 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]);
149 if (fixed && fixupPTS(offset, pts))
154 payload = packet + packet[4] + 4 + 1;
156 payload = packet + 4;
164 /* somehow not a startcode. (this is invalid, since pusi was set.) ignore it. */
165 if (payload[0] || payload[1] || (payload[2] != 1))
168 if (payload[3] == 0xFD)
169 { // stream use extension mechanism defined in ISO 13818-1 Amendment 2
170 if (payload[7] & 1) // PES extension flag
173 if (payload[7] & 0x80) // pts avail
175 if (payload[7] & 0x40) // dts avail
177 if (payload[7] & 0x20) // escr avail
179 if (payload[7] & 0x10) // es rate
181 if (payload[7] & 0x8) // dsm trickmode
183 if (payload[7] & 0x4) // additional copy info
185 if (payload[7] & 0x2) // crc
187 if (payload[8] < offs)
189 uint8_t pef = payload[9+offs++]; // pes extension field
190 if (pef & 1) // pes extension flag 2
192 if (pef & 0x80) // private data flag
194 if (pef & 0x40) // pack header field flag
196 if (pef & 0x20) // program packet sequence counter flag
198 if (pef & 0x10) // P-STD buffer flag
200 if (payload[8] < offs)
202 uint8_t stream_id_extension_len = payload[9+offs++] & 0x7F;
203 if (stream_id_extension_len >= 1)
205 if (payload[8] < (offs + stream_id_extension_len) )
207 if (payload[9+offs] & 0x80) // stream_id_extension_bit (should not set)
209 switch (payload[9+offs])
211 case 0x55 ... 0x5f: // VC-1
213 case 0x71: // AC3 / DTS
215 case 0x72: // DTS - HD
218 eDebug("skip unknwn stream_id_extension %02x\n", payload[9+offs]);
231 /* drop non-audio, non-video packets because other streams
232 can be non-compliant.*/
233 else if (((payload[3] & 0xE0) != 0xC0) && // audio
234 ((payload[3] & 0xF0) != 0xE0)) // video
237 if (payload[7] & 0x80) /* PTS */
239 pts = ((unsigned long long)(payload[ 9]&0xE)) << 29;
240 pts |= ((unsigned long long)(payload[10]&0xFF)) << 22;
241 pts |= ((unsigned long long)(payload[11]&0xFE)) << 14;
242 pts |= ((unsigned long long)(payload[12]&0xFF)) << 7;
243 pts |= ((unsigned long long)(payload[13]&0xFE)) >> 1;
246 eDebug("PTS %16llx found at %lld pid %02x stream: %02x", pts, offset, pid, payload[3]);
248 /* convert to zero-based */
249 if (fixed && fixupPTS(offset, pts))
258 int eDVBTSTools::fixupPTS(const off_t &offset, pts_t &now)
260 if (m_use_streaminfo)
262 if (!m_streaminfo.fixupPTS(offset, now))
266 /* for the simple case, we assume one epoch, with up to one wrap around in the middle. */
270 eDebug("begin not valid, can't fixup");
274 pts_t pos = m_pts_begin;
275 if ((now < pos) && ((pos - now) < 90000 * 10))
281 if (now < pos) /* wrap around */
282 now = now + 0x200000000LL - pos;
287 eDebug("eDVBTSTools::fixupPTS failed!");
291 int eDVBTSTools::getOffset(off_t &offset, pts_t &pts, int marg)
293 eDebug("getOffset for pts 0x%llx", pts);
294 if (m_use_streaminfo)
296 if (pts >= m_pts_end && marg > 0 && m_end_valid)
297 offset = m_offset_end;
299 offset = m_streaminfo.getAccessPoint(pts, marg);
303 calcBegin(); calcEnd();
310 if (!m_samples_taken)
313 if (!m_samples.empty())
320 /* search entry before and after */
321 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(pts);
322 std::map<pts_t, off_t>::const_iterator u = l;
324 if (l != m_samples.begin())
327 /* we could have seeked beyond the end */
328 if (u == m_samples.end())
330 /* use last segment for interpolation. */
331 if (l != m_samples.begin())
338 /* if we don't have enough points */
339 if (u == m_samples.end())
342 pts_t pts_diff = u->first - l->first;
343 off_t offset_diff = u->second - l->second;
347 eDebug("something went wrong when taking samples.");
353 eDebug("using: %llx:%llx -> %llx:%llx", l->first, u->first, l->second, u->second);
358 bitrate = offset_diff * 90000 * 8 / pts_diff;
363 offset += ((pts - l->first) * (pts_t)bitrate) / 8ULL / 90000ULL;
364 offset -= offset % 188;
368 if (!takeSample(offset, p))
370 int diff = (p - pts) / 90;
372 eDebug("calculated diff %d ms", diff);
375 eDebug("diff to big, refining");
379 eDebug("no sample taken, refinement not possible.");
384 /* if even the first sample couldn't be taken, fall back. */
385 /* otherwise, return most refined result. */
389 eDebug("aborting. Taking %llx as offset for %lld", offset, pts);
394 int bitrate = calcBitrate();
395 offset = pts * (pts_t)bitrate / 8ULL / 90000ULL;
396 eDebug("fallback, bitrate=%d, results in %016llx", bitrate, offset);
397 offset -= offset % 188;
403 int eDVBTSTools::getNextAccessPoint(pts_t &ts, const pts_t &start, int direction)
405 if (m_use_streaminfo)
406 return m_streaminfo.getNextAccessPoint(ts, start, direction);
409 eDebug("can't get next access point without streaminfo");
414 void eDVBTSTools::calcBegin()
416 if (!m_source || !m_source->valid())
419 if (!(m_begin_valid || m_futile))
422 if (!getPTS(m_offset_begin, m_pts_begin))
429 void eDVBTSTools::calcEnd()
431 if (!m_source || !m_source->valid())
434 off_t end = m_source->lseek(0, SEEK_END);
436 if (llabs(end - m_last_filelength) > 1*1024*1024)
438 m_last_filelength = end;
442 // eDebug("file size changed, recalc length");
447 m_offset_end = m_last_filelength;
449 while (!(m_end_valid || m_futile))
457 m_offset_end -= m_maxrange;
458 if (m_offset_end < 0)
461 /* restore offset if getpts fails */
462 off_t off = m_offset_end;
464 if (!getPTS(m_offset_end, m_pts_end))
477 int eDVBTSTools::calcLen(pts_t &len)
479 calcBegin(); calcEnd();
480 if (!(m_begin_valid && m_end_valid))
482 len = m_pts_end - m_pts_begin;
485 len += 0x200000000LL;
489 int eDVBTSTools::calcBitrate()
491 calcBegin(); calcEnd();
492 if (!(m_begin_valid && m_end_valid))
495 pts_t len_in_pts = m_pts_end - m_pts_begin;
499 len_in_pts += 0x200000000LL;
500 off_t len_in_bytes = m_offset_end - m_offset_begin;
505 unsigned long long bitrate = len_in_bytes * 90000 * 8 / len_in_pts;
506 if ((bitrate < 10000) || (bitrate > 100000000))
513 void eDVBTSTools::takeSamples()
520 if (calcLen(dummy) == -1)
524 off_t bytes_per_sample = (m_offset_end - m_offset_begin) / (long long)nr_samples;
525 if (bytes_per_sample < 40*1024*1024)
526 bytes_per_sample = 40*1024*1024;
528 bytes_per_sample -= bytes_per_sample % 188;
530 eDebug("samples step %lld, pts begin %llx, pts end %llx, offs begin %lld, offs end %lld:",
531 bytes_per_sample, m_pts_begin, m_pts_end, m_offset_begin, m_offset_end);
533 for (off_t offset = m_offset_begin; offset < m_offset_end;)
536 if (takeSample(offset, p) && retries--)
539 offset += bytes_per_sample;
541 m_samples[0] = m_offset_begin;
542 m_samples[m_pts_end - m_pts_begin] = m_offset_end;
545 /* returns 0 when a sample was taken. */
546 int eDVBTSTools::takeSample(off_t off, pts_t &p)
548 off_t offset_org = off;
550 if (!eDVBTSTools::getPTS(off, p, 1))
552 /* as we are happily mixing PTS and PCR values (no comment, please), we might
553 end up with some "negative" segments.
555 so check if this new sample is between the previous and the next field*/
557 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(p);
558 std::map<pts_t, off_t>::const_iterator u = l;
560 if (l != m_samples.begin())
563 if (u != m_samples.end())
565 if ((l->second > off) || (u->second < off))
567 eDebug("ignoring sample %lld %lld %lld (%llx %llx %llx)",
568 l->second, off, u->second, l->first, p, u->first);
574 eDebug("adding sample %lld: pts 0x%llx -> pos %lld (diff %lld bytes)", offset_org, p, off, off-offset_org);
581 int eDVBTSTools::findPMT(int &pmt_pid, int &service_id)
583 /* FIXME: this will be factored out soon! */
584 if (!m_source || !m_source->valid())
586 eDebug(" file not valid");
592 int left = 5*1024*1024;
596 unsigned char packet[188];
597 int ret = m_source->read(position, packet, 188);
600 eDebug("read error");
606 if (packet[0] != 0x47)
611 if (packet[i] == 0x47)
618 int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
620 int pusi = !!(packet[1] & 0x40);
625 /* ok, now we have a PES header or section header*/
628 /* check for adaption field */
629 if (packet[3] & 0x20)
631 if (packet[4] >= 183)
633 sec = packet + packet[4] + 4 + 1;
637 if (sec[0]) /* table pointer, assumed to be 0 */
640 if (sec[1] == 0x02) /* program map section */
643 service_id = (sec[4] << 8) | sec[5];
651 int eDVBTSTools::findFrame(off_t &_offset, size_t &len, int &direction, int frame_types)
653 off_t offset = _offset;
655 // eDebug("trying to find iFrame at %llx", offset);
657 if (!m_use_streaminfo)
659 // eDebug("can't get next iframe without streaminfo");
663 /* let's find the iframe before the given offset */
664 unsigned long long data;
671 if (m_streaminfo.getStructureEntry(offset, data, (direction == 0) ? 1 : 0))
673 eDebug("getting structure info for origin offset failed.");
676 if (offset == 0x7fffffffffffffffLL) /* eof */
678 eDebug("reached eof");
681 /* data is usually the start code in the lower 8 bit, and the next byte <<8. we extract the picture type from there */
682 /* we know that we aren't recording startcode 0x09 for mpeg2, so this is safe */
683 /* TODO: check frame_types */
684 int is_start = (data & 0xE0FF) == 0x0009; /* H.264 NAL unit access delimiter with I-frame*/
685 is_start |= (data & 0x3800FF) == 0x080000; /* MPEG2 picture start code with I-frame */
687 int is_frame = ((data & 0xFF) == 0x0009) || ((data & 0xFF) == 0x00); /* H.264 UAD or MPEG2 start code */
696 // eDebug("%08llx@%llx -> %d, %d", data, offset, is_start, nr_frames);
701 --offset; /* move to previous entry */
702 else if (direction == +1)
705 off_t start = offset;
708 /* backtrack to find the previous sequence start, in case of MPEG2 */
709 if ((data & 0xFF) == 0x00) {
712 if (m_streaminfo.getStructureEntry(start, data, 0))
714 eDebug("get previous failed");
717 } while (((data & 0xFF) != 9) && ((data & 0xFF) != 0x00) && ((data & 0xFF) != 0xB3)); /* sequence start or previous frame */
718 if ((data & 0xFF) != 0xB3)
719 start = offset; /* Failed to find corresponding sequence start, so never mind */
724 /* let's find the next frame after the given offset */
726 if (m_streaminfo.getStructureEntry(offset, data, 1))
728 eDebug("get next failed");
731 if (offset == 0x7fffffffffffffffLL) /* eof */
733 eDebug("reached eof (while looking for end of iframe)");
736 // eDebug("%08llx@%llx (next)", data, offset);
737 } while (((data & 0xFF) != 9) && ((data & 0xFF) != 0x00)); /* next frame */
740 /* align to TS pkt start */
741 start = start - (start % 188);
742 offset = offset - (offset % 188);
745 len = offset - start;
747 direction = nr_frames;
748 // eDebug("result: offset=%llx, len: %ld", offset, (int)len);
752 int eDVBTSTools::findNextPicture(off_t &offset, size_t &len, int &distance, int frame_types)
754 int nr_frames, direction;
755 // eDebug("trying to move %d frames at %llx", distance, offset);
757 frame_types = frametypeI; /* TODO: intelligent "allow IP frames when not crossing an I-Frame */
759 off_t new_offset = offset;
760 size_t new_len = len;
769 distance = -distance+1;
774 if (findFrame(new_offset, new_len, dir, frame_types))
776 // eDebug("findFrame failed!\n");
780 distance -= abs(dir);
782 // eDebug("we moved %d, %d to go frames (now at %llx)", dir, distance, new_offset);
784 if (distance >= 0 || direction == 0)
789 nr_frames += abs(dir);
795 nr_frames += abs(dir) + distance; // never jump forward during rewind
799 distance = (direction < 0) ? -nr_frames : nr_frames;
800 // eDebug("in total, we moved %d frames", nr_frames);