]> git.vomp.tv Git - vompclient.git/blob - demuxervdr.cc
Demuxer frame counting: first 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
38 DemuxerVDR::DemuxerVDR()
39 {
40   frameCounting = false;
41 }
42
43 void DemuxerVDR::flush()
44 {
45   state = 0;
46   submitting = false;
47   frameCounting = false;
48   Demuxer::flush();
49 }
50
51 int DemuxerVDR::scan(UCHAR *buf, int len)
52 {
53   // Temporarily, just look for the lowest audio stream and return it
54   UCHAR HiByte = PESTYPE_AUDMAX;
55   int ret = 0;
56
57   while (len >= 4)
58   {
59     UINT pattern = *(UINT*)buf;
60     buf++; len--;
61
62 #if __BYTE_ORDER == __BIG_ENDIAN
63     if (pattern < (UINT)(0x100 | PESTYPE_AUD0) ||
64         pattern > (UINT)(0x100 | HiByte)) continue;
65     HiByte = pattern & 0xFF;
66 #else
67     if ((pattern & 0xFFFFFF) != 0x010000 ||
68          pattern < ((UINT)PESTYPE_AUD0 << 24) ||
69          pattern > ((UINT)HiByte << 24)) continue;
70     HiByte = pattern >> 24;
71 #endif
72     ret = HiByte;
73     if (HiByte == PESTYPE_AUD0) break;
74   }
75   return ret;
76 }
77
78 int DemuxerVDR::findVideoPTS(UCHAR* buf, int len, ULLONG* dest)
79 {
80   while (len >= 14)
81   {
82     UINT pattern = *(UINT*)buf;
83     buf++; len--;
84 #if __BYTE_ORDER == __BIG_ENDIAN
85     if (pattern < (0x100 | PESTYPE_VID0) ||
86         pattern > (0x100 | PESTYPE_VIDMAX)) continue;
87 #else
88     if ((pattern & 0xFFFFFF) != 0x010000 ||
89          pattern < ((UINT)PESTYPE_VID0 << 24) ||
90          pattern > ((UINT)PESTYPE_VIDMAX << 24)) continue;
91 #endif
92     if ((buf[5] & 0xC0) != 0x80) continue;
93
94     UINT packetlength = ((UINT)buf[3] << 8) | buf[4];
95
96     if ( buf[6] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
97     {
98       if ( (buf[8]  & 0x01) != 0x01 ||
99            (buf[10] & 0x01) != 0x01 ||
100            (buf[12] & 0x01) != 0x01) continue;
101
102       *dest = ( (ULLONG)(buf[8]  & 0x0E) << 29 ) |
103               ( (ULLONG)(buf[9])         << 22 ) |
104               ( (ULLONG)(buf[10] & 0xFE) << 14 ) |
105               ( (ULLONG)(buf[11])        <<  7 ) |
106               ( (ULLONG)(buf[12] & 0xFE) >>  1 );
107       return 1;
108     }
109
110     buf += 5; len -= 5;
111     buf += packetlength; len -= packetlength;
112   }
113   // No PTS found.
114   return 0;
115 }
116
117 void DemuxerVDR::setFrameNum(ULONG frame)
118 {
119   frameCounting = true;
120   frameNumber = frame;
121 }
122
123 #ifndef NEW_DEMUXER
124 int DemuxerVDR::put(UCHAR* buf, int len)
125 #else
126 int DemuxerVDR::put(UCHAR* buf, int len, ULLONG cur_pos)
127 #endif
128 {
129   int ret = 0;    // return number of bytes consumed
130
131 #ifdef NEW_DEMUXER
132   ULLONG current_position = cur_pos;
133 #endif
134
135   if (submitting)
136   {
137 #ifndef NEW_DEMUXER
138     if (packet.submit() == 0) // Still full!
139 #else
140     if (packet.submit(current_position) == 0) // Still full!
141 #endif
142       return ret;
143     else
144       submitting = false;
145   }
146
147   if (state > 0) // We are half way through a PES packet.
148   {
149     if (len >= state) // The remainder of the packet is available.
150     {
151       packet.write(buf, state);
152       buf += state; len -= state; ret += state;
153       state = 0;
154 #ifndef NEW_DEMUXER
155     if (packet.submit() == 0) // Stream is full
156 #else
157     if (packet.submit(current_position) == 0) // Stream is full
158 #endif
159       {
160         submitting = true;
161         return ret;
162       }
163     }
164     else // Write what we have, then exit.
165     {
166       packet.write(buf, len);
167       state -= len;
168       return len;
169     }
170   }
171
172   while (len > 0)
173   {
174     switch (state)
175     {
176       case  0:
177       case -1:
178         if (*buf == 0x00) state--; else state = 0;
179         buf++; len--; ret++;
180         break;
181       case -2:
182         if (*buf == 0x01) state--; else if (*buf != 0x00) state = 0;
183         buf++; len--; ret++;
184         break;
185       case -3:
186         if ((*buf >= PESTYPE_VID0 && *buf <= PESTYPE_VIDMAX) ||
187             (*buf >= PESTYPE_AUD0 && *buf <= PESTYPE_AUDMAX) ||
188             (*buf == PESTYPE_PRIVATE_1))
189         {
190           packet.init(*buf);
191           state--;
192         }
193         else if (*buf == 0x00)
194           state = -1;
195         else
196           state = 0;
197         buf++; len--; ret++;
198         break;
199       case -4:
200         packetLength = ((UINT)*buf) << 8;
201         state--;
202         buf++; len--; ret++;
203         break;
204       case -5:
205         packetLength += *buf;
206         state--;
207         buf++; len--; ret++;
208         break;
209     }
210
211 #ifdef NEW_DEMUXER
212     current_position++;
213 #endif
214
215     if (state == -6) // Packet header complete
216     {
217       if (len >= packetLength) // The entire packet is available.
218       {
219         packet.write(buf, packetLength);
220         buf += packetLength; len -= packetLength; ret += packetLength;
221 #ifdef NEW_DEMUXER
222         current_position+=(ULLONG)packetLength;
223 #endif
224         state = 0;
225 #ifndef NEW_DEMUXER
226         if (packet.submit() == 0) // Stream is full
227 #else
228         if (packet.submit(current_position) == 0) // Stream is full
229 #endif
230         {
231           submitting = true;
232           return ret;
233         }
234       }
235       else // Write what we have.
236       {
237         packet.write(buf, len);
238         state = packetLength - len;
239         ret += len;
240         len = 0;
241       }
242     }
243   }
244   return ret;
245 }
246
247 void DemuxerVDR::PESPacketVDR::parseDetails()
248 {
249   DemuxerVDR* dx = (DemuxerVDR*)(DemuxerVDR::getInstance());
250   PESPacket::parseDetails();
251   if (dx->frameCounting && pts != PTS_INVALID)
252   {
253     PTSMapEntry me;
254     me.pts = pts;
255     me.frame = dx->frameNumber;
256     dx->PTSMap.push_back(me);
257     if (dx->PTSMap.size() == PTSMAP_MAXENTRIES) dx->PTSMap.pop_front();
258   }
259 }