4 * Created on: 2014. 6. 18.
12 //----------------------------------------------------------------------
14 void Mpeg::seek(HttpHeader &header)
17 off_t byte_offset = 0;
18 std::string position = header.page_params["position"];
19 std::string relative = header.page_params["relative"];
20 if (position.empty() && relative.empty()) {
21 std::string range = header.params["Range"];
22 DEBUG("Range : %s", range.c_str());
23 if((range.length() > 7) && (range.substr(0, 6) == "bytes=")) {
24 range = range.substr(6);
25 if(range.find('-') == (range.length() - 1)) {
26 byte_offset = Util::strtollu(range);
27 DEBUG("Range To : %s -> %llu", range.c_str(), byte_offset);
32 off_t position_offset;
33 if (!relative.empty()) {
34 int dur = calc_length();
35 DEBUG("duration : %d", dur);
36 position_offset = (dur * Util::strtollu(relative)) / 100;
39 position_offset = Util::strtollu(position);
41 position_offset *= 90000;
42 get_offset(byte_offset, position_offset, -1);
45 DEBUG("seek to byte_offset %llu", byte_offset);
46 if (byte_offset > 0) {
47 seek_absolute(byte_offset);
52 WARNING("seek fail.");
55 //----------------------------------------------------------------------
57 off_t Mpeg::seek_internal(off_t offset, int whence)
60 return ::lseek(get_fd(), offset, whence);
63 case SEEK_SET: m_current_offset = offset; break;
64 case SEEK_CUR: m_current_offset += offset; break;
65 case SEEK_END: m_current_offset = m_totallength + offset; break;
68 if (m_current_offset < 0)
70 return m_current_offset;
72 //----------------------------------------------------------------------
74 ssize_t Mpeg::read_internal(off_t offset, void *buf, size_t count)
76 if (offset != m_current_offset) {
77 m_current_offset = seek_internal(offset, SEEK_SET);
78 if (m_current_offset < 0) {
79 return m_current_offset;
82 switch_offset(m_current_offset);
85 if ((m_current_offset + count) > m_totallength)
86 count = m_totallength - m_current_offset;
92 int ret = ::read(get_fd(), buf, count);
94 m_current_offset = m_last_offset += ret;
97 //----------------------------------------------------------------------
99 int Mpeg::switch_offset(off_t off)
102 int filenr = off / m_splitsize;
103 if (filenr >= m_nrfiles)
104 filenr = m_nrfiles - 1;
106 if (filenr != m_current_file) {
109 m_last_offset = m_base_offset = m_splitsize * filenr;
110 m_current_file = filenr;
114 else m_base_offset = 0;
116 return (off != m_last_offset) ? (m_last_offset = ::lseek(get_fd(), off - m_base_offset, SEEK_SET) + m_base_offset) : m_last_offset;
118 //----------------------------------------------------------------------
120 void Mpeg::calc_begin()
122 if (!(m_begin_valid || m_futile)) {
124 if (!get_pts(m_offset_begin, m_pts_begin, 0))
132 //----------------------------------------------------------------------
134 void Mpeg::calc_end()
136 off_t end = seek_internal(0, SEEK_END);
138 if (llabs(end - m_last_filelength) > 1*1024*1024) {
139 m_last_filelength = end;
147 m_offset_end = m_last_filelength;
149 while (!(m_end_valid || m_futile)) {
155 m_offset_end -= 256*1024;
156 if (m_offset_end < 0)
159 off_t off = m_offset_end;
161 if (!get_pts(m_offset_end, m_pts_end, 0))
163 else m_offset_end = off;
171 //----------------------------------------------------------------------
173 int Mpeg::fix_pts(const off_t &offset, pts_t &now)
175 /* for the simple case, we assume one epoch, with up to one wrap around in the middle. */
177 if (!m_begin_valid) {
181 pts_t pos = m_pts_begin;
182 if ((now < pos) && ((pos - now) < 90000 * 10)) {
187 if (now < pos) /* wrap around */
188 now = now + 0x200000000LL - pos;
193 //----------------------------------------------------------------------
195 void Mpeg::take_samples()
200 pts_t dummy = calc_length();
206 off_t bytes_per_sample = (m_offset_end - m_offset_begin) / (long long)nr_samples;
207 if (bytes_per_sample < 40*1024*1024)
208 bytes_per_sample = 40*1024*1024;
210 bytes_per_sample -= bytes_per_sample % 188;
212 DEBUG("samples step %lld, pts begin %llx, pts end %llx, offs begin %lld, offs end %lld:",
213 bytes_per_sample, m_pts_begin, m_pts_end, m_offset_begin, m_offset_end);
215 for (off_t offset = m_offset_begin; offset < m_offset_end;) {
217 if (take_sample(offset, p) && retries--)
220 offset += bytes_per_sample;
222 m_samples[0] = m_offset_begin;
223 m_samples[m_pts_end - m_pts_begin] = m_offset_end;
225 //----------------------------------------------------------------------
227 /* returns 0 when a sample was taken. */
228 int Mpeg::take_sample(off_t off, pts_t &p)
230 off_t offset_org = off;
232 if (!get_pts(off, p, 1)) {
233 /* as we are happily mixing PTS and PCR values (no comment, please), we might
234 end up with some "negative" segments.
235 so check if this new sample is between the previous and the next field*/
236 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(p);
237 std::map<pts_t, off_t>::const_iterator u = l;
239 if (l != m_samples.begin()) {
241 if (u != m_samples.end()) {
242 if ((l->second > off) || (u->second < off)) {
243 DEBUG("ignoring sample %lld %lld %lld (%llx %llx %llx)", l->second, off, u->second, l->first, p, u->first);
249 DEBUG("adding sample %lld: pts 0x%llx -> pos %lld (diff %lld bytes)", offset_org, p, off, off-offset_org);
255 //----------------------------------------------------------------------
257 int Mpeg::calc_bitrate()
260 if (!m_begin_valid || !m_end_valid) {
264 pts_t len_in_pts = m_pts_end - m_pts_begin;
267 if (len_in_pts < 0) {
268 len_in_pts += 0x200000000LL;
270 off_t len_in_bytes = m_offset_end - m_offset_begin;
271 if (!len_in_pts) return -1;
273 unsigned long long bitrate = len_in_bytes * 90000 * 8 / len_in_pts;
274 if ((bitrate < 10000) || (bitrate > 100000000)) {
279 //----------------------------------------------------------------------
281 int Mpeg::get_offset(off_t &offset, pts_t &pts, int marg)
284 if (!m_begin_valid || !m_end_valid) {
288 if (!m_samples_taken) {
292 if (!m_samples.empty()) {
297 /* search entry before and after */
298 std::map<pts_t, off_t>::const_iterator l = m_samples.lower_bound(pts);
299 std::map<pts_t, off_t>::const_iterator u = l;
301 if (l != m_samples.begin())
304 /* we could have seeked beyond the end */
305 if (u == m_samples.end()) {
306 /* use last segment for interpolation. */
307 if (l != m_samples.begin()) {
313 /* if we don't have enough points */
314 if (u == m_samples.end())
317 pts_t pts_diff = u->first - l->first;
318 off_t offset_diff = u->second - l->second;
320 if (offset_diff < 0) {
321 DEBUG("something went wrong when taking samples.");
326 DEBUG("using: %llx:%llx -> %llx:%llx", l->first, u->first, l->second, u->second);
328 int bitrate = (pts_diff) ? (offset_diff * 90000 * 8 / pts_diff) : 0;
330 offset += ((pts - l->first) * (pts_t)bitrate) / 8ULL / 90000ULL;
331 offset -= offset % 188;
334 if (!take_sample(offset, p)) {
335 int diff = (p - pts) / 90;
336 DEBUG("calculated diff %d ms", diff);
338 if (::abs(diff) > 300) {
339 DEBUG("diff to big, refining");
343 else DEBUG("no sample taken, refinement not possible.");
349 DEBUG("aborting. Taking %llx as offset for %lld", offset, pts);
354 int bitrate = calc_bitrate();
355 offset = pts * (pts_t)bitrate / 8ULL / 90000ULL;
356 DEBUG("fallback, bitrate=%d, results in %016llx", bitrate, offset);
357 offset -= offset % 188;
361 //----------------------------------------------------------------------
363 int Mpeg::get_pts(off_t &offset, pts_t &pts, int fixed)
367 offset -= offset % 188;
369 while (left >= 188) {
370 unsigned char packet[188];
371 if (read_internal(offset, packet, 188) != 188) {
378 if (packet[0] != 0x47) {
381 if (packet[i] == 0x47)
388 unsigned char *payload;
389 int pusi = !!(packet[1] & 0x40);
391 /* check for adaption field */
392 if (packet[3] & 0x20) {
393 if (packet[4] >= 183)
396 if (packet[5] & 0x10) { /* PCR present */
397 pts = ((unsigned long long)(packet[ 6]&0xFF)) << 25;
398 pts |= ((unsigned long long)(packet[ 7]&0xFF)) << 17;
399 pts |= ((unsigned long long)(packet[ 8]&0xFE)) << 9;
400 pts |= ((unsigned long long)(packet[ 9]&0xFF)) << 1;
401 pts |= ((unsigned long long)(packet[10]&0x80)) >> 7;
403 if (fixed && fix_pts(offset, pts))
408 payload = packet + packet[4] + 4 + 1;
410 else payload = packet + 4;
414 /* somehow not a startcode. (this is invalid, since pusi was set.) ignore it. */
415 if (payload[0] || payload[1] || (payload[2] != 1))
418 if (payload[3] == 0xFD) { // stream use extension mechanism defined in ISO 13818-1 Amendment 2
419 if (payload[7] & 1) { // PES extension flag
421 if (payload[7] & 0x80) // pts avail
423 if (payload[7] & 0x40) // dts avail
425 if (payload[7] & 0x20) // escr avail
427 if (payload[7] & 0x10) // es rate
429 if (payload[7] & 0x8) // dsm trickmode
431 if (payload[7] & 0x4) // additional copy info
433 if (payload[7] & 0x2) // crc
435 if (payload[8] < offs)
437 uint8_t pef = payload[9+offs++]; // pes extension field
438 if (pef & 1) { // pes extension flag 2
439 if (pef & 0x80) // private data flag
441 if (pef & 0x40) // pack header field flag
443 if (pef & 0x20) // program packet sequence counter flag
445 if (pef & 0x10) // P-STD buffer flag
447 if (payload[8] < offs)
449 uint8_t stream_id_extension_len = payload[9+offs++] & 0x7F;
450 if (stream_id_extension_len >= 1) {
451 if (payload[8] < (offs + stream_id_extension_len) )
453 if (payload[9+offs] & 0x80) // stream_id_extension_bit (should not set)
455 switch (payload[9+offs]) {
456 case 0x55 ... 0x5f: // VC-1
458 case 0x71: // AC3 / DTS
460 case 0x72: // DTS - HD
472 /* drop non-audio, non-video packets because other streams can be non-compliant.*/
473 else if (((payload[3] & 0xE0) != 0xC0) && // audio
474 ((payload[3] & 0xF0) != 0xE0)) { // video
478 if (payload[7] & 0x80) { /* PTS */
479 pts = ((unsigned long long)(payload[ 9]&0xE)) << 29;
480 pts |= ((unsigned long long)(payload[10]&0xFF)) << 22;
481 pts |= ((unsigned long long)(payload[11]&0xFE)) << 14;
482 pts |= ((unsigned long long)(payload[12]&0xFF)) << 7;
483 pts |= ((unsigned long long)(payload[13]&0xFE)) >> 1;
486 return (fixed && fix_pts(offset, pts)) ? -1 : 0;
491 //----------------------------------------------------------------------
493 int Mpeg::calc_length()
495 if (m_duration <= 0) {
496 calc_begin(); calc_end();
497 if (!(m_begin_valid && m_end_valid))
499 pts_t len = m_pts_end - m_pts_begin;
502 len += 0x200000000LL;
506 m_duration = int(len);
510 //----------------------------------------------------------------------