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<iDataSource> src = f;
40 eSingleLocker l(f->getLock());
42 if (f->open(filename, 1) < 0)
45 setSource(src, filename);
50 void eDVBTSTools::setSource(ePtr<iDataSource> source, const char *stream_info_filename)
56 if (stream_info_filename)
58 eDebug("loading streaminfo for %s", stream_info_filename);
59 m_streaminfo.load(stream_info_filename);
62 if (!m_streaminfo.empty())
66 // eDebug("no recorded stream information available");
73 void eDVBTSTools::closeFile()
76 eSingleLocker l(m_source->getLock());
81 void eDVBTSTools::setSyncPID(int pid)
86 void eDVBTSTools::setSearchRange(int maxrange)
88 m_maxrange = maxrange;
91 /* getPTS extracts a pts value from any PID at a given offset. */
92 int eDVBTSTools::getPTS(off_t &offset, pts_t &pts, int fixed)
95 if (!m_streaminfo.getPTS(offset, pts))
98 if (!m_source->valid())
101 offset -= offset % 188;
103 iDataSourcePositionRestorer r(m_source);
105 eSingleLocker l(m_source->getLock());
107 if (m_source->lseek(offset, SEEK_SET) < 0)
109 eDebug("lseek failed");
113 int left = m_maxrange;
117 unsigned char packet[188];
118 if (m_source->read(packet, 188) != 188)
120 eDebug("read error");
126 if (packet[0] != 0x47)
132 if (packet[i] == 0x47)
136 offset = m_source->lseek(i - 188, SEEK_CUR);
140 int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
141 int pusi = !!(packet[1] & 0x40);
143 // printf("PID %04x, PUSI %d\n", pid, pusi);
145 unsigned char *payload;
147 /* check for adaption field */
148 if (packet[3] & 0x20)
150 if (packet[4] >= 183)
154 if (packet[5] & 0x10) /* PCR present */
156 pts = ((unsigned long long)(packet[ 6]&0xFF)) << 25;
157 pts |= ((unsigned long long)(packet[ 7]&0xFF)) << 17;
158 pts |= ((unsigned long long)(packet[ 8]&0xFE)) << 9;
159 pts |= ((unsigned long long)(packet[ 9]&0xFF)) << 1;
160 pts |= ((unsigned long long)(packet[10]&0x80)) >> 7;
162 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]);
163 if (fixed && fixupPTS(offset, pts))
168 payload = packet + packet[4] + 4 + 1;
170 payload = packet + 4;
178 /* somehow not a startcode. (this is invalid, since pusi was set.) ignore it. */
179 if (payload[0] || payload[1] || (payload[2] != 1))
182 if (payload[3] == 0xFD)
183 { // stream use extension mechanism defined in ISO 13818-1 Amendment 2
184 if (payload[7] & 1) // PES extension flag
187 if (payload[7] & 0x80) // pts avail
189 if (payload[7] & 0x40) // dts avail
191 if (payload[7] & 0x20) // escr avail
193 if (payload[7] & 0x10) // es rate
195 if (payload[7] & 0x8) // dsm trickmode
197 if (payload[7] & 0x4) // additional copy info
199 if (payload[7] & 0x2) // crc
201 if (payload[8] < offs)
203 uint8_t pef = payload[9+offs++]; // pes extension field
204 if (pef & 1) // pes extension flag 2
206 if (pef & 0x80) // private data flag
208 if (pef & 0x40) // pack header field flag
210 if (pef & 0x20) // program packet sequence counter flag
212 if (pef & 0x10) // P-STD buffer flag
214 if (payload[8] < offs)
216 uint8_t stream_id_extension_len = payload[9+offs++] & 0x7F;
217 if (stream_id_extension_len >= 1)
219 if (payload[8] < (offs + stream_id_extension_len) )
221 if (payload[9+offs] & 0x80) // stream_id_extension_bit (should not set)
223 switch (payload[9+offs])
225 case 0x55 ... 0x5f: // VC-1
227 case 0x71: // AC3 / DTS
230 eDebug("skip unknwn stream_id_extension %02x\n", payload[9+offs]);
243 /* drop non-audio, non-video packets because other streams
244 can be non-compliant.*/
245 else if (((payload[3] & 0xE0) != 0xC0) && // audio
246 ((payload[3] & 0xF0) != 0xE0)) // video
249 if (payload[7] & 0x80) /* PTS */
251 pts = ((unsigned long long)(payload[ 9]&0xE)) << 29;
252 pts |= ((unsigned long long)(payload[10]&0xFF)) << 22;
253 pts |= ((unsigned long long)(payload[11]&0xFE)) << 14;
254 pts |= ((unsigned long long)(payload[12]&0xFF)) << 7;
255 pts |= ((unsigned long long)(payload[13]&0xFE)) >> 1;
258 eDebug("PTS %16llx found at %lld pid %02x stream: %02x", pts, offset, pid, payload[3]);
260 /* convert to zero-based */
261 if (fixed && fixupPTS(offset, pts))
270 int eDVBTSTools::fixupPTS(const off_t &offset, pts_t &now)
272 if (m_use_streaminfo)
274 if (!m_streaminfo.fixupPTS(offset, now))
278 /* for the simple case, we assume one epoch, with up to one wrap around in the middle. */
282 eDebug("begin not valid, can't fixup");
286 pts_t pos = m_pts_begin;
287 if ((now < pos) && ((pos - now) < 90000 * 10))
293 if (now < pos) /* wrap around */
294 now = now + 0x200000000LL - pos;
299 eDebug("eDVBTSTools::fixupPTS failed!");
303 int eDVBTSTools::getOffset(off_t &offset, pts_t &pts, int marg)
305 eDebug("getOffset for pts 0x%llx", pts);
306 if (m_use_streaminfo)
308 if (pts >= m_pts_end && marg > 0 && m_end_valid)
309 offset = m_offset_end;
311 offset = m_streaminfo.getAccessPoint(pts, marg);
315 calcBegin(); calcEnd();
322 if (!m_samples_taken)
325 if (!m_samples.empty())
332 /* search entry before and after */
333 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(pts);
334 std::map<pts_t, off_t>::const_iterator u = l;
336 if (l != m_samples.begin())
339 /* we could have seeked beyond the end */
340 if (u == m_samples.end())
342 /* use last segment for interpolation. */
343 if (l != m_samples.begin())
350 /* if we don't have enough points */
351 if (u == m_samples.end())
354 pts_t pts_diff = u->first - l->first;
355 off_t offset_diff = u->second - l->second;
359 eDebug("something went wrong when taking samples.");
365 eDebug("using: %llx:%llx -> %llx:%llx", l->first, u->first, l->second, u->second);
370 bitrate = offset_diff * 90000 * 8 / pts_diff;
375 offset += ((pts - l->first) * (pts_t)bitrate) / 8ULL / 90000ULL;
376 offset -= offset % 188;
380 if (!takeSample(offset, p))
382 int diff = (p - pts) / 90;
384 eDebug("calculated diff %d ms", diff);
387 eDebug("diff to big, refining");
391 eDebug("no sample taken, refinement not possible.");
396 /* if even the first sample couldn't be taken, fall back. */
397 /* otherwise, return most refined result. */
401 eDebug("aborting. Taking %llx as offset for %lld", offset, pts);
406 int bitrate = calcBitrate();
407 offset = pts * (pts_t)bitrate / 8ULL / 90000ULL;
408 eDebug("fallback, bitrate=%d, results in %016llx", bitrate, offset);
409 offset -= offset % 188;
415 int eDVBTSTools::getNextAccessPoint(pts_t &ts, const pts_t &start, int direction)
417 if (m_use_streaminfo)
418 return m_streaminfo.getNextAccessPoint(ts, start, direction);
421 eDebug("can't get next access point without streaminfo");
426 void eDVBTSTools::calcBegin()
428 if (!m_source->valid())
431 if (!(m_begin_valid || m_futile))
434 if (!getPTS(m_offset_begin, m_pts_begin))
441 void eDVBTSTools::calcEnd()
443 if (!m_source->valid())
446 iDataSourcePositionRestorer r(m_source);
448 eSingleLocker l(m_source->getLock());
450 off_t end = m_source->lseek(0, SEEK_END);
452 if (llabs(end - m_last_filelength) > 1*1024*1024)
454 m_last_filelength = end;
458 // eDebug("file size changed, recalc length");
463 m_offset_end = m_last_filelength;
465 while (!(m_end_valid || m_futile))
473 m_offset_end -= m_maxrange;
474 if (m_offset_end < 0)
477 /* restore offset if getpts fails */
478 off_t off = m_offset_end;
480 if (!getPTS(m_offset_end, m_pts_end))
493 int eDVBTSTools::calcLen(pts_t &len)
495 calcBegin(); calcEnd();
496 if (!(m_begin_valid && m_end_valid))
498 len = m_pts_end - m_pts_begin;
501 len += 0x200000000LL;
505 int eDVBTSTools::calcBitrate()
507 calcBegin(); calcEnd();
508 if (!(m_begin_valid && m_end_valid))
511 pts_t len_in_pts = m_pts_end - m_pts_begin;
515 len_in_pts += 0x200000000LL;
516 off_t len_in_bytes = m_offset_end - m_offset_begin;
521 unsigned long long bitrate = len_in_bytes * 90000 * 8 / len_in_pts;
522 if ((bitrate < 10000) || (bitrate > 100000000))
529 void eDVBTSTools::takeSamples()
536 if (calcLen(dummy) == -1)
540 off_t bytes_per_sample = (m_offset_end - m_offset_begin) / (long long)nr_samples;
541 if (bytes_per_sample < 40*1024*1024)
542 bytes_per_sample = 40*1024*1024;
544 bytes_per_sample -= bytes_per_sample % 188;
546 eDebug("samples step %lld, pts begin %llx, pts end %llx, offs begin %lld, offs end %lld:",
547 bytes_per_sample, m_pts_begin, m_pts_end, m_offset_begin, m_offset_end);
549 for (off_t offset = m_offset_begin; offset < m_offset_end;)
552 if (takeSample(offset, p) && retries--)
555 offset += bytes_per_sample;
557 m_samples[0] = m_offset_begin;
558 m_samples[m_pts_end - m_pts_begin] = m_offset_end;
561 /* returns 0 when a sample was taken. */
562 int eDVBTSTools::takeSample(off_t off, pts_t &p)
564 off_t offset_org = off;
566 if (!eDVBTSTools::getPTS(off, p, 1))
568 /* as we are happily mixing PTS and PCR values (no comment, please), we might
569 end up with some "negative" segments.
571 so check if this new sample is between the previous and the next field*/
573 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(p);
574 std::map<pts_t, off_t>::const_iterator u = l;
576 if (l != m_samples.begin())
579 if (u != m_samples.end())
581 if ((l->second > off) || (u->second < off))
583 eDebug("ignoring sample %lld %lld %lld (%llx %llx %llx)",
584 l->second, off, u->second, l->first, p, u->first);
590 eDebug("adding sample %lld: pts 0x%llx -> pos %lld (diff %lld bytes)", offset_org, p, off, off-offset_org);
597 int eDVBTSTools::findPMT(int &pmt_pid, int &service_id)
599 /* FIXME: this will be factored out soon! */
600 if (!m_source->valid())
602 eDebug(" file not valid");
606 iDataSourcePositionRestorer r(m_source);
608 eSingleLocker l(m_source->getLock());
610 if (m_source->lseek(0, SEEK_SET) < 0)
612 eDebug("seek failed");
616 int left = 5*1024*1024;
620 unsigned char packet[188];
621 if (m_source->read(packet, 188) != 188)
623 eDebug("read error");
628 if (packet[0] != 0x47)
633 if (packet[i] == 0x47)
637 m_source->lseek(i - 188, SEEK_CUR);
641 int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
643 int pusi = !!(packet[1] & 0x40);
648 /* ok, now we have a PES header or section header*/
651 /* check for adaption field */
652 if (packet[3] & 0x20)
654 if (packet[4] >= 183)
656 sec = packet + packet[4] + 4 + 1;
660 if (sec[0]) /* table pointer, assumed to be 0 */
663 if (sec[1] == 0x02) /* program map section */
666 service_id = (sec[4] << 8) | sec[5];
674 int eDVBTSTools::findFrame(off_t &_offset, size_t &len, int &direction, int frame_types)
676 off_t offset = _offset;
678 // eDebug("trying to find iFrame at %llx", offset);
680 if (!m_use_streaminfo)
682 // eDebug("can't get next iframe without streaminfo");
686 /* let's find the iframe before the given offset */
687 unsigned long long data;
694 if (m_streaminfo.getStructureEntry(offset, data, (direction == 0) ? 1 : 0))
696 eDebug("getting structure info for origin offset failed.");
699 if (offset == 0x7fffffffffffffffLL) /* eof */
701 eDebug("reached eof");
704 /* data is usually the start code in the lower 8 bit, and the next byte <<8. we extract the picture type from there */
705 /* we know that we aren't recording startcode 0x09 for mpeg2, so this is safe */
706 /* TODO: check frame_types */
707 int is_start = (data & 0xE0FF) == 0x0009; /* H.264 NAL unit access delimiter with I-frame*/
708 is_start |= (data & 0x3800FF) == 0x080000; /* MPEG2 picture start code with I-frame */
710 int is_frame = ((data & 0xFF) == 0x0009) || ((data & 0xFF) == 0x00); /* H.264 UAD or MPEG2 start code */
719 // eDebug("%08llx@%llx -> %d, %d", data, offset, is_start, nr_frames);
724 --offset; /* move to previous entry */
725 else if (direction == +1)
728 /* let's find the next frame after the given offset */
729 off_t start = offset;
732 if (m_streaminfo.getStructureEntry(offset, data, 1))
734 eDebug("get next failed");
737 if (offset == 0x7fffffffffffffffLL) /* eof */
739 eDebug("reached eof (while looking for end of iframe)");
742 // eDebug("%08llx@%llx (next)", data, offset);
743 } while (((data & 0xFF) != 9) && ((data & 0xFF) != 0x00)); /* next frame */
745 /* align to TS pkt start */
746 // start = start - (start % 188);
747 // offset = offset - (offset % 188);
749 len = offset - start;
751 direction = nr_frames;
752 // eDebug("result: offset=%llx, len: %ld", offset, (int)len);
756 int eDVBTSTools::findNextPicture(off_t &offset, size_t &len, int &distance, int frame_types)
758 int nr_frames, direction;
759 // eDebug("trying to move %d frames at %llx", distance, offset);
761 frame_types = frametypeI; /* TODO: intelligent "allow IP frames when not crossing an I-Frame */
763 off_t new_offset = offset;
764 size_t new_len = len;
773 distance = -distance+1;
778 if (findFrame(new_offset, new_len, dir, frame_types))
780 // eDebug("findFrame failed!\n");
784 distance -= abs(dir);
786 // eDebug("we moved %d, %d to go frames (now at %llx)", dir, distance, new_offset);
788 if (distance >= 0 || direction == 0)
793 nr_frames += abs(dir);
799 nr_frames += abs(dir) + distance; // never jump forward during rewind
803 distance = (direction < 0) ? -nr_frames : nr_frames;
804 // eDebug("in total, we moved %d frames", nr_frames);