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;
153 /* somehow not a startcode. (this is invalid, since pusi was set.) ignore it. */
154 if (payload[0] || payload[1] || (payload[2] != 1))
157 if (payload[3] == 0xFD)
158 { // stream use extension mechanism defined in ISO 13818-1 Amendment 2
159 if (payload[7] & 1) // PES extension flag
162 if (payload[7] & 0x80) // pts avail
164 if (payload[7] & 0x40) // dts avail
166 if (payload[7] & 0x20) // escr avail
168 if (payload[7] & 0x10) // es rate
170 if (payload[7] & 0x8) // dsm trickmode
172 if (payload[7] & 0x4) // additional copy info
174 if (payload[7] & 0x2) // crc
176 if (payload[8] < offs)
178 uint8_t pef = payload[9+offs++]; // pes extension field
179 if (pef & 1) // pes extension flag 2
181 if (pef & 0x80) // private data flag
183 if (pef & 0x40) // pack header field flag
185 if (pef & 0x20) // program packet sequence counter flag
187 if (pef & 0x10) // P-STD buffer flag
189 if (payload[8] < offs)
191 uint8_t stream_id_extension_len = payload[9+offs++] & 0x7F;
192 if (stream_id_extension_len >= 1)
194 if (payload[8] < (offs + stream_id_extension_len) )
196 if (payload[9+offs] & 0x80) // stream_id_extension_bit (should not set)
198 switch (payload[9+offs])
200 case 0x55 ... 0x5f: // VC-1
202 case 0x71: // AC3 / DTS
205 eDebug("skip unknwn stream_id_extension %02x\n", payload[9+offs]);
218 /* drop non-audio, non-video packets because other streams
219 can be non-compliant.*/
220 else if (((payload[3] & 0xE0) != 0xC0) && // audio
221 ((payload[3] & 0xF0) != 0xE0)) // video
224 if (payload[7] & 0x80) /* PTS */
226 pts = ((unsigned long long)(payload[ 9]&0xE)) << 29;
227 pts |= ((unsigned long long)(payload[10]&0xFF)) << 22;
228 pts |= ((unsigned long long)(payload[11]&0xFE)) << 14;
229 pts |= ((unsigned long long)(payload[12]&0xFF)) << 7;
230 pts |= ((unsigned long long)(payload[13]&0xFE)) >> 1;
233 eDebug("PTS %16llx found at %lld pid %02x stream: %02x", pts, offset, pid, payload[3]);
235 /* convert to zero-based */
236 if (fixed && fixupPTS(offset, pts))
245 int eDVBTSTools::fixupPTS(const off_t &offset, pts_t &now)
247 if (m_use_streaminfo)
249 if (!m_streaminfo.fixupPTS(offset, now))
253 /* for the simple case, we assume one epoch, with up to one wrap around in the middle. */
257 eDebug("begin not valid, can't fixup");
261 pts_t pos = m_pts_begin;
262 if ((now < pos) && ((pos - now) < 90000 * 10))
268 if (now < pos) /* wrap around */
269 now = now + 0x200000000LL - pos;
274 eDebug("eDVBTSTools::fixupPTS failed!");
278 int eDVBTSTools::getOffset(off_t &offset, pts_t &pts, int marg)
280 eDebug("getOffset for pts 0x%llx", pts);
281 if (m_use_streaminfo)
283 if (pts >= m_pts_end && marg > 0 && m_end_valid)
284 offset = m_offset_end;
286 offset = m_streaminfo.getAccessPoint(pts, marg);
290 calcBegin(); calcEnd();
297 if (!m_samples_taken)
300 if (!m_samples.empty())
307 /* search entry before and after */
308 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(pts);
309 std::map<pts_t, off_t>::const_iterator u = l;
311 if (l != m_samples.begin())
314 /* we could have seeked beyond the end */
315 if (u == m_samples.end())
317 /* use last segment for interpolation. */
318 if (l != m_samples.begin())
325 /* if we don't have enough points */
326 if (u == m_samples.end())
329 pts_t pts_diff = u->first - l->first;
330 off_t offset_diff = u->second - l->second;
334 eDebug("something went wrong when taking samples.");
340 eDebug("using: %llx:%llx -> %llx:%llx", l->first, u->first, l->second, u->second);
345 bitrate = offset_diff * 90000 * 8 / pts_diff;
350 offset += ((pts - l->first) * (pts_t)bitrate) / 8ULL / 90000ULL;
351 offset -= offset % 188;
355 if (!takeSample(offset, p))
357 int diff = (p - pts) / 90;
359 eDebug("calculated diff %d ms", diff);
362 eDebug("diff to big, refining");
366 eDebug("no sample taken, refinement not possible.");
371 /* if even the first sample couldn't be taken, fall back. */
372 /* otherwise, return most refined result. */
376 eDebug("aborting. Taking %llx as offset for %lld", offset, pts);
381 int bitrate = calcBitrate();
382 offset = pts * (pts_t)bitrate / 8ULL / 90000ULL;
383 eDebug("fallback, bitrate=%d, results in %016llx", bitrate, offset);
384 offset -= offset % 188;
390 int eDVBTSTools::getNextAccessPoint(pts_t &ts, const pts_t &start, int direction)
392 if (m_use_streaminfo)
393 return m_streaminfo.getNextAccessPoint(ts, start, direction);
396 eDebug("can't get next access point without streaminfo");
401 void eDVBTSTools::calcBegin()
406 if (!(m_begin_valid || m_futile))
409 if (!getPTS(m_offset_begin, m_pts_begin))
416 void eDVBTSTools::calcEnd()
421 off_t end = m_file.lseek(0, SEEK_END);
423 if (llabs(end - m_last_filelength) > 1*1024*1024)
425 m_last_filelength = end;
429 // eDebug("file size changed, recalc length");
434 m_offset_end = m_last_filelength;
436 while (!(m_end_valid || m_futile))
444 m_offset_end -= m_maxrange;
445 if (m_offset_end < 0)
448 /* restore offset if getpts fails */
449 off_t off = m_offset_end;
451 if (!getPTS(m_offset_end, m_pts_end))
464 int eDVBTSTools::calcLen(pts_t &len)
466 calcBegin(); calcEnd();
467 if (!(m_begin_valid && m_end_valid))
469 len = m_pts_end - m_pts_begin;
472 len += 0x200000000LL;
476 int eDVBTSTools::calcBitrate()
478 calcBegin(); calcEnd();
479 if (!(m_begin_valid && m_end_valid))
482 pts_t len_in_pts = m_pts_end - m_pts_begin;
486 len_in_pts += 0x200000000LL;
487 off_t len_in_bytes = m_offset_end - m_offset_begin;
492 unsigned long long bitrate = len_in_bytes * 90000 * 8 / len_in_pts;
493 if ((bitrate < 10000) || (bitrate > 100000000))
500 void eDVBTSTools::takeSamples()
507 if (calcLen(dummy) == -1)
511 off_t bytes_per_sample = (m_offset_end - m_offset_begin) / (long long)nr_samples;
512 if (bytes_per_sample < 40*1024*1024)
513 bytes_per_sample = 40*1024*1024;
515 bytes_per_sample -= bytes_per_sample % 188;
517 eDebug("samples step %lld, pts begin %llx, pts end %llx, offs begin %lld, offs end %lld:",
518 bytes_per_sample, m_pts_begin, m_pts_end, m_offset_begin, m_offset_end);
520 for (off_t offset = m_offset_begin; offset < m_offset_end;)
523 if (takeSample(offset, p) && retries--)
526 offset += bytes_per_sample;
528 m_samples[0] = m_offset_begin;
529 m_samples[m_pts_end - m_pts_begin] = m_offset_end;
532 /* returns 0 when a sample was taken. */
533 int eDVBTSTools::takeSample(off_t off, pts_t &p)
535 off_t offset_org = off;
537 if (!eDVBTSTools::getPTS(off, p, 1))
539 /* as we are happily mixing PTS and PCR values (no comment, please), we might
540 end up with some "negative" segments.
542 so check if this new sample is between the previous and the next field*/
544 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(p);
545 std::map<pts_t, off_t>::const_iterator u = l;
547 if (l != m_samples.begin())
550 if (u != m_samples.end())
552 if ((l->second > off) || (u->second < off))
554 eDebug("ignoring sample %lld %lld %lld (%llx %llx %llx)",
555 l->second, off, u->second, l->first, p, u->first);
561 eDebug("adding sample %lld: pts 0x%llx -> pos %lld (diff %lld bytes)", offset_org, p, off, off-offset_org);
568 int eDVBTSTools::findPMT(int &pmt_pid, int &service_id)
570 /* FIXME: this will be factored out soon! */
573 eDebug(" file not valid");
577 if (m_file.lseek(0, SEEK_SET) < 0)
579 eDebug("seek failed");
583 int left = 5*1024*1024;
587 unsigned char packet[188];
588 if (m_file.read(packet, 188) != 188)
590 eDebug("read error");
595 if (packet[0] != 0x47)
600 if (packet[i] == 0x47)
604 m_file.lseek(i - 188, SEEK_CUR);
608 int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
610 int pusi = !!(packet[1] & 0x40);
615 /* ok, now we have a PES header or section header*/
618 /* check for adaption field */
619 if (packet[3] & 0x20)
621 if (packet[4] >= 183)
623 sec = packet + packet[4] + 4 + 1;
627 if (sec[0]) /* table pointer, assumed to be 0 */
630 if (sec[1] == 0x02) /* program map section */
633 service_id = (sec[4] << 8) | sec[5];
641 int eDVBTSTools::findFrame(off_t &_offset, size_t &len, int &direction, int frame_types)
643 off_t offset = _offset;
645 // eDebug("trying to find iFrame at %llx", offset);
647 if (!m_use_streaminfo)
649 // eDebug("can't get next iframe without streaminfo");
653 /* let's find the iframe before the given offset */
654 unsigned long long data;
661 if (m_streaminfo.getStructureEntry(offset, data, (direction == 0) ? 1 : 0))
663 eDebug("getting structure info for origin offset failed.");
666 if (offset == 0x7fffffffffffffffLL) /* eof */
668 eDebug("reached eof");
671 /* data is usually the start code in the lower 8 bit, and the next byte <<8. we extract the picture type from there */
672 /* we know that we aren't recording startcode 0x09 for mpeg2, so this is safe */
673 /* TODO: check frame_types */
674 int is_start = (data & 0xE0FF) == 0x0009; /* H.264 NAL unit access delimiter with I-frame*/
675 is_start |= (data & 0x3800FF) == 0x080000; /* MPEG2 picture start code with I-frame */
677 int is_frame = ((data & 0xFF) == 0x0009) || ((data & 0xFF) == 0x00); /* H.264 UAD or MPEG2 start code */
686 // eDebug("%08llx@%llx -> %d, %d", data, offset, is_start, nr_frames);
691 --offset; /* move to previous entry */
692 else if (direction == +1)
695 /* let's find the next frame after the given offset */
696 off_t start = offset;
699 if (m_streaminfo.getStructureEntry(offset, data, 1))
701 eDebug("get next failed");
704 if (offset == 0x7fffffffffffffffLL) /* eof */
706 eDebug("reached eof (while looking for end of iframe)");
709 // eDebug("%08llx@%llx (next)", data, offset);
710 } while (((data & 0xFF) != 9) && ((data & 0xFF) != 0x00)); /* next frame */
712 /* align to TS pkt start */
713 // start = start - (start % 188);
714 // offset = offset - (offset % 188);
716 len = offset - start;
718 direction = nr_frames;
719 // eDebug("result: offset=%llx, len: %ld", offset, (int)len);
723 int eDVBTSTools::findNextPicture(off_t &offset, size_t &len, int &distance, int frame_types)
725 int nr_frames, direction;
726 // eDebug("trying to move %d frames at %llx", distance, offset);
728 frame_types = frametypeI; /* TODO: intelligent "allow IP frames when not crossing an I-Frame */
730 off_t new_offset = offset;
731 size_t new_len = len;
740 distance = -distance+1;
745 if (findFrame(new_offset, new_len, dir, frame_types))
747 // eDebug("findFrame failed!\n");
751 distance -= abs(dir);
753 // eDebug("we moved %d, %d to go frames (now at %llx)", dir, distance, new_offset);
755 if (distance >= 0 || direction == 0)
760 nr_frames += abs(dir);
766 nr_frames += abs(dir) + distance; // never jump forward during rewind
770 distance = (direction < 0) ? -nr_frames : nr_frames;
771 // eDebug("in total, we moved %d frames", nr_frames);