1 #include <lib/dvb/pvrparse.h>
2 #include <lib/base/eerror.h>
6 #error no byte order defined!
9 int eMPEGStreamInformation::save(const char *filename)
11 FILE *f = fopen(filename, "wb");
15 for (std::map<off_t, pts_t>::const_iterator i(m_access_points.begin()); i != m_access_points.end(); ++i)
17 unsigned long long d[2];
18 #if BYTE_ORDER == BIG_ENDIAN
22 d[0] = bswap_64(i->first);
23 d[1] = bswap_64(i->second);
25 fwrite(d, sizeof(d), 1, f);
32 int eMPEGStreamInformation::load(const char *filename)
34 FILE *f = fopen(filename, "rb");
37 m_access_points.clear();
40 unsigned long long d[2];
41 if (fread(d, sizeof(d), 1, f) < 1)
44 #if BYTE_ORDER == LITTLE_ENDIAN
45 d[0] = bswap_64(d[0]);
46 d[1] = bswap_64(d[1]);
48 m_access_points[d[0]] = d[1];
51 fixupDiscontinuties();
55 bool eMPEGStreamInformation::empty()
57 return m_access_points.empty();
60 void eMPEGStreamInformation::fixupDiscontinuties()
62 m_timestamp_deltas.clear();
63 if (!m_access_points.size())
66 int first_is_unreliable = 0;
67 eDebug("Fixing discontinuities ...");
69 /* if we have no delta at the beginning, extrapolate it */
70 if ((m_access_points.find(0) == m_access_points.end()) && (m_access_points.size() > 1))
72 std::map<off_t,pts_t>::const_iterator second = m_access_points.begin();
73 std::map<off_t,pts_t>::const_iterator first = second++;
74 if (first->first < second->first) /* i.e., not equal or broken */
76 off_t diff = second->first - first->first;
77 pts_t tdiff = second->second - first->second;
78 tdiff *= first->first;
80 m_timestamp_deltas[0] = first->second - tdiff;
81 first_is_unreliable = 1;
82 eDebug("first delta is %08llx", first->second - tdiff);
86 if (m_timestamp_deltas.empty())
87 m_timestamp_deltas[m_access_points.begin()->first] = m_access_points.begin()->second;
89 pts_t currentDelta = m_timestamp_deltas.begin()->second, lastpts_t = 0;
90 for (std::map<off_t,pts_t>::const_iterator i(m_access_points.begin()); i != m_access_points.end(); ++i)
92 pts_t current = i->second - currentDelta;
93 pts_t diff = current - lastpts_t;
94 if ((first_is_unreliable) || (diff > (90000*5))) // 5sec diff
96 first_is_unreliable = 0;
97 eDebug("%llx < %llx, have discont. new timestamp is %llx (diff is %llx)!", current, lastpts_t, i->second, diff);
98 currentDelta = i->second - lastpts_t; /* FIXME: should be the extrapolated new timestamp, based on the current rate */
99 eDebug("current delta now %llx, making current to %llx", currentDelta, i->second - currentDelta);
100 m_timestamp_deltas[i->first] = currentDelta;
102 lastpts_t = i->second - currentDelta;
106 eDebug("ok, found %d disconts.", m_timestamp_deltas.size());
109 for (off_t x=0; x < 1000000; x+= 100000)
111 eDebug("%08llx -> %08llx | %08llx", x, getDelta(x), getInterpolated(x));
115 pts_t eMPEGStreamInformation::getDelta(off_t offset)
117 if (!m_timestamp_deltas.size())
119 std::map<off_t,pts_t>::iterator i = m_timestamp_deltas.upper_bound(offset);
121 /* i can be the first when you query for something before the first PTS */
122 if (i != m_timestamp_deltas.begin())
128 pts_t eMPEGStreamInformation::fixuppts_t(off_t offset, pts_t ts)
130 if (!m_timestamp_deltas.size())
132 std::map<off_t, pts_t>::const_iterator i = m_access_points.upper_bound(offset - 1024 * 1024), nearest = m_access_points.end();
134 while (i != m_access_points.end())
136 if ((nearest == m_access_points.end()) || (llabs(i->second - ts) < llabs(nearest->second - ts)))
140 if (nearest == m_access_points.end())
142 return ts - getDelta(nearest->first);
145 pts_t eMPEGStreamInformation::getInterpolated(off_t offset)
147 /* get the PTS values before and after the offset. */
148 std::map<off_t,pts_t>::iterator before, after;
150 after = m_access_points.upper_bound(offset);
153 if (before != m_access_points.begin())
155 else /* we query before the first known timestamp ... FIXME */
159 if (before == m_access_points.end())
162 /* if after == end, then we need to extrapolate ... FIXME */
163 if ((before->first == offset) || (after == m_access_points.end()))
164 return before->second - getDelta(offset);
166 pts_t before_ts = before->second - getDelta(before->first);
167 pts_t after_ts = after->second - getDelta(after->first);
169 // eDebug("%08llx .. ? .. %08llx", before_ts, after_ts);
170 // eDebug("%08llx .. %08llx .. %08llx", before->first, offset, after->first);
172 pts_t diff = after_ts - before_ts;
173 off_t diff_off = after->first - before->first;
175 diff = (offset - before->first) * diff / diff_off;
176 // eDebug("%08llx .. %08llx .. %08llx", before_ts, before_ts + diff, after_ts);
177 return before_ts + diff;
180 off_t eMPEGStreamInformation::getAccessPoint(pts_t ts)
182 /* FIXME: more efficient implementation */
185 for (std::map<off_t, pts_t>::const_iterator i(m_access_points.begin()); i != m_access_points.end(); ++i)
187 std::map<off_t, pts_t>::const_iterator d = m_timestamp_deltas.find(i->first);
188 if (d != m_timestamp_deltas.end())
190 pts_t c = i->second - delta;
198 eMPEGStreamParserTS::eMPEGStreamParserTS(eMPEGStreamInformation &streaminfo): m_streaminfo(streaminfo), m_pktptr(0), m_pid(-1), m_need_next_packet(0), m_skip(0)
202 int eMPEGStreamParserTS::processPacket(const unsigned char *pkt, off_t offset)
204 if (!wantPacket(pkt))
205 printf("ne irgendwas ist da falsch\n");
207 const unsigned char *end = pkt + 188;
209 if (!(pkt[3] & 0x10))
211 eWarning("[TSPARSE] PUSI set but no payload.");
215 if (pkt[3] & 0x20) // adaption field present?
216 pkt += pkt[4] + 4 + 1; /* skip adaption field and header */
218 pkt += 4; /* skip header */
222 eWarning("[TSPARSE] dropping huge adaption field");
226 // ok, we now have the start of the payload, aligned with the PES packet start.
227 if (pkt[0] || pkt[1] || (pkt[2] != 1))
229 eWarning("broken startcode");
237 if (pkt[7] & 0x80) // PTS present?
239 pts = ((unsigned long long)(pkt[ 9]&0xE)) << 29;
240 pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22;
241 pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14;
242 pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7;
243 pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1;
247 int sec = pts / 90000;
248 int frm = pts % 90000;
256 eDebug("pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
260 /* advance to payload */
263 /* if startcode found */
264 if (!(pkt[0] || pkt[1] || (pkt[2] != 1)))
266 if (pkt[3] == 0xb3) /* sequence header */
270 m_streaminfo.m_access_points[offset] = pts;
271 eDebug("Sequence header at %llx, pts %llx", offset, pts);
273 eDebug("Sequence header but no valid PTS value.");
279 inline int eMPEGStreamParserTS::wantPacket(const unsigned char *hdr) const
283 eDebug("missing sync!");
286 int ppid = ((hdr[1]&0x1F) << 8) | hdr[2];
291 if (m_need_next_packet) /* next packet (on this pid) was required? */
294 if (hdr[1] & 0x40) /* pusi set: yes. */
300 void eMPEGStreamParserTS::parseData(off_t offset, const void *data, unsigned int len)
302 const unsigned char *packet = (const unsigned char*)data;
303 const unsigned char *packet_start = packet;
305 /* sorry for the redundant code here, but there are too many special cases... */
310 /* skip last packet */
313 unsigned int skiplen = -m_pktptr;
320 } else if (m_pktptr < 4) /* header not complete, thus we don't know if we want this packet */
322 unsigned int storelen = 4 - m_pktptr;
325 memcpy(m_pkt + m_pktptr, packet, storelen);
327 m_pktptr += storelen;
332 if (!wantPacket(m_pkt))
341 /* otherwise we complete up to the full packet */
342 unsigned int storelen = 188 - m_pktptr;
345 memcpy(m_pkt + m_pktptr, packet, storelen);
346 m_pktptr += storelen;
352 m_need_next_packet = processPacket(m_pkt, offset + (packet - packet_start));
355 } else if (len >= 4) /* if we have a full header... */
357 if (wantPacket(packet)) /* decide wheter we need it ... */
359 if (len >= 188) /* packet complete? */
361 m_need_next_packet = processPacket(packet, offset + (packet - packet_start)); /* process it now. */
364 memcpy(m_pkt, packet, len); /* otherwise queue it up */
373 else if (!m_pktptr) /* we dont want this packet, otherwise m_pktptr = sk (=len) > 4 */
378 } else /* if we don't have a complete header */
380 memcpy(m_pkt, packet, len); /* complete header next time */
388 void eMPEGStreamParserTS::setPid(int _pid)