2 Copyright 2005-2008 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 Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "demuxervdr.h"
23 #include "dvbsubtitles.h"
29 #define __LITTLE_ENDIAN 1234
30 #define __BIG_ENDIAN 4321
31 #define __BYTE_ORDER __LITTLE_ENDIAN
34 #define PTS_JUMP_MARGIN 10000
35 #define PTS_ALLOWANCE 90000
37 // TODO: PTS class to handle wrapping arithmetic & comparisons?
38 static ULLONG PTSDistance(ULLONG pts1, ULLONG pts2)
40 // Assume pts1, pts2 < 2^33; calculate shortest distance between
41 ULLONG ret = (pts1 > pts2) ? pts1 - pts2 : pts2 - pts1;
42 if (ret > (1LL<<32)) ret = (1LL<<33) - ret;
46 static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)
48 // Assume pts1, pts2 < 2^33; calculate pts1 - pts2
52 return (1LL<<33) + pts1 - pts2;
55 DemuxerVDR::DemuxerVDR()
57 frameCounting = false;
58 packetCounting = false;
59 subtitlePacketPosition = 0;
62 void DemuxerVDR::reset()
64 frameCounting = false;
65 packetCounting = false;
70 void DemuxerVDR::flush()
74 subtitlePacketPosition = 0;
78 int DemuxerVDR::scan(UCHAR *buf, int len) {
79 // Temporarily, just look for the lowest audio stream and return it
80 UCHAR HiByte = PESTYPE_AUDMAX;
84 UINT pattern = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
88 if (pattern < (UINT)(0x100 | PESTYPE_AUD0) || pattern > (UINT)(
91 HiByte = pattern & 0xFF;
94 if (HiByte == PESTYPE_AUD0)
100 int DemuxerVDR::findPTS(UCHAR* buf, int len, ULLONG* dest) {
102 UINT pattern = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
105 if (pattern < (0x100 | PESTYPE_AUD0) || pattern > (0x100
109 if ((buf[5] & 0xC0) != 0x80)
112 UINT packetlength = ((UINT) buf[3] << 8) | buf[4];
114 if (buf[6] & 0x80) // PTS_DTS_flags indicate that PTS is present
116 if ((buf[8] & 0x01) != 0x01 || (buf[10] & 0x01) != 0x01 || (buf[12]
120 *dest = ((ULLONG)(buf[8] & 0x0E) << 29) | ((ULLONG)(buf[9]) << 22)
121 | ((ULLONG)(buf[10] & 0xFE) << 14) | ((ULLONG)(buf[11])
122 << 7) | ((ULLONG)(buf[12] & 0xFE) >> 1);
135 void DemuxerVDR::setFrameNum(ULONG frame)
137 frameCounting = true;
139 Log::getInstance()->log("Demuxer", Log::DEBUG, "setFrameNum %d", frame);
142 void DemuxerVDR::setPacketNum(ULONG npacket)
144 packetCounting = true;
145 packetNumber = npacket;
146 Log::getInstance()->log("Demuxer", Log::DEBUG, "setPacketNum %d", npacket);
149 int DemuxerVDR::put(UCHAR* buf, int len)
151 int ret = 0; // return number of bytes consumed
154 if (submitPacket(packet) == 0) // Still full!
160 if (state > 0) // We are half way through a PES packet.
162 if (len >= state) // The remainder of the packet is available.
164 packet.write(buf, state);
165 buf += state; len -= state; ret += state;
167 parseVDRPacketDetails();
168 if (submitPacket(packet) == 0) // Stream is full
174 else // Write what we have, then exit.
176 packet.write(buf, len);
188 if (*buf == 0x00) state--; else state = 0;
192 if (*buf == 0x01) state--; else if (*buf != 0x00) state = 0;
196 if ((*buf >= PESTYPE_VID0 && *buf <= PESTYPE_VIDMAX) ||
197 (*buf >= PESTYPE_AUD0 && *buf <= PESTYPE_AUDMAX) ||
198 (*buf == PESTYPE_PRIVATE_1))
203 else if (*buf == 0x00)
210 packetLength = ((UINT)*buf) << 8;
215 packetLength += *buf;
221 if (state == -6) // Packet header complete
223 if (len >= packetLength) // The entire packet is available.
225 packet.write(buf, packetLength);
226 buf += packetLength; len -= packetLength; ret += packetLength;
228 parseVDRPacketDetails();
229 if (submitPacket(packet) == 0) // Stream is full
235 else // Write what we have.
237 packet.write(buf, len);
238 state = packetLength - len;
247 ULONG DemuxerVDR::getPacketNum()
252 ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts)
254 ULLONG difference = (1LL<<33);
256 int total = 0, actual = 0;
257 pts_map_mutex.Lock();
258 PTSMap::iterator iter = pts_map.begin();
259 while (iter != pts_map.end())
262 if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE)
265 ref_frame = iter->frame;
269 ULLONG newdiff = PTSDifference(pts, iter->pts);
270 if (newdiff < difference)
272 difference = newdiff;
273 ref_frame = iter->frame;
278 if (total > 1 && actual == 1) // We are using the most recent PTS ref.
279 { // Delete the rest.
280 iter = pts_map.begin(); iter++;
281 pts_map.erase(iter, pts_map.end());
283 pts_map_mutex.Unlock();
285 if (difference == (1LL<<33))
286 return 0; // We cannot make sense of the pts
288 return ref_frame + (ULONG)((double) (difference / 90000) *fps);
291 void DemuxerVDR::dealWithSubtitlePacket()
293 const UCHAR* data = packet.getData();
294 UINT packetSize = packet.getSize();
295 if (packetSize < 9) return;
296 UINT payloadOffset = data[8] + 9;
297 if (packetSize < payloadOffset + 5) return;
298 if (data[payloadOffset + 3] == 0x00)
299 { // Not a continuation packet
300 if (packetSize < payloadOffset + 7) return;
301 subtitlePacket.init(data[3]);
302 subtitlePacket.write(&data[6], payloadOffset - 6);
303 subtitlePacket.write(&data[payloadOffset+4], packetSize-payloadOffset-4);
304 subtitlePacketPosition = payloadOffset + 2;
307 { // Continuation packet
308 if (subtitlePacketPosition == 0) return;
309 subtitlePacket.write(&data[payloadOffset+4], packetSize-payloadOffset-4);
312 const UCHAR* sub_data = subtitlePacket.getData();
313 UINT subSize = subtitlePacket.getSize();
314 while (subtitlePacketPosition < subSize)
316 if (sub_data[subtitlePacketPosition] == 0xFF)
317 { // Packet is complete. Switch it into the "real" packet to be submitted.
318 packet = subtitlePacket;
319 parsePacketDetails(packet);
320 subtitlePacketPosition = 0; // Wait for next non-continuation packet
323 if (sub_data[subtitlePacketPosition] != 0x0F)
325 subtitlePacketPosition = 0; // Wait for next non-continuation packet
328 if (subSize < subtitlePacketPosition + 6) break;
329 UINT segmentLength = (sub_data[subtitlePacketPosition + 4] << 8)
330 + sub_data[subtitlePacketPosition + 5];
331 subtitlePacketPosition += segmentLength + 6;
335 void DemuxerVDR::parseVDRPacketDetails()
337 if (packet.getPacketType() == PESTYPE_PRIVATE_1 && packet.getSize() > 8)
339 UINT payload_begin = packet[8] + 9;
340 if (packet.getSize() > payload_begin)
342 UCHAR substream_type = packet[payload_begin] & 0xF0;
343 if (substream_type == 0x20) // Subtitles
345 dealWithSubtitlePacket();
347 else // Not subtitles
348 parsePacketDetails(packet);
351 else // Not a private packet*/
352 parsePacketDetails(packet);
354 if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 &&
355 packet.getPacketType() <= PESTYPE_AUDMAX)
360 if (frameCounting && packet.findPictureHeader(h264) &&
361 packet.getPacketType() >= PESTYPE_VID0 &&
362 packet.getPacketType() <= PESTYPE_VIDMAX)
364 ULONG frame_num = (frameNumber)++;
365 if (packet.findSeqHeader(h264) > 1 && packet.hasPTS())
368 pts_map_mutex.Lock();
371 me.pts = packet.getPTS();
372 me.frame = frame_num;
373 pts_map_mutex.Unlock();
374 Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS INIT *+ %llu %u", me.pts, me.frame);
375 pts_map_mutex.Lock();
376 pts_map.push_front(me);
378 me = pts_map.front();
379 pts_map_mutex.Unlock();
381 // UINT fps = Video::getInstance()->getFPS();
382 ULLONG pts_expected = me.pts + 90000*((ULONG)((double)(frame_num - me.frame)) / fps);
383 while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33);
385 if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump!
387 Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS JUMP *+ %llu %u", packet.getPTS(), frame_num);
388 me.pts = packet.getPTS();
389 me.frame = frame_num;
390 pts_map_mutex.Lock();
391 pts_map.push_front(me);
392 pts_map_mutex.Unlock();