]> git.vomp.tv Git - vompclient.git/blob - demuxervdr.cc
Keep compiler happy
[vompclient.git] / demuxervdr.cc
1 /*
2     Copyright 2005-2006 Mark Calderbank
3
4     This file is part of VOMP.
5
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.
10
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.
15
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
19 */
20
21 #include "demuxervdr.h"
22 #ifndef WIN32
23 #include <endian.h>
24 #else
25 #define __LITTLE_ENDIAN 1234
26 #define __BIG_ENDIAN  4321
27 #define __BYTE_ORDER __LITTLE_ENDIAN
28 #endif
29
30 #if __BYTE_ORDER == __BIG_ENDIAN
31 #define DEMUXER_SEQ_HEAD 0x000001B3
32 #else
33 #define DEMUXER_SEQ_HEAD 0xB3010000
34 #endif
35
36 #define PTSMAP_MAXENTRIES 300
37 #define PTSMAP_THRESHOLD 90000 // One second
38           // ISO standard demands at least one PTS every 0.7 seconds
39
40 DemuxerVDR::DemuxerVDR()
41 {
42   frameCounting = false;
43 }
44
45 void DemuxerVDR::flush()
46 {
47   state = 0;
48   submitting = false;
49   frameCounting = false;
50   Demuxer::flush();
51 }
52
53 int DemuxerVDR::scan(UCHAR *buf, int len)
54 {
55   // Temporarily, just look for the lowest audio stream and return it
56   UCHAR HiByte = PESTYPE_AUDMAX;
57   int ret = 0;
58
59   while (len >= 4)
60   {
61     UINT pattern = *(UINT*)buf;
62     buf++; len--;
63
64 #if __BYTE_ORDER == __BIG_ENDIAN
65     if (pattern < (UINT)(0x100 | PESTYPE_AUD0) ||
66         pattern > (UINT)(0x100 | HiByte)) continue;
67     HiByte = pattern & 0xFF;
68 #else
69     if ((pattern & 0xFFFFFF) != 0x010000 ||
70          pattern < ((UINT)PESTYPE_AUD0 << 24) ||
71          pattern > ((UINT)HiByte << 24)) continue;
72     HiByte = pattern >> 24;
73 #endif
74     ret = HiByte;
75     if (HiByte == PESTYPE_AUD0) break;
76   }
77   return ret;
78 }
79
80 int DemuxerVDR::findVideoPTS(UCHAR* buf, int len, ULLONG* dest)
81 {
82   while (len >= 14)
83   {
84     UINT pattern = *(UINT*)buf;
85     buf++; len--;
86 #if __BYTE_ORDER == __BIG_ENDIAN
87     if (pattern < (0x100 | PESTYPE_VID0) ||
88         pattern > (0x100 | PESTYPE_VIDMAX)) continue;
89 #else
90     if ((pattern & 0xFFFFFF) != 0x010000 ||
91          pattern < ((UINT)PESTYPE_VID0 << 24) ||
92          pattern > ((UINT)PESTYPE_VIDMAX << 24)) continue;
93 #endif
94     if ((buf[5] & 0xC0) != 0x80) continue;
95
96     UINT packetlength = ((UINT)buf[3] << 8) | buf[4];
97
98     if ( buf[6] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
99     {
100       if ( (buf[8]  & 0x01) != 0x01 ||
101            (buf[10] & 0x01) != 0x01 ||
102            (buf[12] & 0x01) != 0x01) continue;
103
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 );
109       return 1;
110     }
111
112     buf += 5; len -= 5;
113     buf += packetlength; len -= packetlength;
114   }
115   // No PTS found.
116   return 0;
117 }
118
119 void DemuxerVDR::setFrameNum(ULONG frame)
120 {
121   frameCounting = true;
122   frameNumber = frame;
123   Log::getInstance()->log("Demuxer", Log::DEBUG, "setFrameNum %d", frame);
124 }
125
126 #ifndef NEW_DEMUXER
127 int DemuxerVDR::put(UCHAR* buf, int len)
128 #else
129 int DemuxerVDR::put(UCHAR* buf, int len, ULLONG cur_pos)
130 #endif
131 {
132   int ret = 0;    // return number of bytes consumed
133
134 #ifdef NEW_DEMUXER
135   ULLONG current_position = cur_pos;
136 #endif
137
138   if (submitting)
139   {
140 #ifndef NEW_DEMUXER
141     if (packet.submit() == 0) // Still full!
142 #else
143     if (packet.submit(current_position) == 0) // Still full!
144 #endif
145       return ret;
146     else
147       submitting = false;
148   }
149
150   if (state > 0) // We are half way through a PES packet.
151   {
152     if (len >= state) // The remainder of the packet is available.
153     {
154       packet.write(buf, state);
155       buf += state; len -= state; ret += state;
156       state = 0;
157 #ifndef NEW_DEMUXER
158     if (packet.submit() == 0) // Stream is full
159 #else
160     if (packet.submit(current_position) == 0) // Stream is full
161 #endif
162       {
163         submitting = true;
164         return ret;
165       }
166     }
167     else // Write what we have, then exit.
168     {
169       packet.write(buf, len);
170       state -= len;
171       return len;
172     }
173   }
174
175   while (len > 0)
176   {
177     switch (state)
178     {
179       case  0:
180       case -1:
181         if (*buf == 0x00) state--; else state = 0;
182         buf++; len--; ret++;
183         break;
184       case -2:
185         if (*buf == 0x01) state--; else if (*buf != 0x00) state = 0;
186         buf++; len--; ret++;
187         break;
188       case -3:
189         if ((*buf >= PESTYPE_VID0 && *buf <= PESTYPE_VIDMAX) ||
190             (*buf >= PESTYPE_AUD0 && *buf <= PESTYPE_AUDMAX) ||
191             (*buf == PESTYPE_PRIVATE_1))
192         {
193           packet.init(*buf);
194           state--;
195         }
196         else if (*buf == 0x00)
197           state = -1;
198         else
199           state = 0;
200         buf++; len--; ret++;
201         break;
202       case -4:
203         packetLength = ((UINT)*buf) << 8;
204         state--;
205         buf++; len--; ret++;
206         break;
207       case -5:
208         packetLength += *buf;
209         state--;
210         buf++; len--; ret++;
211         break;
212     }
213
214 #ifdef NEW_DEMUXER
215     current_position++;
216 #endif
217
218     if (state == -6) // Packet header complete
219     {
220       if (len >= packetLength) // The entire packet is available.
221       {
222         packet.write(buf, packetLength);
223         buf += packetLength; len -= packetLength; ret += packetLength;
224 #ifdef NEW_DEMUXER
225         current_position+=(ULLONG)packetLength;
226 #endif
227         state = 0;
228 #ifndef NEW_DEMUXER
229         if (packet.submit() == 0) // Stream is full
230 #else
231         if (packet.submit(current_position) == 0) // Stream is full
232 #endif
233         {
234           submitting = true;
235           return ret;
236         }
237       }
238       else // Write what we have.
239       {
240         packet.write(buf, len);
241         state = packetLength - len;
242         ret += len;
243         len = 0;
244       }
245     }
246   }
247   return ret;
248 }
249
250 ULONG DemuxerVDR::getFrameNumFromPTS(ULLONG pts)
251 {
252   ULONG ret;
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())
257   {
258     bool inRange, inDoubleRange;
259     if (pts < PTSMAP_THRESHOLD)
260       inRange = (iter->pts <= pts ||
261                  iter->pts >= (1LL<<33) - PTSMAP_THRESHOLD + pts);
262     else
263       inRange = (iter->pts <= pts &&
264                  iter->pts >= pts - PTSMAP_THRESHOLD);
265
266     if (pts < PTSMAP_THRESHOLD*2)
267       inDoubleRange = (iter->pts <= pts ||
268                  iter->pts >= (1LL<<33) - PTSMAP_THRESHOLD*2 + pts);
269     else
270       inDoubleRange = (iter->pts <= pts &&
271                  iter->pts >= pts - PTSMAP_THRESHOLD*2);
272
273     if (onTarget)
274     {
275       if (!inDoubleRange) break; // We have hit the target
276     }
277     else
278     {
279       if (inRange){ onTarget = true; // We are hot on the trail
280          Log::getInstance()->log("Demuxer", Log::DEBUG, "ON TARGET AT %d", iter->frame); }
281     }
282     ++iter;
283   }
284   --iter;
285   pthread_mutex_unlock(&pts_map_mutex);
286   if (!onTarget)
287   {
288     Log::getInstance()->log("Demuxer", Log::DEBUG, "FAILED TO FIND FRAME NUMBER for %llu", pts);
289     return 0;
290   }
291   else
292   {
293     ret = iter->frame;
294     Log::getInstance()->log("Demuxer", Log::DEBUG, "FOUND FRAME NUMBER %d for %llu", ret, pts);
295     return ret;
296   }
297 }
298
299 void DemuxerVDR::PESPacketVDR::parseDetails()
300 {
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
304
305   DemuxerVDR* dx = (DemuxerVDR*)(DemuxerVDR::getInstance());
306   PESPacket::parseDetails();
307   if (dx->frameCounting && pts != PTS_INVALID &&
308       packetType >= PESTYPE_VID0 && packetType <= PESTYPE_VIDMAX)
309   {
310     PTSMapEntry me;
311     me.pts = pts;
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));
318     ++(dx->frameNumber);
319   }
320 }