1 #define _ISOC99_SOURCE /* for llabs */
2 #include <lib/dvb/tstools.h>
3 #include <lib/base/eerror.h>
9 eDVBTSTools::eDVBTSTools()
13 m_maxrange = 256*1024;
21 m_last_filelength = 0;
26 eDVBTSTools::~eDVBTSTools()
31 int eDVBTSTools::openFile(const char *filename, int nostreaminfo)
37 eDebug("loading streaminfo for %s", filename);
38 m_streaminfo.load(filename);
41 if (!m_streaminfo.empty())
45 // eDebug("no recorded stream information available");
51 eSingleLocker l(m_file_lock);
52 if (m_file.open(filename, 1) < 0)
57 void eDVBTSTools::closeFile()
59 eSingleLocker l(m_file_lock);
63 void eDVBTSTools::setSyncPID(int pid)
68 void eDVBTSTools::setSearchRange(int maxrange)
70 m_maxrange = maxrange;
73 /* getPTS extracts a pts value from any PID at a given offset. */
74 int eDVBTSTools::getPTS(off_t &offset, pts_t &pts, int fixed)
77 if (!m_streaminfo.getPTS(offset, pts))
83 offset -= offset % 188;
85 eSingleLocker l(m_file_lock);
86 if (m_file.lseek(offset, SEEK_SET) < 0)
88 eDebug("lseek failed");
92 int left = m_maxrange;
96 unsigned char packet[188];
97 if (m_file.read(packet, 188) != 188)
105 if (packet[0] != 0x47)
111 if (packet[i] == 0x47)
115 offset = m_file.lseek(i - 188, SEEK_CUR);
119 int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
120 int pusi = !!(packet[1] & 0x40);
122 // printf("PID %04x, PUSI %d\n", pid, pusi);
124 unsigned char *payload;
126 /* check for adaption field */
127 if (packet[3] & 0x20)
129 if (packet[4] >= 183)
133 if (packet[5] & 0x10) /* PCR present */
135 pts = ((unsigned long long)(packet[ 6]&0xFF)) << 25;
136 pts |= ((unsigned long long)(packet[ 7]&0xFF)) << 17;
137 pts |= ((unsigned long long)(packet[ 8]&0xFE)) << 9;
138 pts |= ((unsigned long long)(packet[ 9]&0xFF)) << 1;
139 pts |= ((unsigned long long)(packet[10]&0x80)) >> 7;
141 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]);
142 if (fixed && fixupPTS(offset, pts))
147 payload = packet + packet[4] + 4 + 1;
149 payload = packet + 4;
157 /* somehow not a startcode. (this is invalid, since pusi was set.) ignore it. */
158 if (payload[0] || payload[1] || (payload[2] != 1))
161 if (payload[3] == 0xFD)
162 { // stream use extension mechanism defined in ISO 13818-1 Amendment 2
163 if (payload[7] & 1) // PES extension flag
166 if (payload[7] & 0x80) // pts avail
168 if (payload[7] & 0x40) // dts avail
170 if (payload[7] & 0x20) // escr avail
172 if (payload[7] & 0x10) // es rate
174 if (payload[7] & 0x8) // dsm trickmode
176 if (payload[7] & 0x4) // additional copy info
178 if (payload[7] & 0x2) // crc
180 if (payload[8] < offs)
182 uint8_t pef = payload[9+offs++]; // pes extension field
183 if (pef & 1) // pes extension flag 2
185 if (pef & 0x80) // private data flag
187 if (pef & 0x40) // pack header field flag
189 if (pef & 0x20) // program packet sequence counter flag
191 if (pef & 0x10) // P-STD buffer flag
193 if (payload[8] < offs)
195 uint8_t stream_id_extension_len = payload[9+offs++] & 0x7F;
196 if (stream_id_extension_len >= 1)
198 if (payload[8] < (offs + stream_id_extension_len) )
200 if (payload[9+offs] & 0x80) // stream_id_extension_bit (should not set)
202 switch (payload[9+offs])
204 case 0x55 ... 0x5f: // VC-1
206 case 0x71: // AC3 / DTS
209 eDebug("skip unknwn stream_id_extension %02x\n", payload[9+offs]);
222 /* drop non-audio, non-video packets because other streams
223 can be non-compliant.*/
224 else if (((payload[3] & 0xE0) != 0xC0) && // audio
225 ((payload[3] & 0xF0) != 0xE0)) // video
228 if (payload[7] & 0x80) /* PTS */
230 pts = ((unsigned long long)(payload[ 9]&0xE)) << 29;
231 pts |= ((unsigned long long)(payload[10]&0xFF)) << 22;
232 pts |= ((unsigned long long)(payload[11]&0xFE)) << 14;
233 pts |= ((unsigned long long)(payload[12]&0xFF)) << 7;
234 pts |= ((unsigned long long)(payload[13]&0xFE)) >> 1;
237 eDebug("PTS %16llx found at %lld pid %02x stream: %02x", pts, offset, pid, payload[3]);
239 /* convert to zero-based */
240 if (fixed && fixupPTS(offset, pts))
249 int eDVBTSTools::fixupPTS(const off_t &offset, pts_t &now)
251 if (m_use_streaminfo)
253 if (!m_streaminfo.fixupPTS(offset, now))
257 /* for the simple case, we assume one epoch, with up to one wrap around in the middle. */
261 eDebug("begin not valid, can't fixup");
265 pts_t pos = m_pts_begin;
266 if ((now < pos) && ((pos - now) < 90000 * 10))
272 if (now < pos) /* wrap around */
273 now = now + 0x200000000LL - pos;
278 eDebug("eDVBTSTools::fixupPTS failed!");
282 int eDVBTSTools::getOffset(off_t &offset, pts_t &pts, int marg)
284 eDebug("getOffset for pts 0x%llx", pts);
285 if (m_use_streaminfo)
287 if (pts >= m_pts_end && marg > 0 && m_end_valid)
288 offset = m_offset_end;
290 offset = m_streaminfo.getAccessPoint(pts, marg);
294 calcBegin(); calcEnd();
301 if (!m_samples_taken)
304 if (!m_samples.empty())
311 /* search entry before and after */
312 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(pts);
313 std::map<pts_t, off_t>::const_iterator u = l;
315 if (l != m_samples.begin())
318 /* we could have seeked beyond the end */
319 if (u == m_samples.end())
321 /* use last segment for interpolation. */
322 if (l != m_samples.begin())
329 /* if we don't have enough points */
330 if (u == m_samples.end())
333 pts_t pts_diff = u->first - l->first;
334 off_t offset_diff = u->second - l->second;
338 eDebug("something went wrong when taking samples.");
344 eDebug("using: %llx:%llx -> %llx:%llx", l->first, u->first, l->second, u->second);
349 bitrate = offset_diff * 90000 * 8 / pts_diff;
354 offset += ((pts - l->first) * (pts_t)bitrate) / 8ULL / 90000ULL;
355 offset -= offset % 188;
359 if (!takeSample(offset, p))
361 int diff = (p - pts) / 90;
363 eDebug("calculated diff %d ms", diff);
366 eDebug("diff to big, refining");
370 eDebug("no sample taken, refinement not possible.");
375 /* if even the first sample couldn't be taken, fall back. */
376 /* otherwise, return most refined result. */
380 eDebug("aborting. Taking %llx as offset for %lld", offset, pts);
385 int bitrate = calcBitrate();
386 offset = pts * (pts_t)bitrate / 8ULL / 90000ULL;
387 eDebug("fallback, bitrate=%d, results in %016llx", bitrate, offset);
388 offset -= offset % 188;
394 int eDVBTSTools::getNextAccessPoint(pts_t &ts, const pts_t &start, int direction)
396 if (m_use_streaminfo)
397 return m_streaminfo.getNextAccessPoint(ts, start, direction);
400 eDebug("can't get next access point without streaminfo");
405 void eDVBTSTools::calcBegin()
410 if (!(m_begin_valid || m_futile))
413 if (!getPTS(m_offset_begin, m_pts_begin))
420 void eDVBTSTools::calcEnd()
425 eSingleLocker l(m_file_lock);
426 off_t end = m_file.lseek(0, SEEK_END);
428 if (llabs(end - m_last_filelength) > 1*1024*1024)
430 m_last_filelength = end;
434 // eDebug("file size changed, recalc length");
439 m_offset_end = m_last_filelength;
441 while (!(m_end_valid || m_futile))
449 m_offset_end -= m_maxrange;
450 if (m_offset_end < 0)
453 /* restore offset if getpts fails */
454 off_t off = m_offset_end;
456 if (!getPTS(m_offset_end, m_pts_end))
469 int eDVBTSTools::calcLen(pts_t &len)
471 calcBegin(); calcEnd();
472 if (!(m_begin_valid && m_end_valid))
474 len = m_pts_end - m_pts_begin;
477 len += 0x200000000LL;
481 int eDVBTSTools::calcBitrate()
483 calcBegin(); calcEnd();
484 if (!(m_begin_valid && m_end_valid))
487 pts_t len_in_pts = m_pts_end - m_pts_begin;
491 len_in_pts += 0x200000000LL;
492 off_t len_in_bytes = m_offset_end - m_offset_begin;
497 unsigned long long bitrate = len_in_bytes * 90000 * 8 / len_in_pts;
498 if ((bitrate < 10000) || (bitrate > 100000000))
505 void eDVBTSTools::takeSamples()
512 if (calcLen(dummy) == -1)
516 off_t bytes_per_sample = (m_offset_end - m_offset_begin) / (long long)nr_samples;
517 if (bytes_per_sample < 40*1024*1024)
518 bytes_per_sample = 40*1024*1024;
520 bytes_per_sample -= bytes_per_sample % 188;
522 eDebug("samples step %lld, pts begin %llx, pts end %llx, offs begin %lld, offs end %lld:",
523 bytes_per_sample, m_pts_begin, m_pts_end, m_offset_begin, m_offset_end);
525 for (off_t offset = m_offset_begin; offset < m_offset_end;)
528 if (takeSample(offset, p) && retries--)
531 offset += bytes_per_sample;
533 m_samples[0] = m_offset_begin;
534 m_samples[m_pts_end - m_pts_begin] = m_offset_end;
537 /* returns 0 when a sample was taken. */
538 int eDVBTSTools::takeSample(off_t off, pts_t &p)
540 off_t offset_org = off;
542 if (!eDVBTSTools::getPTS(off, p, 1))
544 /* as we are happily mixing PTS and PCR values (no comment, please), we might
545 end up with some "negative" segments.
547 so check if this new sample is between the previous and the next field*/
549 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(p);
550 std::map<pts_t, off_t>::const_iterator u = l;
552 if (l != m_samples.begin())
555 if (u != m_samples.end())
557 if ((l->second > off) || (u->second < off))
559 eDebug("ignoring sample %lld %lld %lld (%llx %llx %llx)",
560 l->second, off, u->second, l->first, p, u->first);
566 eDebug("adding sample %lld: pts 0x%llx -> pos %lld (diff %lld bytes)", offset_org, p, off, off-offset_org);
573 int eDVBTSTools::findPMT(int &pmt_pid, int &service_id)
575 /* FIXME: this will be factored out soon! */
578 eDebug(" file not valid");
582 eSingleLocker l(m_file_lock);
583 if (m_file.lseek(0, SEEK_SET) < 0)
585 eDebug("seek failed");
589 int left = 5*1024*1024;
593 unsigned char packet[188];
594 if (m_file.read(packet, 188) != 188)
596 eDebug("read error");
601 if (packet[0] != 0x47)
606 if (packet[i] == 0x47)
610 m_file.lseek(i - 188, SEEK_CUR);
614 int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
616 int pusi = !!(packet[1] & 0x40);
621 /* ok, now we have a PES header or section header*/
624 /* check for adaption field */
625 if (packet[3] & 0x20)
627 if (packet[4] >= 183)
629 sec = packet + packet[4] + 4 + 1;
633 if (sec[0]) /* table pointer, assumed to be 0 */
636 if (sec[1] == 0x02) /* program map section */
639 service_id = (sec[4] << 8) | sec[5];
647 int eDVBTSTools::findFrame(off_t &_offset, size_t &len, int &direction, int frame_types)
649 off_t offset = _offset;
651 // eDebug("trying to find iFrame at %llx", offset);
653 if (!m_use_streaminfo)
655 // eDebug("can't get next iframe without streaminfo");
659 /* let's find the iframe before the given offset */
660 unsigned long long data;
667 if (m_streaminfo.getStructureEntry(offset, data, (direction == 0) ? 1 : 0))
669 eDebug("getting structure info for origin offset failed.");
672 if (offset == 0x7fffffffffffffffLL) /* eof */
674 eDebug("reached eof");
677 /* data is usually the start code in the lower 8 bit, and the next byte <<8. we extract the picture type from there */
678 /* we know that we aren't recording startcode 0x09 for mpeg2, so this is safe */
679 /* TODO: check frame_types */
680 int is_start = (data & 0xE0FF) == 0x0009; /* H.264 NAL unit access delimiter with I-frame*/
681 is_start |= (data & 0x3800FF) == 0x080000; /* MPEG2 picture start code with I-frame */
683 int is_frame = ((data & 0xFF) == 0x0009) || ((data & 0xFF) == 0x00); /* H.264 UAD or MPEG2 start code */
692 // eDebug("%08llx@%llx -> %d, %d", data, offset, is_start, nr_frames);
697 --offset; /* move to previous entry */
698 else if (direction == +1)
701 /* let's find the next frame after the given offset */
702 off_t start = offset;
705 if (m_streaminfo.getStructureEntry(offset, data, 1))
707 eDebug("get next failed");
710 if (offset == 0x7fffffffffffffffLL) /* eof */
712 eDebug("reached eof (while looking for end of iframe)");
715 // eDebug("%08llx@%llx (next)", data, offset);
716 } while (((data & 0xFF) != 9) && ((data & 0xFF) != 0x00)); /* next frame */
718 /* align to TS pkt start */
719 // start = start - (start % 188);
720 // offset = offset - (offset % 188);
722 len = offset - start;
724 direction = nr_frames;
725 // eDebug("result: offset=%llx, len: %ld", offset, (int)len);
729 int eDVBTSTools::findNextPicture(off_t &offset, size_t &len, int &distance, int frame_types)
731 int nr_frames, direction;
732 // eDebug("trying to move %d frames at %llx", distance, offset);
734 frame_types = frametypeI; /* TODO: intelligent "allow IP frames when not crossing an I-Frame */
736 off_t new_offset = offset;
737 size_t new_len = len;
746 distance = -distance+1;
751 if (findFrame(new_offset, new_len, dir, frame_types))
753 // eDebug("findFrame failed!\n");
757 distance -= abs(dir);
759 // eDebug("we moved %d, %d to go frames (now at %llx)", dir, distance, new_offset);
761 if (distance >= 0 || direction == 0)
766 nr_frames += abs(dir);
772 nr_frames += abs(dir) + distance; // never jump forward during rewind
776 distance = (direction < 0) ? -nr_frames : nr_frames;
777 // eDebug("in total, we moved %d frames", nr_frames);