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)
80 // Temporarily, just look for the lowest audio stream and return it
81 UCHAR HiByte = PESTYPE_AUDMAX;
86 UINT pattern = *(UINT*)buf;
89 #if __BYTE_ORDER == __BIG_ENDIAN
90 if (pattern < (UINT)(0x100 | PESTYPE_AUD0) ||
91 pattern > (UINT)(0x100 | HiByte)) continue;
92 HiByte = pattern & 0xFF;
94 if ((pattern & 0xFFFFFF) != 0x010000 ||
95 pattern < ((UINT)PESTYPE_AUD0 << 24) ||
96 pattern > ((UINT)HiByte << 24)) continue;
97 HiByte = pattern >> 24;
100 if (HiByte == PESTYPE_AUD0) break;
105 int DemuxerVDR::findPTS(UCHAR* buf, int len, ULLONG* dest)
109 UINT pattern = *(UINT*)buf;
111 #if __BYTE_ORDER == __BIG_ENDIAN
112 if (pattern < (0x100 | PESTYPE_AUD0) ||
113 pattern > (0x100 | PESTYPE_VIDMAX)) continue;
115 if ((pattern & 0xFFFFFF) != 0x010000 ||
116 pattern < ((UINT)PESTYPE_AUD0 << 24) ||
117 pattern > ((UINT)PESTYPE_VIDMAX << 24)) continue;
119 if ((buf[5] & 0xC0) != 0x80) continue;
121 UINT packetlength = ((UINT)buf[3] << 8) | buf[4];
123 if ( buf[6] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
125 if ( (buf[8] & 0x01) != 0x01 ||
126 (buf[10] & 0x01) != 0x01 ||
127 (buf[12] & 0x01) != 0x01) continue;
129 *dest = ( (ULLONG)(buf[8] & 0x0E) << 29 ) |
130 ( (ULLONG)(buf[9]) << 22 ) |
131 ( (ULLONG)(buf[10] & 0xFE) << 14 ) |
132 ( (ULLONG)(buf[11]) << 7 ) |
133 ( (ULLONG)(buf[12] & 0xFE) >> 1 );
138 buf += packetlength; len -= packetlength;
144 void DemuxerVDR::setFrameNum(ULONG frame)
146 frameCounting = true;
148 Log::getInstance()->log("Demuxer", Log::DEBUG, "setFrameNum %d", frame);
151 void DemuxerVDR::setPacketNum(ULONG npacket)
153 packetCounting = true;
154 packetNumber = npacket;
155 Log::getInstance()->log("Demuxer", Log::DEBUG, "setPacketNum %d", npacket);
158 int DemuxerVDR::put(UCHAR* buf, int len)
160 int ret = 0; // return number of bytes consumed
163 if (submitPacket(packet) == 0) // Still full!
169 if (state > 0) // We are half way through a PES packet.
171 if (len >= state) // The remainder of the packet is available.
173 packet.write(buf, state);
174 buf += state; len -= state; ret += state;
176 parseVDRPacketDetails();
177 if (submitPacket(packet) == 0) // Stream is full
183 else // Write what we have, then exit.
185 packet.write(buf, len);
197 if (*buf == 0x00) state--; else state = 0;
201 if (*buf == 0x01) state--; else if (*buf != 0x00) state = 0;
205 if ((*buf >= PESTYPE_VID0 && *buf <= PESTYPE_VIDMAX) ||
206 (*buf >= PESTYPE_AUD0 && *buf <= PESTYPE_AUDMAX) ||
207 (*buf == PESTYPE_PRIVATE_1))
212 else if (*buf == 0x00)
219 packetLength = ((UINT)*buf) << 8;
224 packetLength += *buf;
230 if (state == -6) // Packet header complete
232 if (len >= packetLength) // The entire packet is available.
234 packet.write(buf, packetLength);
235 buf += packetLength; len -= packetLength; ret += packetLength;
237 parseVDRPacketDetails();
238 if (submitPacket(packet) == 0) // Stream is full
244 else // Write what we have.
246 packet.write(buf, len);
247 state = packetLength - len;
256 ULONG DemuxerVDR::getPacketNum()
261 ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts)
263 ULLONG difference = (1LL<<33);
265 int total = 0, actual = 0;
266 pts_map_mutex.Lock();
267 PTSMap::iterator iter = pts_map.begin();
268 while (iter != pts_map.end())
271 if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE)
274 ref_frame = iter->frame;
278 ULLONG newdiff = PTSDifference(pts, iter->pts);
279 if (newdiff < difference)
281 difference = newdiff;
282 ref_frame = iter->frame;
287 if (total > 1 && actual == 1) // We are using the most recent PTS ref.
288 { // Delete the rest.
289 iter = pts_map.begin(); iter++;
290 pts_map.erase(iter, pts_map.end());
292 pts_map_mutex.Unlock();
294 if (difference == (1LL<<33))
295 return 0; // We cannot make sense of the pts
297 return ref_frame + difference * Video::getInstance()->getFPS() / 90000;
300 void DemuxerVDR::dealWithSubtitlePacket()
302 const UCHAR* data = packet.getData();
303 UINT packetSize = packet.getSize();
304 if (packetSize < 9) return;
305 UINT payloadOffset = data[8] + 9;
306 if (packetSize < payloadOffset + 5) return;
307 if (data[payloadOffset + 3] == 0x00)
308 { // Not a continuation packet
309 if (packetSize < payloadOffset + 7) return;
310 subtitlePacket.init(data[3]);
311 subtitlePacket.write(&data[6], payloadOffset - 6);
312 subtitlePacket.write(&data[payloadOffset+4], packetSize-payloadOffset-4);
313 subtitlePacketPosition = payloadOffset + 2;
316 { // Continuation packet
317 if (subtitlePacketPosition == 0) return;
318 subtitlePacket.write(&data[payloadOffset+4], packetSize-payloadOffset-4);
321 const UCHAR* sub_data = subtitlePacket.getData();
322 UINT subSize = subtitlePacket.getSize();
323 while (subtitlePacketPosition < subSize)
325 if (sub_data[subtitlePacketPosition] == 0xFF)
326 { // Packet is complete. Switch it into the "real" packet to be submitted.
327 packet = subtitlePacket;
328 parsePacketDetails(packet);
329 subtitlePacketPosition = 0; // Wait for next non-continuation packet
332 if (sub_data[subtitlePacketPosition] != 0x0F)
334 subtitlePacketPosition = 0; // Wait for next non-continuation packet
337 if (subSize < subtitlePacketPosition + 6) break;
338 UINT segmentLength = (sub_data[subtitlePacketPosition + 4] << 8)
339 + sub_data[subtitlePacketPosition + 5];
340 subtitlePacketPosition += segmentLength + 6;
344 void DemuxerVDR::parseVDRPacketDetails()
346 if (packet.getPacketType() == PESTYPE_PRIVATE_1 && packet.getSize() > 8)
348 UINT payload_begin = packet[8] + 9;
349 if (packet.getSize() > payload_begin)
351 UCHAR substream_type = packet[payload_begin] & 0xF0;
352 if (substream_type == 0x20) // Subtitles
354 dealWithSubtitlePacket();
356 else // Not subtitles
357 parsePacketDetails(packet);
360 else // Not a private packet*/
361 parsePacketDetails(packet);
363 if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 &&
364 packet.getPacketType() <= PESTYPE_AUDMAX)
369 if (frameCounting && packet.findPictureHeader() &&
370 packet.getPacketType() >= PESTYPE_VID0 &&
371 packet.getPacketType() <= PESTYPE_VIDMAX)
373 ULONG frame_num = (frameNumber)++;
374 if (packet.findSeqHeader() > 1 && packet.hasPTS())
377 pts_map_mutex.Lock();
380 me.pts = packet.getPTS();
381 me.frame = frame_num;
382 pts_map_mutex.Unlock();
383 Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS INIT *+ %llu %u", me.pts, me.frame);
384 pts_map_mutex.Lock();
385 pts_map.push_front(me);
387 me = pts_map.front();
388 pts_map_mutex.Unlock();
390 UINT fps = Video::getInstance()->getFPS();
391 ULLONG pts_expected = me.pts + 90000*(frame_num - me.frame) / fps;
392 while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33);
394 if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump!
396 Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS JUMP *+ %llu %u", packet.getPTS(), frame_num);
397 me.pts = packet.getPTS();
398 me.frame = frame_num;
399 pts_map_mutex.Lock();
400 pts_map.push_front(me);
401 pts_map_mutex.Unlock();