]> git.vomp.tv Git - vompclient.git/blob - demuxervdr.cc
Demuxer frame counting, second step
[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;
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     if (onTarget)
266     {
267       if (!inRange) break; // We have hit the target
268     }
269     else
270     {
271       if (inRange) onTarget = true; // We are hot on the trail
272     }
273     ++iter;
274   }
275   --iter;
276   if (onTarget) ret = iter->frame;
277   pthread_mutex_unlock(&pts_map_mutex);
278   if (!onTarget)
279     return 0;
280   else
281     return ret;
282 }
283  
284 void DemuxerVDR::PESPacketVDR::parseDetails()
285 {
286   // TODO: Currently, we naïvely assume that a packet contains a new frame
287   // if and only if it contains a pts, and that no packet contains more
288   // than one new frame
289   
290   DemuxerVDR* dx = (DemuxerVDR*)(DemuxerVDR::getInstance());
291   PESPacket::parseDetails();
292   if (dx->frameCounting && pts != PTS_INVALID &&
293       packetType >= PESTYPE_VID0 && packetType <= PESTYPE_VIDMAX)
294   {
295     PTSMapEntry me;
296     me.pts = pts;
297     me.frame = dx->frameNumber;
298     Log::getInstance()->log("Demuxer", Log::DEBUG, "Map %llu %u", me.pts, me.frame);
299     pthread_mutex_lock(&(dx->pts_map_mutex));
300     dx->pts_map.push_back(me);
301     if (dx->pts_map.size() == PTSMAP_MAXENTRIES) dx->pts_map.pop_front();
302     pthread_mutex_unlock(&(dx->pts_map_mutex));
303     ++(dx->frameNumber);
304   }
305 }