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 static const char* TAG = "DemuxerVDR";
38 // TODO: PTS class to handle wrapping arithmetic & comparisons?
39 static u8 PTSDistance(u8 pts1, u8 pts2)
41 // Assume pts1, pts2 < 2^33; calculate shortest distance between
42 u8 ret = (pts1 > pts2) ? pts1 - pts2 : pts2 - pts1;
43 if (ret > (1LL<<32)) ret = (1LL<<33) - ret;
47 static u8 PTSDifference(u8 pts1, u8 pts2)
49 // Assume pts1, pts2 < 2^33; calculate pts1 - pts2
53 return (1LL<<33) + pts1 - pts2;
56 DemuxerVDR::DemuxerVDR()
58 frameCounting = false;
59 packetCounting = false;
60 subtitlePacketPosition = 0;
63 void DemuxerVDR::reset()
65 frameCounting = false;
66 packetCounting = false;
71 void DemuxerVDR::flush()
75 subtitlePacketPosition = 0;
79 int DemuxerVDR::scan(u1 *buf, int len) {
80 // Temporarily, just look for the lowest audio stream and return it
81 u1 HiByte = PESTYPE_AUDMAX;
85 u4 pattern = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
89 if (pattern < (u4)(0x100 | PESTYPE_AUD0) || pattern > (u4)(
92 HiByte = pattern & 0xFF;
95 if (HiByte == PESTYPE_AUD0)
101 int DemuxerVDR::findPTS(u1* buf, int len, u8* dest) {
103 u4 pattern = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
106 if (pattern < (0x100 | PESTYPE_AUD0) || pattern > (0x100
110 if ((buf[5] & 0xC0) != 0x80)
113 u4 packetlength = ((u4) buf[3] << 8) | buf[4];
115 if (buf[6] & 0x80) // PTS_DTS_flags indicate that PTS is present
117 if ((buf[8] & 0x01) != 0x01 || (buf[10] & 0x01) != 0x01 || (buf[12]
121 *dest = ((u8)(buf[8] & 0x0E) << 29) | ((u8)(buf[9]) << 22)
122 | ((u8)(buf[10] & 0xFE) << 14) | ((u8)(buf[11])
123 << 7) | ((u8)(buf[12] & 0xFE) >> 1);
136 void DemuxerVDR::setFrameNum(u4 frame)
138 frameCounting = true;
140 LogNT::getInstance()->debug(TAG, "setFrameNum {}", frame);
143 void DemuxerVDR::setPacketNum(u4 npacket)
145 packetCounting = true;
146 packetNumber = npacket;
147 LogNT::getInstance()->debug(TAG, "setPacketNum {}", npacket);
150 int DemuxerVDR::put(u1* buf, int len)
152 int ret = 0; // return number of bytes consumed
155 if (submitPacket(packet) == 0) // Still full!
161 if (state > 0) // We are half way through a PES packet.
163 if (len >= state) // The remainder of the packet is available.
165 packet.write(buf, state);
166 buf += state; len -= state; ret += state;
168 parseVDRPacketDetails();
169 if (submitPacket(packet) == 0) // Stream is full
175 else // Write what we have, then exit.
177 packet.write(buf, len);
189 if (*buf == 0x00) state--; else state = 0;
193 if (*buf == 0x01) state--; else if (*buf != 0x00) state = 0;
197 if ((*buf >= PESTYPE_VID0 && *buf <= PESTYPE_VIDMAX) ||
198 (*buf >= PESTYPE_AUD0 && *buf <= PESTYPE_AUDMAX) ||
199 (*buf == PESTYPE_PRIVATE_1))
204 else if (*buf == 0x00)
211 packetLength = ((u4)*buf) << 8;
216 packetLength += *buf;
222 if (state == -6) // Packet header complete
224 if (len >= packetLength) // The entire packet is available.
226 packet.write(buf, packetLength);
227 buf += packetLength; len -= packetLength; ret += packetLength;
229 parseVDRPacketDetails();
230 if (submitPacket(packet) == 0) // Stream is full
236 else // Write what we have.
238 packet.write(buf, len);
239 state = packetLength - len;
248 u4 DemuxerVDR::getPacketNum()
253 u4 DemuxerVDR::getFrameNumFromPTS(u8 pts)
255 u8 difference = (1LL<<33);
257 int total = 0, actual = 0;
258 pts_map_mutex.lock();
259 PTSMap::iterator iter = pts_map.begin();
260 while (iter != pts_map.end())
263 if (PTSDifference(iter->pts, pts) < PTS_ALLOWANCE)
266 ref_frame = iter->frame;
270 u8 newdiff = PTSDifference(pts, iter->pts);
271 if (newdiff < difference)
273 difference = newdiff;
274 ref_frame = iter->frame;
279 if (total > 1 && actual == 1) // We are using the most recent PTS ref.
280 { // Delete the rest.
281 iter = pts_map.begin(); iter++;
282 pts_map.erase(iter, pts_map.end());
284 pts_map_mutex.unlock();
286 if (difference == (1LL<<33))
287 return 0; // We cannot make sense of the pts
289 return ref_frame + (u4)((double) (difference / 90000) *fps);
292 void DemuxerVDR::dealWithSubtitlePacket()
294 const u1* data = packet.getData();
295 u4 packetSize = packet.getSize();
296 if (packetSize < 9) return;
297 u4 payloadOffset = data[8] + 9;
298 if (packetSize < payloadOffset + 5) return;
299 if (data[payloadOffset + 3] == 0x00)
300 { // Not a continuation packet
301 if (packetSize < payloadOffset + 7) return;
302 subtitlePacket.init(data[3]);
303 subtitlePacket.write(&data[6], payloadOffset - 6);
304 subtitlePacket.write(&data[payloadOffset+4], packetSize-payloadOffset-4);
305 subtitlePacketPosition = payloadOffset + 2;
308 { // Continuation packet
309 if (subtitlePacketPosition == 0) return;
310 subtitlePacket.write(&data[payloadOffset+4], packetSize-payloadOffset-4);
313 const u1* sub_data = subtitlePacket.getData();
314 u4 subSize = subtitlePacket.getSize();
315 while (subtitlePacketPosition < subSize)
317 if (sub_data[subtitlePacketPosition] == 0xFF)
318 { // Packet is complete. Switch it into the "real" packet to be submitted.
319 packet = subtitlePacket;
320 parsePacketDetails(packet);
321 subtitlePacketPosition = 0; // Wait for next non-continuation packet
324 if (sub_data[subtitlePacketPosition] != 0x0F)
326 subtitlePacketPosition = 0; // Wait for next non-continuation packet
329 if (subSize < subtitlePacketPosition + 6) break;
330 u4 segmentLength = (sub_data[subtitlePacketPosition + 4] << 8)
331 + sub_data[subtitlePacketPosition + 5];
332 subtitlePacketPosition += segmentLength + 6;
336 void DemuxerVDR::parseVDRPacketDetails()
338 if (packet.getPacketType() == PESTYPE_PRIVATE_1 && packet.getSize() > 8)
340 u4 payload_begin = packet[8] + 9;
341 if (packet.getSize() > payload_begin)
343 u1 substream_type = packet[payload_begin] & 0xF0;
344 if (substream_type == 0x20) // Subtitles
346 dealWithSubtitlePacket();
348 else // Not subtitles
349 parsePacketDetails(packet);
352 else // Not a private packet*/
353 parsePacketDetails(packet);
355 if (packetCounting && packet.getPacketType() >= PESTYPE_AUD0 &&
356 packet.getPacketType() <= PESTYPE_AUDMAX)
361 if (frameCounting && packet.findPictureHeader(h264) &&
362 packet.getPacketType() >= PESTYPE_VID0 &&
363 packet.getPacketType() <= PESTYPE_VIDMAX)
365 u4 frame_num = (frameNumber)++;
366 if (packet.findSeqHeader(h264) > 1 && packet.hasPTS())
369 pts_map_mutex.lock();
372 me.pts = packet.getPTS();
373 me.frame = frame_num;
374 pts_map_mutex.unlock();
375 LogNT::getInstance()->debug(TAG, "+* PTS INIT *+ {} {}", me.pts, me.frame);
376 pts_map_mutex.lock();
377 pts_map.push_front(me);
379 me = pts_map.front();
380 pts_map_mutex.unlock();
382 // u4 fps = Video::getInstance()->getFPS();
383 u8 pts_expected = me.pts + 90000*((u4)((double)(frame_num - me.frame)) / fps);
384 while (pts_expected > (1LL<<33)) pts_expected -= (1LL<<33);
386 if (PTSDistance(pts_expected, packet.getPTS()) > PTS_JUMP_MARGIN) // PTS jump!
388 LogNT::getInstance()->debug(TAG, "+* PTS JUMP *+ {} {}", packet.getPTS(), frame_num);
389 me.pts = packet.getPTS();
390 me.frame = frame_num;
391 pts_map_mutex.lock();
392 pts_map.push_front(me);
393 pts_map_mutex.unlock();