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, see <https://www.gnu.org/licenses/>.
20 #include "demuxervdr.h"
22 #include "dvbsubtitles.h"
28 #define __LITTLE_ENDIAN 1234
29 #define __BIG_ENDIAN 4321
30 #define __BYTE_ORDER __LITTLE_ENDIAN
33 #define PTS_JUMP_MARGIN 10000
34 #define PTS_ALLOWANCE 90000
36 // TODO: PTS class to handle wrapping arithmetic & comparisons?
37 static ULLONG PTSDistance(ULLONG pts1, ULLONG pts2)
39 // Assume pts1, pts2 < 2^33; calculate shortest distance between
40 ULLONG ret = (pts1 > pts2) ? pts1 - pts2 : pts2 - pts1;
41 if (ret > (1LL<<32)) ret = (1LL<<33) - ret;
45 static ULLONG PTSDifference(ULLONG pts1, ULLONG pts2)
47 // Assume pts1, pts2 < 2^33; calculate pts1 - pts2
51 return (1LL<<33) + pts1 - pts2;
54 DemuxerVDR::DemuxerVDR()
56 frameCounting = false;
57 packetCounting = false;
58 subtitlePacketPosition = 0;
61 void DemuxerVDR::reset()
63 frameCounting = false;
64 packetCounting = false;
69 void DemuxerVDR::flush()
73 subtitlePacketPosition = 0;
77 int DemuxerVDR::scan(UCHAR *buf, int len) {
78 // Temporarily, just look for the lowest audio stream and return it
79 UCHAR HiByte = PESTYPE_AUDMAX;
83 UINT pattern = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
87 if (pattern < (UINT)(0x100 | PESTYPE_AUD0) || pattern > (UINT)(
90 HiByte = pattern & 0xFF;
93 if (HiByte == PESTYPE_AUD0)
99 int DemuxerVDR::findPTS(UCHAR* buf, int len, ULLONG* dest) {
101 UINT pattern = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
104 if (pattern < (0x100 | PESTYPE_AUD0) || pattern > (0x100
108 if ((buf[5] & 0xC0) != 0x80)
111 UINT packetlength = ((UINT) buf[3] << 8) | buf[4];
113 if (buf[6] & 0x80) // PTS_DTS_flags indicate that PTS is present
115 if ((buf[8] & 0x01) != 0x01 || (buf[10] & 0x01) != 0x01 || (buf[12]
119 *dest = ((ULLONG)(buf[8] & 0x0E) << 29) | ((ULLONG)(buf[9]) << 22)
120 | ((ULLONG)(buf[10] & 0xFE) << 14) | ((ULLONG)(buf[11])
121 << 7) | ((ULLONG)(buf[12] & 0xFE) >> 1);
134 void DemuxerVDR::setFrameNum(ULONG frame)
136 frameCounting = true;
138 Log::getInstance()->log("Demuxer", Log::DEBUG, "setFrameNum %d", frame);
141 void DemuxerVDR::setPacketNum(ULONG npacket)
143 packetCounting = true;
144 packetNumber = npacket;
145 Log::getInstance()->log("Demuxer", Log::DEBUG, "setPacketNum %d", npacket);
148 int DemuxerVDR::put(UCHAR* buf, int len)
150 int ret = 0; // return number of bytes consumed
153 if (submitPacket(packet) == 0) // Still full!
159 if (state > 0) // We are half way through a PES packet.
161 if (len >= state) // The remainder of the packet is available.
163 packet.write(buf, state);
164 buf += state; len -= state; ret += state;
166 parseVDRPacketDetails();
167 if (submitPacket(packet) == 0) // Stream is full
173 else // Write what we have, then exit.
175 packet.write(buf, len);
187 if (*buf == 0x00) state--; else state = 0;
191 if (*buf == 0x01) state--; else if (*buf != 0x00) state = 0;
195 if ((*buf >= PESTYPE_VID0 && *buf <= PESTYPE_VIDMAX) ||
196 (*buf >= PESTYPE_AUD0 && *buf <= PESTYPE_AUDMAX) ||
197 (*buf == PESTYPE_PRIVATE_1))
202 else if (*buf == 0x00)
209 packetLength = ((UINT)*buf) << 8;
214 packetLength += *buf;
220 if (state == -6) // Packet header complete
222 if (len >= packetLength) // The entire packet is available.
224 packet.write(buf, packetLength);
225 buf += packetLength; len -= packetLength; ret += packetLength;
227 parseVDRPacketDetails();
228 if (submitPacket(packet) == 0) // Stream is full
234 else // Write what we have.
236 packet.write(buf, len);
237 state = packetLength - len;
246 ULONG DemuxerVDR::getPacketNum()
251 ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts)
253 ULLONG difference = (1LL<<33);
255 int total = 0, actual = 0;
256 pts_map_mutex.lock();
257 PTSMap::iterator iter = pts_map.begin();
258 while (iter != pts_map.end())
261 if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE)
264 ref_frame = iter->frame;
268 ULLONG newdiff = PTSDifference(pts, iter->pts);
269 if (newdiff < difference)
271 difference = newdiff;
272 ref_frame = iter->frame;
277 if (total > 1 && actual == 1) // We are using the most recent PTS ref.
278 { // Delete the rest.
279 iter = pts_map.begin(); iter++;
280 pts_map.erase(iter, pts_map.end());
282 pts_map_mutex.unlock();
284 if (difference == (1LL<<33))
285 return 0; // We cannot make sense of the pts
287 return ref_frame + (ULONG)((double) (difference / 90000) *fps);
290 void DemuxerVDR::dealWithSubtitlePacket()
292 const UCHAR* data = packet.getData();
293 UINT packetSize = packet.getSize();
294 if (packetSize < 9) return;
295 UINT payloadOffset = data[8] + 9;
296 if (packetSize < payloadOffset + 5) return;
297 if (data[payloadOffset + 3] == 0x00)
298 { // Not a continuation packet
299 if (packetSize < payloadOffset + 7) return;
300 subtitlePacket.init(data[3]);
301 subtitlePacket.write(&data[6], payloadOffset - 6);
302 subtitlePacket.write(&data[payloadOffset+4], packetSize-payloadOffset-4);
303 subtitlePacketPosition = payloadOffset + 2;
306 { // Continuation packet
307 if (subtitlePacketPosition == 0) return;
308 subtitlePacket.write(&data[payloadOffset+4], packetSize-payloadOffset-4);
311 const UCHAR* sub_data = subtitlePacket.getData();
312 UINT subSize = subtitlePacket.getSize();
313 while (subtitlePacketPosition < subSize)
315 if (sub_data[subtitlePacketPosition] == 0xFF)
316 { // Packet is complete. Switch it into the "real" packet to be submitted.
317 packet = subtitlePacket;
318 parsePacketDetails(packet);
319 subtitlePacketPosition = 0; // Wait for next non-continuation packet
322 if (sub_data[subtitlePacketPosition] != 0x0F)
324 subtitlePacketPosition = 0; // Wait for next non-continuation packet
327 if (subSize < subtitlePacketPosition + 6) break;
328 UINT segmentLength = (sub_data[subtitlePacketPosition + 4] << 8)
329 + sub_data[subtitlePacketPosition + 5];
330 subtitlePacketPosition += segmentLength + 6;
334 void DemuxerVDR::parseVDRPacketDetails()
336 if (packet.getPacketType() == PESTYPE_PRIVATE_1 && packet.getSize() > 8)
338 UINT payload_begin = packet[8] + 9;
339 if (packet.getSize() > payload_begin)
341 UCHAR substream_type = packet[payload_begin] & 0xF0;
342 if (substream_type == 0x20) // Subtitles
344 dealWithSubtitlePacket();
346 else // Not subtitles
347 parsePacketDetails(packet);
350 else // Not a private packet*/
351 parsePacketDetails(packet);
353 if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 &&
354 packet.getPacketType() <= PESTYPE_AUDMAX)
359 if (frameCounting && packet.findPictureHeader(h264) &&
360 packet.getPacketType() >= PESTYPE_VID0 &&
361 packet.getPacketType() <= PESTYPE_VIDMAX)
363 ULONG frame_num = (frameNumber)++;
364 if (packet.findSeqHeader(h264) > 1 && packet.hasPTS())
367 pts_map_mutex.lock();
370 me.pts = packet.getPTS();
371 me.frame = frame_num;
372 pts_map_mutex.unlock();
373 Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS INIT *+ %llu %u", me.pts, me.frame);
374 pts_map_mutex.lock();
375 pts_map.push_front(me);
377 me = pts_map.front();
378 pts_map_mutex.unlock();
380 // UINT fps = Video::getInstance()->getFPS();
381 ULLONG pts_expected = me.pts + 90000*((ULONG)((double)(frame_num - me.frame)) / fps);
382 while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33);
384 if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump!
386 Log::getInstance()->log("Demuxer", Log::DEBUG, "+* PTS JUMP *+ %llu %u", packet.getPTS(), frame_num);
387 me.pts = packet.getPTS();
388 me.frame = frame_num;
389 pts_map_mutex.lock();
390 pts_map.push_front(me);
391 pts_map_mutex.unlock();