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