trunk 20080912
[gitenigma.git] / lib / dvb / pvrparse.cpp
blobe1fc303270401874ad46c5d778ee492ddc240fff
1 #include <lib/dvb/pvrparse.h>
2 #include <lib/base/eerror.h>
4 #ifndef BYTE_ORDER
5 #error no byte order defined!
6 #endif
8 int eMPEGStreamInformation::save(const char *filename)
10 FILE *f = fopen(filename, "wb");
11 if (!f)
12 return -1;
14 for (std::map<off_t, Timestamp>::const_iterator i(accessPoints.begin()); i != accessPoints.end(); ++i)
16 unsigned long long d[2];
17 #if BYTE_ORDER == BIG_ENDIAN
18 d[0] = i->first;
19 d[1] = i->second;
20 #else
21 d[0] = bswap64(i->first);
22 d[1] = bswap64(i->second);
23 #endif
24 fwrite(d, sizeof(d), 1, f);
26 fclose(f);
28 return 0;
31 int eMPEGStreamInformation::load(const char *filename)
33 FILE *f = fopen(filename, "rb");
34 if (!f)
35 return -1;
36 accessPoints.clear();
37 while (1)
39 unsigned long long d[2];
40 if (fread(d, sizeof(d), 1, f) < 1)
41 break;
43 #if BYTE_ORDER == LITTLE_ENDIAN
44 d[0] = bswap64(d[0]);
45 d[1] = bswap64(d[1]);
46 #endif
47 accessPoints[d[0]] = d[1];
49 fclose(f);
50 fixupDiscontinuties();
51 return 0;
54 eMPEGStreamInformation::operator bool()
56 return !!accessPoints.size();
59 void eMPEGStreamInformation::fixupDiscontinuties()
61 timestampDeltas.clear();
62 if (!accessPoints.size())
63 return;
65 eDebug("Fixing discontinuities ...");
66 Timestamp currentDelta = accessPoints.begin()->second, lastTimestamp = 0;
67 timestampDeltas[accessPoints.begin()->first] = accessPoints.begin()->second;
68 for (std::map<off_t,Timestamp>::const_iterator i(accessPoints.begin()); i != accessPoints.end(); ++i)
70 Timestamp current = i->second - currentDelta;
71 Timestamp diff = current - lastTimestamp;
72 if (diff > (90000*5)) // 5sec diff
74 eDebug("%llx < %llx, have discont. new timestamp is %llx (diff is %llx)!", current, lastTimestamp, i->second, diff);
75 currentDelta = i->second - lastTimestamp;
76 eDebug("current delta now %llx, making current to %llx", currentDelta, i->second - currentDelta);
77 timestampDeltas[i->first] = currentDelta;
79 lastTimestamp = i->second - currentDelta;
81 eDebug("ok, found %d disconts.", timestampDeltas.size());
84 eMPEGStreamInformation::Timestamp eMPEGStreamInformation::getDelta(eMPEGStreamInformation::off_t offset)
86 if (!timestampDeltas.size())
87 return 0;
88 std::map<off_t,Timestamp>::iterator i = timestampDeltas.upper_bound(offset);
90 /* i can be the first when you query for something before the first PTS */
91 if (i != timestampDeltas.begin())
92 --i;
94 return i->second;
97 eMPEGStreamInformation::Timestamp eMPEGStreamInformation::getInterpolated(eMPEGStreamInformation::off_t offset)
99 /* get the PTS values before and after the offset. */
100 std::map<off_t,Timestamp>::iterator before, after;
102 after = accessPoints.upper_bound(offset);
103 before = after;
105 eDebug("query %llx", offset);
107 if (before != accessPoints.begin())
108 --before;
109 else /* we query before the first known timestamp ... FIXME */
111 eDebug("query before");
112 return 0;
115 /* empty... */
116 if (before == accessPoints.end())
118 eDebug("empty");
119 return 0;
122 /* if after == end, then we need to extrapolate ... FIXME */
123 if ((before->first == offset) || (after == accessPoints.end()))
125 eDebug("exact match (or after end..)");
126 return before->second - getDelta(offset);
129 Timestamp before_ts = before->second - getDelta(before->first);
130 Timestamp after_ts = after->second - getDelta(after->first);
132 Timestamp diff = after_ts - before_ts;
133 off_t diff_off = after->first - before->first;
134 eDebug("interpolating: %llx(%llx) .. %llx .. %llx(%llx)", before->first, before_ts, offset, after->first, after_ts),
136 diff = (offset - before->first) * diff / diff_off;
137 eDebug("result %llx + %llx = %llx", before_ts, diff, before_ts + diff);
138 return before_ts + diff;
141 eMPEGStreamInformation::off_t eMPEGStreamInformation::getAccessPoint(eMPEGStreamInformation::Timestamp ts)
143 /* FIXME: more efficient implementation */
144 Timestamp delta = 0;
145 off_t last = 0;
146 for (std::map<off_t, Timestamp>::const_iterator i(accessPoints.begin()); i != accessPoints.end(); ++i)
148 std::map<off_t, Timestamp>::const_iterator d = timestampDeltas.find(i->first);
149 if (d != timestampDeltas.end())
150 delta = d->second;
151 Timestamp c = i->second - delta;
152 if (c > ts)
153 break;
154 last = i->first;
156 return last;
159 eMPEGStreamParserTS::eMPEGStreamParserTS(eMPEGStreamInformation &streaminfo): streaminfo(streaminfo), pktptr(0), pid(-1), needNextPacket(0), skip(0)
163 int eMPEGStreamParserTS::processPacket(const unsigned char *pkt, eMPEGStreamInformation::off_t offset)
165 if (!wantPacket(pkt))
166 printf("ne irgendwas ist da falsch\n");
168 const unsigned char *end = pkt + 188;
170 if (!(pkt[3] & 0x10))
172 eWarning("[TSPARSE] PUSI set but no payload.");
173 return 0;
176 if (pkt[3] & 0x20) // adaption field present?
177 pkt += pkt[4] + 4 + 1; /* skip adaption field and header */
178 else
179 pkt += 4; /* skip header */
181 if (pkt > end)
183 eWarning("[TSPARSE] dropping huge adaption field");
184 return 0;
187 // ok, we now have the start of the payload, aligned with the PES packet start.
188 if (pkt[0] || pkt[1] || (pkt[2] != 1))
190 eWarning("broken startcode");
191 return 0;
195 eMPEGStreamInformation::Timestamp pts = 0;
196 int ptsvalid = 0;
198 if (pkt[7] & 0x80) // PTS present?
200 pts = ((unsigned long long)(pkt[ 9]&0xE)) << 29;
201 pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22;
202 pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14;
203 pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7;
204 pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1;
205 ptsvalid = 1;
207 #if 0
208 int sec = pts / 90000;
209 int frm = pts % 90000;
210 int min = sec / 60;
211 sec %= 60;
212 int hr = min / 60;
213 min %= 60;
214 int d = hr / 24;
215 hr %= 24;
217 eDebug("pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
218 #endif
221 /* advance to payload */
222 pkt += pkt[8] + 9;
224 /* if startcode found */
225 if (!(pkt[0] || pkt[1] || (pkt[2] != 1)))
227 if (pkt[3] == 0xb3) /* sequence header */
229 if (ptsvalid)
231 streaminfo.accessPoints[offset] = pts;
232 eDebug("Sequence header at %llx, pts %llx", offset, pts);
233 } else
234 eDebug("Sequence header but no valid PTS value.");
237 return 0;
240 inline int eMPEGStreamParserTS::wantPacket(const unsigned char *hdr) const
242 if (hdr[0] != 0x47)
244 eDebug("missing sync!");
245 return 0;
247 int ppid = ((hdr[1]&0x1F) << 8) | hdr[2];
249 if (ppid != pid)
250 return 0;
252 if (needNextPacket) /* next packet (on this pid) was required? */
253 return 1;
255 if (hdr[1] & 0x40) /* pusi set: yes. */
256 return 1;
258 return 0;
261 void eMPEGStreamParserTS::parseData(eMPEGStreamInformation::off_t offset, const void *data, unsigned int len)
263 const unsigned char *packet = (const unsigned char*)data;
264 const unsigned char *packet_start = packet;
266 /* sorry for the redundant code here, but there are too many special cases... */
267 while (len)
269 if (pktptr)
271 /* skip last packet */
272 if (pktptr < 0)
274 unsigned int skiplen = -pktptr;
275 if (skiplen > len)
276 skiplen = len;
277 packet += skiplen;
278 len -= skiplen;
279 pktptr += skiplen;
280 continue;
281 } else if (pktptr < 4) /* header not complete, thus we don't know if we want this packet */
283 unsigned int storelen = 4 - pktptr;
284 if (storelen > len)
285 storelen = len;
286 memcpy(pkt + pktptr, packet, storelen);
288 pktptr += storelen;
289 len -= storelen;
290 packet += storelen;
292 if (pktptr == 4)
293 if (!wantPacket(pkt))
295 /* skip packet */
296 packet += 184;
297 len -= 184;
298 pktptr = 0;
299 continue;
302 /* otherwise we complete up to the full packet */
303 unsigned int storelen = 188 - pktptr;
304 if (storelen > len)
305 storelen = len;
306 memcpy(pkt + pktptr, packet, storelen);
307 pktptr += storelen;
308 len -= storelen;
309 packet += storelen;
311 if (pktptr == 188)
313 needNextPacket = processPacket(pkt, offset + (packet - packet_start));
314 pktptr = 0;
316 } else if (len >= 4) /* if we have a full header... */
318 if (wantPacket(packet)) /* decide wheter we need it ... */
320 if (len >= 188) /* packet complete? */
322 needNextPacket = processPacket(packet, offset + (packet - packet_start)); /* process it now. */
323 } else
325 memcpy(pkt, packet, len); /* otherwise queue it up */
326 pktptr = len;
330 /* skip packet */
331 int sk = len;
332 if (sk >= 188)
333 sk = 188;
334 else if (!pktptr) /* we dont want this packet, otherwise pktptr = sk (=len) > 4 */
335 pktptr = sk - 188;
337 len -= sk;
338 packet += sk;
339 } else /* if we don't have a complete header */
341 memcpy(pkt, packet, len); /* complete header next time */
342 pktptr = len;
343 packet += len;
344 len = 0;
349 void eMPEGStreamParserTS::setPid(int _pid)
351 pktptr = 0;
352 pid = _pid;