2 Copyright 2005-2006 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
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "demuxervdr.h"
25 #define __LITTLE_ENDIAN 1234
26 #define __BIG_ENDIAN 4321
27 #define __BYTE_ORDER __LITTLE_ENDIAN
30 #if __BYTE_ORDER == __BIG_ENDIAN
31 #define DEMUXER_SEQ_HEAD 0x000001B3
33 #define DEMUXER_SEQ_HEAD 0xB3010000
36 #define PTSMAP_MAXENTRIES 300
37 #define PTSMAP_THRESHOLD 90000 // One second
38 // ISO standard demands at least one PTS every 0.7 seconds
40 DemuxerVDR::DemuxerVDR()
42 frameCounting = false;
45 void DemuxerVDR::flush()
49 frameCounting = false;
53 int DemuxerVDR::scan(UCHAR *buf, int len)
55 // Temporarily, just look for the lowest audio stream and return it
56 UCHAR HiByte = PESTYPE_AUDMAX;
61 UINT pattern = *(UINT*)buf;
64 #if __BYTE_ORDER == __BIG_ENDIAN
65 if (pattern < (UINT)(0x100 | PESTYPE_AUD0) ||
66 pattern > (UINT)(0x100 | HiByte)) continue;
67 HiByte = pattern & 0xFF;
69 if ((pattern & 0xFFFFFF) != 0x010000 ||
70 pattern < ((UINT)PESTYPE_AUD0 << 24) ||
71 pattern > ((UINT)HiByte << 24)) continue;
72 HiByte = pattern >> 24;
75 if (HiByte == PESTYPE_AUD0) break;
80 int DemuxerVDR::findVideoPTS(UCHAR* buf, int len, ULLONG* dest)
84 UINT pattern = *(UINT*)buf;
86 #if __BYTE_ORDER == __BIG_ENDIAN
87 if (pattern < (0x100 | PESTYPE_VID0) ||
88 pattern > (0x100 | PESTYPE_VIDMAX)) continue;
90 if ((pattern & 0xFFFFFF) != 0x010000 ||
91 pattern < ((UINT)PESTYPE_VID0 << 24) ||
92 pattern > ((UINT)PESTYPE_VIDMAX << 24)) continue;
94 if ((buf[5] & 0xC0) != 0x80) continue;
96 UINT packetlength = ((UINT)buf[3] << 8) | buf[4];
98 if ( buf[6] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
100 if ( (buf[8] & 0x01) != 0x01 ||
101 (buf[10] & 0x01) != 0x01 ||
102 (buf[12] & 0x01) != 0x01) continue;
104 *dest = ( (ULLONG)(buf[8] & 0x0E) << 29 ) |
105 ( (ULLONG)(buf[9]) << 22 ) |
106 ( (ULLONG)(buf[10] & 0xFE) << 14 ) |
107 ( (ULLONG)(buf[11]) << 7 ) |
108 ( (ULLONG)(buf[12] & 0xFE) >> 1 );
113 buf += packetlength; len -= packetlength;
119 void DemuxerVDR::setFrameNum(ULONG frame)
121 frameCounting = true;
123 Log::getInstance()->log("Demuxer", Log::DEBUG, "setFrameNum %d", frame);
127 int DemuxerVDR::put(UCHAR* buf, int len)
129 int DemuxerVDR::put(UCHAR* buf, int len, ULLONG cur_pos)
132 int ret = 0; // return number of bytes consumed
135 ULLONG current_position = cur_pos;
141 if (packet.submit() == 0) // Still full!
143 if (packet.submit(current_position) == 0) // Still full!
150 if (state > 0) // We are half way through a PES packet.
152 if (len >= state) // The remainder of the packet is available.
154 packet.write(buf, state);
155 buf += state; len -= state; ret += state;
158 if (packet.submit() == 0) // Stream is full
160 if (packet.submit(current_position) == 0) // Stream is full
167 else // Write what we have, then exit.
169 packet.write(buf, len);
181 if (*buf == 0x00) state--; else state = 0;
185 if (*buf == 0x01) state--; else if (*buf != 0x00) state = 0;
189 if ((*buf >= PESTYPE_VID0 && *buf <= PESTYPE_VIDMAX) ||
190 (*buf >= PESTYPE_AUD0 && *buf <= PESTYPE_AUDMAX) ||
191 (*buf == PESTYPE_PRIVATE_1))
196 else if (*buf == 0x00)
203 packetLength = ((UINT)*buf) << 8;
208 packetLength += *buf;
218 if (state == -6) // Packet header complete
220 if (len >= packetLength) // The entire packet is available.
222 packet.write(buf, packetLength);
223 buf += packetLength; len -= packetLength; ret += packetLength;
225 current_position+=(ULLONG)packetLength;
229 if (packet.submit() == 0) // Stream is full
231 if (packet.submit(current_position) == 0) // Stream is full
238 else // Write what we have.
240 packet.write(buf, len);
241 state = packetLength - len;
250 ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts)
253 pthread_mutex_lock(&pts_map_mutex);
254 PTSMap::const_iterator iter = pts_map.begin();
255 bool onTarget = false;
256 while (iter != pts_map.end())
258 bool inRange, inDoubleRange;
259 if (pts < PTSMAP_THRESHOLD)
260 inRange = (iter->pts <= pts ||
261 iter->pts >= (1LL<<33) - PTSMAP_THRESHOLD + pts);
263 inRange = (iter->pts <= pts &&
264 iter->pts >= pts - PTSMAP_THRESHOLD);
266 if (pts < PTSMAP_THRESHOLD*2)
267 inDoubleRange = (iter->pts <= pts ||
268 iter->pts >= (1LL<<33) - PTSMAP_THRESHOLD*2 + pts);
270 inDoubleRange = (iter->pts <= pts &&
271 iter->pts >= pts - PTSMAP_THRESHOLD*2);
275 if (!inDoubleRange) break; // We have hit the target
279 if (inRange){ onTarget = true; // We are hot on the trail
280 Log::getInstance()->log("Demuxer", Log::DEBUG, "ON TARGET AT %d", iter->frame); }
285 if (onTarget) ret = iter->frame;
286 pthread_mutex_unlock(&pts_map_mutex);
289 Log::getInstance()->log("Demuxer", Log::DEBUG, "FAILED TO FIND FRAME NUMBER for %llu", pts);
294 Log::getInstance()->log("Demuxer", Log::DEBUG, "FOUND FRAME NUMBER %d for %llu", ret, pts);
299 void DemuxerVDR::PESPacketVDR::parseDetails()
301 // TODO: Currently, we naïvely assume that a packet contains a new frame
302 // if and only if it contains a pts, and that no packet contains more
303 // than one new frame
305 DemuxerVDR* dx = (DemuxerVDR*)(DemuxerVDR::getInstance());
306 PESPacket::parseDetails();
307 if (dx->frameCounting && pts != PTS_INVALID &&
308 packetType >= PESTYPE_VID0 && packetType <= PESTYPE_VIDMAX)
312 me.frame = dx->frameNumber;
313 Log::getInstance()->log("Demuxer", Log::DEBUG, "Map %llu %u", me.pts, me.frame);
314 pthread_mutex_lock(&(dx->pts_map_mutex));
315 dx->pts_map.push_back(me);
316 if (dx->pts_map.size() == PTSMAP_MAXENTRIES) dx->pts_map.pop_front();
317 pthread_mutex_unlock(&(dx->pts_map_mutex));