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;
159 /* somehow not a startcode. (this is invalid, since pusi was set.) ignore it. */
160 if (payload[0] || payload[1] || (payload[2] != 1))
163 /* drop non-audio, non-video packets because other streams
164 can be non-compliant.*/
165 if (((payload[3] & 0xE0) != 0xC0) && // audio
166 ((payload[3] & 0xF0) != 0xE0)) // video
169 if (payload[7] & 0x80) /* PTS */
171 pts = ((unsigned long long)(payload[ 9]&0xE)) << 29;
172 pts |= ((unsigned long long)(payload[10]&0xFF)) << 22;
173 pts |= ((unsigned long long)(payload[11]&0xFE)) << 14;
174 pts |= ((unsigned long long)(payload[12]&0xFF)) << 7;
175 pts |= ((unsigned long long)(payload[13]&0xFE)) >> 1;
178 eDebug("PTS %16llx found at %lld pid %02x stream: %02x", pts, offset, pid, payload[3]);
180 /* convert to zero-based */
181 if (fixed && fixupPTS(offset, pts))
190 int eDVBTSTools::fixupPTS(const off_t &offset, pts_t &now)
192 if (m_use_streaminfo)
194 if (!m_streaminfo.fixupPTS(offset, now))
198 /* for the simple case, we assume one epoch, with up to one wrap around in the middle. */
202 eDebug("begin not valid, can't fixup");
206 pts_t pos = m_pts_begin;
207 if ((now < pos) && ((pos - now) < 90000 * 10))
213 if (now < pos) /* wrap around */
214 now = now + 0x200000000LL - pos;
219 eDebug("eDVBTSTools::fixupPTS failed!");
223 int eDVBTSTools::getOffset(off_t &offset, pts_t &pts, int marg)
225 eDebug("getOffset for pts 0x%llx", pts);
226 if (m_use_streaminfo)
228 if (pts >= m_pts_end && marg > 0 && m_end_valid)
229 offset = m_offset_end;
231 offset = m_streaminfo.getAccessPoint(pts, marg);
235 calcBegin(); calcEnd();
242 if (!m_samples_taken)
245 if (!m_samples.empty())
252 /* search entry before and after */
253 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(pts);
254 std::map<pts_t, off_t>::const_iterator u = l;
256 if (l != m_samples.begin())
259 /* we could have seeked beyond the end */
260 if (u == m_samples.end())
262 /* use last segment for interpolation. */
263 if (l != m_samples.begin())
270 /* if we don't have enough points */
271 if (u == m_samples.end())
274 pts_t pts_diff = u->first - l->first;
275 off_t offset_diff = u->second - l->second;
279 eDebug("something went wrong when taking samples.");
285 eDebug("using: %llx:%llx -> %llx:%llx", l->first, u->first, l->second, u->second);
290 bitrate = offset_diff * 90000 * 8 / pts_diff;
295 offset += ((pts - l->first) * (pts_t)bitrate) / 8ULL / 90000ULL;
296 offset -= offset % 188;
300 if (!takeSample(offset, p))
302 int diff = (p - pts) / 90;
304 eDebug("calculated diff %d ms", diff);
307 eDebug("diff to big, refining");
311 eDebug("no sample taken, refinement not possible.");
316 /* if even the first sample couldn't be taken, fall back. */
317 /* otherwise, return most refined result. */
321 eDebug("aborting. Taking %llx as offset for %lld", offset, pts);
326 int bitrate = calcBitrate();
327 offset = pts * (pts_t)bitrate / 8ULL / 90000ULL;
328 eDebug("fallback, bitrate=%d, results in %016llx", bitrate, offset);
329 offset -= offset % 188;
335 int eDVBTSTools::getNextAccessPoint(pts_t &ts, const pts_t &start, int direction)
337 if (m_use_streaminfo)
338 return m_streaminfo.getNextAccessPoint(ts, start, direction);
341 eDebug("can't get next access point without streaminfo");
346 void eDVBTSTools::calcBegin()
351 if (!(m_begin_valid || m_futile))
354 if (!getPTS(m_offset_begin, m_pts_begin))
361 void eDVBTSTools::calcEnd()
366 eSingleLocker l(m_file_lock);
367 off_t end = m_file.lseek(0, SEEK_END);
369 if (llabs(end - m_last_filelength) > 1*1024*1024)
371 m_last_filelength = end;
375 // eDebug("file size changed, recalc length");
380 m_offset_end = m_last_filelength;
382 while (!(m_end_valid || m_futile))
390 m_offset_end -= m_maxrange;
391 if (m_offset_end < 0)
394 /* restore offset if getpts fails */
395 off_t off = m_offset_end;
397 if (!getPTS(m_offset_end, m_pts_end))
410 int eDVBTSTools::calcLen(pts_t &len)
412 calcBegin(); calcEnd();
413 if (!(m_begin_valid && m_end_valid))
415 len = m_pts_end - m_pts_begin;
418 len += 0x200000000LL;
422 int eDVBTSTools::calcBitrate()
424 calcBegin(); calcEnd();
425 if (!(m_begin_valid && m_end_valid))
428 pts_t len_in_pts = m_pts_end - m_pts_begin;
432 len_in_pts += 0x200000000LL;
433 off_t len_in_bytes = m_offset_end - m_offset_begin;
438 unsigned long long bitrate = len_in_bytes * 90000 * 8 / len_in_pts;
439 if ((bitrate < 10000) || (bitrate > 100000000))
446 void eDVBTSTools::takeSamples()
453 if (calcLen(dummy) == -1)
457 off_t bytes_per_sample = (m_offset_end - m_offset_begin) / (long long)nr_samples;
458 if (bytes_per_sample < 40*1024*1024)
459 bytes_per_sample = 40*1024*1024;
461 bytes_per_sample -= bytes_per_sample % 188;
463 eDebug("samples step %lld, pts begin %llx, pts end %llx, offs begin %lld, offs end %lld:",
464 bytes_per_sample, m_pts_begin, m_pts_end, m_offset_begin, m_offset_end);
466 for (off_t offset = m_offset_begin; offset < m_offset_end;)
469 if (takeSample(offset, p) && retries--)
472 offset += bytes_per_sample;
474 m_samples[0] = m_offset_begin;
475 m_samples[m_pts_end - m_pts_begin] = m_offset_end;
478 /* returns 0 when a sample was taken. */
479 int eDVBTSTools::takeSample(off_t off, pts_t &p)
481 off_t offset_org = off;
483 if (!eDVBTSTools::getPTS(off, p, 1))
485 /* as we are happily mixing PTS and PCR values (no comment, please), we might
486 end up with some "negative" segments.
488 so check if this new sample is between the previous and the next field*/
490 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(p);
491 std::map<pts_t, off_t>::const_iterator u = l;
493 if (l != m_samples.begin())
496 if (u != m_samples.end())
498 if ((l->second > off) || (u->second < off))
500 eDebug("ignoring sample %lld %lld %lld (%llx %llx %llx)",
501 l->second, off, u->second, l->first, p, u->first);
507 eDebug("adding sample %lld: pts 0x%llx -> pos %lld (diff %lld bytes)", offset_org, p, off, off-offset_org);
514 int eDVBTSTools::findPMT(int &pmt_pid, int &service_id)
516 /* FIXME: this will be factored out soon! */
519 eDebug(" file not valid");
523 eSingleLocker l(m_file_lock);
524 if (m_file.lseek(0, SEEK_SET) < 0)
526 eDebug("seek failed");
530 int left = 5*1024*1024;
534 unsigned char packet[188];
535 if (m_file.read(packet, 188) != 188)
537 eDebug("read error");
542 if (packet[0] != 0x47)
547 if (packet[i] == 0x47)
551 m_file.lseek(i - 188, SEEK_CUR);
555 int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
557 int pusi = !!(packet[1] & 0x40);
562 /* ok, now we have a PES header or section header*/
565 /* check for adaption field */
566 if (packet[3] & 0x20)
568 if (packet[4] >= 183)
570 sec = packet + packet[4] + 4 + 1;
574 if (sec[0]) /* table pointer, assumed to be 0 */
577 if (sec[1] == 0x02) /* program map section */
580 service_id = (sec[4] << 8) | sec[5];
588 int eDVBTSTools::findFrame(off_t &_offset, size_t &len, int &direction, int frame_types)
590 off_t offset = _offset;
592 // eDebug("trying to find iFrame at %llx", offset);
594 if (!m_use_streaminfo)
596 // eDebug("can't get next iframe without streaminfo");
600 /* let's find the iframe before the given offset */
601 unsigned long long data;
608 if (m_streaminfo.getStructureEntry(offset, data, (direction == 0) ? 1 : 0))
610 eDebug("getting structure info for origin offset failed.");
613 if (offset == 0x7fffffffffffffffLL) /* eof */
615 eDebug("reached eof");
618 /* data is usually the start code in the lower 8 bit, and the next byte <<8. we extract the picture type from there */
619 /* we know that we aren't recording startcode 0x09 for mpeg2, so this is safe */
620 /* TODO: check frame_types */
621 int is_start = (data & 0xE0FF) == 0x0009; /* H.264 NAL unit access delimiter with I-frame*/
622 is_start |= (data & 0x3800FF) == 0x080000; /* MPEG2 picture start code with I-frame */
624 int is_frame = ((data & 0xFF) == 0x0009) || ((data & 0xFF) == 0x00); /* H.264 UAD or MPEG2 start code */
633 // eDebug("%08llx@%llx -> %d, %d", data, offset, is_start, nr_frames);
638 --offset; /* move to previous entry */
639 else if (direction == +1)
642 /* let's find the next frame after the given offset */
643 off_t start = offset;
646 if (m_streaminfo.getStructureEntry(offset, data, 1))
648 eDebug("get next failed");
651 if (offset == 0x7fffffffffffffffLL) /* eof */
653 eDebug("reached eof (while looking for end of iframe)");
656 // eDebug("%08llx@%llx (next)", data, offset);
657 } while (((data & 0xFF) != 9) && ((data & 0xFF) != 0x00)); /* next frame */
659 /* align to TS pkt start */
660 // start = start - (start % 188);
661 // offset = offset - (offset % 188);
663 len = offset - start;
665 direction = nr_frames;
666 // eDebug("result: offset=%llx, len: %ld", offset, (int)len);
670 int eDVBTSTools::findNextPicture(off_t &offset, size_t &len, int &distance, int frame_types)
672 int nr_frames, direction;
673 // eDebug("trying to move %d frames at %llx", distance, offset);
675 frame_types = frametypeI; /* TODO: intelligent "allow IP frames when not crossing an I-Frame */
677 off_t new_offset = offset;
678 size_t new_len = len;
687 distance = -distance+1;
692 if (findFrame(new_offset, new_len, dir, frame_types))
694 // eDebug("findFrame failed!\n");
698 distance -= abs(dir);
700 // eDebug("we moved %d, %d to go frames (now at %llx)", dir, distance, new_offset);
702 if (distance >= 0 || direction == 0)
707 nr_frames += abs(dir);
713 nr_frames += abs(dir) + distance; // never jump forward during rewind
717 distance = (direction < 0) ? -nr_frames : nr_frames;
718 // eDebug("in total, we moved %d frames", nr_frames);