2 Copyright 2005-2007 Mark Calderbank
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "demuxervdr.h"
26 #define __LITTLE_ENDIAN 1234
27 #define __BIG_ENDIAN 4321
28 #define __BYTE_ORDER __LITTLE_ENDIAN
31 #define PTS_JUMP_MARGIN 10000
32 #define PTS_ALLOWANCE 90000
34 // TODO: PTS class to handle wrapping arithmetic & comparisons?
35 static ULLONG PTSDistance(ULLONG pts1, ULLONG pts2)
37 // Assume pts1, pts2 < 2^33; calculate shortest distance between
38 ULLONG ret = (pts1 > pts2) ? pts1 - pts2 : pts2 - pts1;
39 if (ret > (1LL<<32)) ret = (1LL<<33) - ret;
43 static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)
45 // Assume pts1, pts2 < 2^33; calculate pts1 - pts2
49 return (1LL<<33) + pts1 - pts2;
52 DemuxerVDR::DemuxerVDR()
54 frameCounting = false;
55 packetCounting = false;
58 void DemuxerVDR::reset()
60 frameCounting = false;
61 packetCounting = false;
66 void DemuxerVDR::flush()
73 int DemuxerVDR::scan(UCHAR *buf, int len)
75 // Temporarily, just look for the lowest audio stream and return it
76 UCHAR HiByte = PESTYPE_AUDMAX;
81 UINT pattern = *(UINT*)buf;
84 #if __BYTE_ORDER == __BIG_ENDIAN
85 if (pattern < (UINT)(0x100 | PESTYPE_AUD0) ||
86 pattern > (UINT)(0x100 | HiByte)) continue;
87 HiByte = pattern & 0xFF;
89 if ((pattern & 0xFFFFFF) != 0x010000 ||
90 pattern < ((UINT)PESTYPE_AUD0 << 24) ||
91 pattern > ((UINT)HiByte << 24)) continue;
92 HiByte = pattern >> 24;
95 if (HiByte == PESTYPE_AUD0) break;
100 int DemuxerVDR::findPTS(UCHAR* buf, int len, ULLONG* dest)
104 UINT pattern = *(UINT*)buf;
106 #if __BYTE_ORDER == __BIG_ENDIAN
107 if (pattern < (0x100 | PESTYPE_AUD0) ||
108 pattern > (0x100 | PESTYPE_VIDMAX)) continue;
110 if ((pattern & 0xFFFFFF) != 0x010000 ||
111 pattern < ((UINT)PESTYPE_AUD0 << 24) ||
112 pattern > ((UINT)PESTYPE_VIDMAX << 24)) continue;
114 if ((buf[5] & 0xC0) != 0x80) continue;
116 UINT packetlength = ((UINT)buf[3] << 8) | buf[4];
118 if ( buf[6] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
120 if ( (buf[8] & 0x01) != 0x01 ||
121 (buf[10] & 0x01) != 0x01 ||
122 (buf[12] & 0x01) != 0x01) continue;
124 *dest = ( (ULLONG)(buf[8] & 0x0E) << 29 ) |
125 ( (ULLONG)(buf[9]) << 22 ) |
126 ( (ULLONG)(buf[10] & 0xFE) << 14 ) |
127 ( (ULLONG)(buf[11]) << 7 ) |
128 ( (ULLONG)(buf[12] & 0xFE) >> 1 );
133 buf += packetlength; len -= packetlength;
139 void DemuxerVDR::setFrameNum(ULONG frame)
141 frameCounting = true;
143 Log::getInstance()->log("Demuxer", Log::DEBUG, "setFrameNum %d", frame);
146 void DemuxerVDR::setPacketNum(ULONG npacket)
148 packetCounting = true;
149 packetNumber = npacket;
150 Log::getInstance()->log("Demuxer", Log::DEBUG, "setPacketNum %d", npacket);
153 int DemuxerVDR::put(UCHAR* buf, int len)
155 int ret = 0; // return number of bytes consumed
158 if (submitPacket(packet) == 0) // Still full!
164 if (state > 0) // We are half way through a PES packet.
166 if (len >= state) // The remainder of the packet is available.
168 packet.write(buf, state);
169 buf += state; len -= state; ret += state;
171 parseVDRPacketDetails();
172 if (submitPacket(packet) == 0) // Stream is full
178 else // Write what we have, then exit.
180 packet.write(buf, len);
192 if (*buf == 0x00) state--; else state = 0;
196 if (*buf == 0x01) state--; else if (*buf != 0x00) state = 0;
200 if ((*buf >= PESTYPE_VID0 && *buf <= PESTYPE_VIDMAX) ||
201 (*buf >= PESTYPE_AUD0 && *buf <= PESTYPE_AUDMAX) ||
202 (*buf == PESTYPE_PRIVATE_1))
207 else if (*buf == 0x00)
214 packetLength = ((UINT)*buf) << 8;
219 packetLength += *buf;
225 if (state == -6) // Packet header complete
227 if (len >= packetLength) // The entire packet is available.
229 packet.write(buf, packetLength);
230 buf += packetLength; len -= packetLength; ret += packetLength;
232 parseVDRPacketDetails();
233 if (submitPacket(packet) == 0) // Stream is full
239 else // Write what we have.
241 packet.write(buf, len);
242 state = packetLength - len;
251 ULONG DemuxerVDR::getPacketNum()
256 ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts)
258 ULLONG difference = (1LL<<33);
260 int total = 0, actual = 0;
261 pts_map_mutex.Lock();
262 PTSMap::iterator iter = pts_map.begin();
263 while (iter != pts_map.end())
266 if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE)
269 ref_frame = iter->frame;
273 ULLONG newdiff = PTSDifference(pts, iter->pts);
274 if (newdiff < difference)
276 difference = newdiff;
277 ref_frame = iter->frame;
282 if (total > 1 && actual == 1) // We are using the most recent PTS ref.
283 { // Delete the rest.
284 iter = pts_map.begin(); iter++;
285 pts_map.erase(iter, pts_map.end());
287 pts_map_mutex.Unlock();
288 if (total > 1 && actual == 1)
289 Log::getInstance()->log("Demuxer", Log::DEBUG, "DELETED REFERENCES");
291 Log::getInstance()->log("Demuxer", Log::DEBUG, "STILL USING OLD REF");
293 if (difference == (1LL<<33))
294 return 0; // We cannot make sense of the pts
296 return ref_frame + difference * Video::getInstance()->getFPS() / 90000;
299 void DemuxerVDR::parseVDRPacketDetails()
301 parsePacketDetails(packet);
303 if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 &&
304 packet.getPacketType() <= PESTYPE_AUDMAX)
309 if (frameCounting && packet.findPictureHeader() &&
310 packet.getPacketType() >= PESTYPE_VID0 &&
311 packet.getPacketType() <= PESTYPE_VIDMAX)
313 ULONG frame_num = (frameNumber)++;
314 if (packet.findSeqHeader() > 1 && packet.hasPTS())
317 pts_map_mutex.Lock();
320 me.pts = packet.getPTS();
321 me.frame = frame_num;
322 pts_map_mutex.Unlock();
323 Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS INIT *+ %llu %u", me.pts, me.frame);
324 pts_map_mutex.Lock();
325 pts_map.push_front(me);
327 me = pts_map.front();
328 pts_map_mutex.Unlock();
330 UINT fps = Video::getInstance()->getFPS();
331 ULLONG pts_expected = me.pts + 90000*(frame_num - me.frame) / fps;
332 while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33);
334 if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump!
336 Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS JUMP *+ %llu %u", packet.getPTS(), frame_num);
337 me.pts = packet.getPTS();
338 me.frame = frame_num;
339 pts_map_mutex.Lock();
340 pts_map.push_front(me);
341 pts_map_mutex.Unlock();