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, 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
216 eDebug("skip unknwn stream_id_extension %02x\n", payload[9+offs]);
229 /* drop non-audio, non-video packets because other streams
230 can be non-compliant.*/
231 else if (((payload[3] & 0xE0) != 0xC0) && // audio
232 ((payload[3] & 0xF0) != 0xE0)) // video
235 if (payload[7] & 0x80) /* PTS */
237 pts = ((unsigned long long)(payload[ 9]&0xE)) << 29;
238 pts |= ((unsigned long long)(payload[10]&0xFF)) << 22;
239 pts |= ((unsigned long long)(payload[11]&0xFE)) << 14;
240 pts |= ((unsigned long long)(payload[12]&0xFF)) << 7;
241 pts |= ((unsigned long long)(payload[13]&0xFE)) >> 1;
244 eDebug("PTS %16llx found at %lld pid %02x stream: %02x", pts, offset, pid, payload[3]);
246 /* convert to zero-based */
247 if (fixed && fixupPTS(offset, pts))
256 int eDVBTSTools::fixupPTS(const off_t &offset, pts_t &now)
258 if (m_use_streaminfo)
260 if (!m_streaminfo.fixupPTS(offset, now))
264 /* for the simple case, we assume one epoch, with up to one wrap around in the middle. */
268 eDebug("begin not valid, can't fixup");
272 pts_t pos = m_pts_begin;
273 if ((now < pos) && ((pos - now) < 90000 * 10))
279 if (now < pos) /* wrap around */
280 now = now + 0x200000000LL - pos;
285 eDebug("eDVBTSTools::fixupPTS failed!");
289 int eDVBTSTools::getOffset(off_t &offset, pts_t &pts, int marg)
291 eDebug("getOffset for pts 0x%llx", pts);
292 if (m_use_streaminfo)
294 if (pts >= m_pts_end && marg > 0 && m_end_valid)
295 offset = m_offset_end;
297 offset = m_streaminfo.getAccessPoint(pts, marg);
301 calcBegin(); calcEnd();
308 if (!m_samples_taken)
311 if (!m_samples.empty())
318 /* search entry before and after */
319 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(pts);
320 std::map<pts_t, off_t>::const_iterator u = l;
322 if (l != m_samples.begin())
325 /* we could have seeked beyond the end */
326 if (u == m_samples.end())
328 /* use last segment for interpolation. */
329 if (l != m_samples.begin())
336 /* if we don't have enough points */
337 if (u == m_samples.end())
340 pts_t pts_diff = u->first - l->first;
341 off_t offset_diff = u->second - l->second;
345 eDebug("something went wrong when taking samples.");
351 eDebug("using: %llx:%llx -> %llx:%llx", l->first, u->first, l->second, u->second);
356 bitrate = offset_diff * 90000 * 8 / pts_diff;
361 offset += ((pts - l->first) * (pts_t)bitrate) / 8ULL / 90000ULL;
362 offset -= offset % 188;
366 if (!takeSample(offset, p))
368 int diff = (p - pts) / 90;
370 eDebug("calculated diff %d ms", diff);
373 eDebug("diff to big, refining");
377 eDebug("no sample taken, refinement not possible.");
382 /* if even the first sample couldn't be taken, fall back. */
383 /* otherwise, return most refined result. */
387 eDebug("aborting. Taking %llx as offset for %lld", offset, pts);
392 int bitrate = calcBitrate();
393 offset = pts * (pts_t)bitrate / 8ULL / 90000ULL;
394 eDebug("fallback, bitrate=%d, results in %016llx", bitrate, offset);
395 offset -= offset % 188;
401 int eDVBTSTools::getNextAccessPoint(pts_t &ts, const pts_t &start, int direction)
403 if (m_use_streaminfo)
404 return m_streaminfo.getNextAccessPoint(ts, start, direction);
407 eDebug("can't get next access point without streaminfo");
412 void eDVBTSTools::calcBegin()
414 if (!m_source || !m_source->valid())
417 if (!(m_begin_valid || m_futile))
420 if (!getPTS(m_offset_begin, m_pts_begin))
427 void eDVBTSTools::calcEnd()
429 if (!m_source || !m_source->valid())
432 off_t end = m_source->lseek(0, SEEK_END);
434 if (llabs(end - m_last_filelength) > 1*1024*1024)
436 m_last_filelength = end;
440 // eDebug("file size changed, recalc length");
445 m_offset_end = m_last_filelength;
447 while (!(m_end_valid || m_futile))
455 m_offset_end -= m_maxrange;
456 if (m_offset_end < 0)
459 /* restore offset if getpts fails */
460 off_t off = m_offset_end;
462 if (!getPTS(m_offset_end, m_pts_end))
475 int eDVBTSTools::calcLen(pts_t &len)
477 calcBegin(); calcEnd();
478 if (!(m_begin_valid && m_end_valid))
480 len = m_pts_end - m_pts_begin;
483 len += 0x200000000LL;
487 int eDVBTSTools::calcBitrate()
489 calcBegin(); calcEnd();
490 if (!(m_begin_valid && m_end_valid))
493 pts_t len_in_pts = m_pts_end - m_pts_begin;
497 len_in_pts += 0x200000000LL;
498 off_t len_in_bytes = m_offset_end - m_offset_begin;
503 unsigned long long bitrate = len_in_bytes * 90000 * 8 / len_in_pts;
504 if ((bitrate < 10000) || (bitrate > 100000000))
511 void eDVBTSTools::takeSamples()
518 if (calcLen(dummy) == -1)
522 off_t bytes_per_sample = (m_offset_end - m_offset_begin) / (long long)nr_samples;
523 if (bytes_per_sample < 40*1024*1024)
524 bytes_per_sample = 40*1024*1024;
526 bytes_per_sample -= bytes_per_sample % 188;
528 eDebug("samples step %lld, pts begin %llx, pts end %llx, offs begin %lld, offs end %lld:",
529 bytes_per_sample, m_pts_begin, m_pts_end, m_offset_begin, m_offset_end);
531 for (off_t offset = m_offset_begin; offset < m_offset_end;)
534 if (takeSample(offset, p) && retries--)
537 offset += bytes_per_sample;
539 m_samples[0] = m_offset_begin;
540 m_samples[m_pts_end - m_pts_begin] = m_offset_end;
543 /* returns 0 when a sample was taken. */
544 int eDVBTSTools::takeSample(off_t off, pts_t &p)
546 off_t offset_org = off;
548 if (!eDVBTSTools::getPTS(off, p, 1))
550 /* as we are happily mixing PTS and PCR values (no comment, please), we might
551 end up with some "negative" segments.
553 so check if this new sample is between the previous and the next field*/
555 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(p);
556 std::map<pts_t, off_t>::const_iterator u = l;
558 if (l != m_samples.begin())
561 if (u != m_samples.end())
563 if ((l->second > off) || (u->second < off))
565 eDebug("ignoring sample %lld %lld %lld (%llx %llx %llx)",
566 l->second, off, u->second, l->first, p, u->first);
572 eDebug("adding sample %lld: pts 0x%llx -> pos %lld (diff %lld bytes)", offset_org, p, off, off-offset_org);
579 int eDVBTSTools::findPMT(int &pmt_pid, int &service_id)
581 /* FIXME: this will be factored out soon! */
582 if (!m_source || !m_source->valid())
584 eDebug(" file not valid");
590 int left = 5*1024*1024;
594 unsigned char packet[188];
595 int ret = m_source->read(position, packet, 188);
598 eDebug("read error");
604 if (packet[0] != 0x47)
609 if (packet[i] == 0x47)
616 int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
618 int pusi = !!(packet[1] & 0x40);
623 /* ok, now we have a PES header or section header*/
626 /* check for adaption field */
627 if (packet[3] & 0x20)
629 if (packet[4] >= 183)
631 sec = packet + packet[4] + 4 + 1;
635 if (sec[0]) /* table pointer, assumed to be 0 */
638 if (sec[1] == 0x02) /* program map section */
641 service_id = (sec[4] << 8) | sec[5];
649 int eDVBTSTools::findFrame(off_t &_offset, size_t &len, int &direction, int frame_types)
651 off_t offset = _offset;
653 // eDebug("trying to find iFrame at %llx", offset);
655 if (!m_use_streaminfo)
657 // eDebug("can't get next iframe without streaminfo");
661 /* let's find the iframe before the given offset */
662 unsigned long long data;
669 if (m_streaminfo.getStructureEntry(offset, data, (direction == 0) ? 1 : 0))
671 eDebug("getting structure info for origin offset failed.");
674 if (offset == 0x7fffffffffffffffLL) /* eof */
676 eDebug("reached eof");
679 /* data is usually the start code in the lower 8 bit, and the next byte <<8. we extract the picture type from there */
680 /* we know that we aren't recording startcode 0x09 for mpeg2, so this is safe */
681 /* TODO: check frame_types */
682 int is_start = (data & 0xE0FF) == 0x0009; /* H.264 NAL unit access delimiter with I-frame*/
683 is_start |= (data & 0x3800FF) == 0x080000; /* MPEG2 picture start code with I-frame */
685 int is_frame = ((data & 0xFF) == 0x0009) || ((data & 0xFF) == 0x00); /* H.264 UAD or MPEG2 start code */
694 // eDebug("%08llx@%llx -> %d, %d", data, offset, is_start, nr_frames);
699 --offset; /* move to previous entry */
700 else if (direction == +1)
703 /* let's find the next frame after the given offset */
704 off_t start = offset;
707 if (m_streaminfo.getStructureEntry(offset, data, 1))
709 eDebug("get next failed");
712 if (offset == 0x7fffffffffffffffLL) /* eof */
714 eDebug("reached eof (while looking for end of iframe)");
717 // eDebug("%08llx@%llx (next)", data, offset);
718 } while (((data & 0xFF) != 9) && ((data & 0xFF) != 0x00)); /* next frame */
720 /* align to TS pkt start */
721 // start = start - (start % 188);
722 // offset = offset - (offset % 188);
724 len = offset - start;
726 direction = nr_frames;
727 // eDebug("result: offset=%llx, len: %ld", offset, (int)len);
731 int eDVBTSTools::findNextPicture(off_t &offset, size_t &len, int &distance, int frame_types)
733 int nr_frames, direction;
734 // eDebug("trying to move %d frames at %llx", distance, offset);
736 frame_types = frametypeI; /* TODO: intelligent "allow IP frames when not crossing an I-Frame */
738 off_t new_offset = offset;
739 size_t new_len = len;
748 distance = -distance+1;
753 if (findFrame(new_offset, new_len, dir, frame_types))
755 // eDebug("findFrame failed!\n");
759 distance -= abs(dir);
761 // eDebug("we moved %d, %d to go frames (now at %llx)", dir, distance, new_offset);
763 if (distance >= 0 || direction == 0)
768 nr_frames += abs(dir);
774 nr_frames += abs(dir) + distance; // never jump forward during rewind
778 distance = (direction < 0) ? -nr_frames : nr_frames;
779 // eDebug("in total, we moved %d frames", nr_frames);