]> git.vomp.tv Git - vompclient-marten.git/blob - demuxerts.cc
Buffering progress bar
[vompclient-marten.git] / demuxerts.cc
1 /*
2     Copyright 2006-2007 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #include "demuxerts.h"
22 #include "log.h"
23
24 DemuxerTS::DemuxerTS(int p_vID, int p_aID)
25 {
26   vID = p_vID;
27   aID = p_aID;
28   atype = 0;
29 }
30
31 void DemuxerTS::flush()
32 {
33   partPacket = 0;
34   parsed = false;
35   Demuxer::flush();
36   vPacket.init(PESTYPE_VID0);
37   switch (atype) {
38   case 1:
39   aPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_AC30);break;
40   default:
41   case 0:
42   aPacket.init(PESTYPE_AUD0);break;
43   };
44   vActive = false;
45   aActive = false;
46 }
47
48 int DemuxerTS::scan(UCHAR *buf, int len)
49 {
50   switch (atype) {
51   case 1:
52   return PESTYPE_PRIVATE_1;
53   default:
54   case 0:
55   return PESTYPE_AUD0;
56   };
57   
58 }
59
60 void DemuxerTS::setVID(int p_vID)
61 {
62   vID = p_vID;
63   vPacket.init(PESTYPE_VID0);
64   vActive = false;
65 }
66
67 void DemuxerTS::setAID(int p_aID, int type)
68 {
69   aID = p_aID;
70   atype = type;
71   switch (atype) {
72   case 1:
73   aPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_AC30);
74   setAudioStream(PESTYPE_SUBSTREAM_AC30);break;
75   default:
76   case 0:
77   aPacket.init(PESTYPE_AUD0);
78   setAudioStream(PESTYPE_AUD0);
79   break;
80   };
81   aActive = false;
82 }
83
84 int DemuxerTS::findPTS(UCHAR* buf, int len, ULLONG* dest)
85 {
86   UINT LoPattern = 0x100 | PESTYPE_VID0,
87        HiPattern = 0x100 | PESTYPE_VIDMAX;
88
89   while (len >= 14)
90   {
91     UINT pattern = *(UINT*)buf;
92     buf++; len--;
93     if (pattern < LoPattern || pattern > HiPattern) continue;
94
95     UINT framelength = ((UINT)buf[3] << 8) | buf[4];
96     buf += 5; len -= 5;
97
98     if ( buf[1] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
99     {
100       *dest = ( (ULLONG)(buf[3] & 0x0E) << 29 ) |
101               ( (ULLONG)(buf[4])        << 22 ) |
102               ( (ULLONG)(buf[5] & 0xFE) << 14 ) |
103               ( (ULLONG)(buf[6])        <<  7 ) |
104               ( (ULLONG)(buf[7] & 0xFE) >>  1 );
105       return 1;
106     }
107
108     buf += framelength; len -= framelength;
109   }
110   // No PTS found.
111   return 0;
112 }
113
114 int DemuxerTS::put(UCHAR* buf, int len)
115 {
116   int ret = 0;    // return number of bytes consumed
117
118   while (partPacket)
119   {
120     if (len >= TS_SIZE + 1 - partPacket)
121     { // Remainder of partial packet is available, plus one
122       memcpy(store+partPacket, buf, TS_SIZE - partPacket);
123       ret += TS_SIZE - partPacket;
124       buf += TS_SIZE - partPacket;
125       len -= TS_SIZE - partPacket;
126       partPacket = TS_SIZE;
127       if (*buf == TS_SIG)
128       { // Packet is properly terminated
129         int rc = processTS(store);
130         if (rc)
131           partPacket = 0; // Successfully processed
132         else
133           return ret;     // Try again later.
134       }
135       else
136       { // Packet not terminated. Find another candidate, and shift store
137         Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!");
138         int search = 1;
139         while (search < partPacket && store[search] != TS_SIG)
140           search++;
141         partPacket -= search;
142         if (partPacket) memcpy(store, store+search, partPacket);
143       }
144     }
145     else
146     { // Still don't have complete packet. Consume what we do have.
147       memcpy(store+partPacket, buf, len);
148       partPacket += len;
149       ret += len;
150       return ret;
151     }
152   }
153
154   // Position ourselves at a candidate TS packet
155   while (len > 0 && *buf != TS_SIG)
156   {
157     Log::getInstance()->log("TS Demuxer", Log::ERR, "TS Misaligned!");
158     buf++; ret++; len--;
159   }
160
161   while (len)
162   {
163     if (len < TS_SIZE + 1)
164     { // Not enough data. Store what we have.
165       memcpy(store, buf, len);
166       partPacket = len;
167       ret += len;
168       return ret;
169     }
170
171     if (buf[TS_SIZE] != TS_SIG)
172     { // Not terminated correctly.
173       buf++; ret++; len--;
174       while (len > 0 && *buf != TS_SIG)
175       {
176         buf++; ret++; len--;
177       }
178     }
179     else
180     {
181       int rc = processTS(buf);
182       if (rc)
183       { // Successfully processed
184         buf += TS_SIZE; ret += TS_SIZE; len -= TS_SIZE;
185       }
186       else
187       { // Processing failed.
188         return ret;
189       }
190     }
191   }
192   return ret;
193 }
194
195 int DemuxerTS::processTS(UCHAR* buf)
196 {
197   int datalen = TS_SIZE - 4;
198   int pid = ( (buf[1] & 0x1F) << 8 ) | buf[2];
199   UCHAR payload = buf[1] & 0x40;
200
201   if (buf[3] & 0x20) // Adaptation field is present
202     datalen -= (buf[4] + 1);
203   if (datalen < 0) // Error in stream TODO log this
204     return 1;
205   if (datalen == 0) // Null packet
206     return 1;
207   buf += (TS_SIZE - datalen);
208
209   if (payload)
210   {
211     int rc = 1;
212
213     if (pid == vID)
214     {
215       if (vActive)
216       {
217         if (!parsed)
218         {
219           parsePacketDetails(vPacket);
220           parsed = true;
221         }
222       rc = submitPacket(vPacket);
223       }
224       vActive = true;
225     }
226     if (pid == aID)
227     {
228       if (aActive)
229       {
230         if (!parsed)
231         {
232           parsePacketDetails(aPacket);
233           parsed = true;
234         }
235       rc = submitPacket(aPacket);
236       }
237       aActive = true;
238     }
239     if (rc == 0) return 0;
240
241     parsed = false;
242     if (pid == vID)
243     {
244       vPacket.init(PESTYPE_VID0);
245       buf += 6; datalen -= 6;
246     }
247     if (pid == aID)
248     {
249       switch (atype) {
250       case 1:
251           aPacket.init(PESTYPE_PRIVATE_1,PESTYPE_SUBSTREAM_AC30);break;
252       default:
253       case 0:
254       aPacket.init(PESTYPE_AUD0);break;
255       };
256       buf += 6; datalen -= 6;
257     }
258   }
259
260   if ( (pid == vID && vActive) ||
261        (pid == aID && aActive) )
262   {
263     PESPacket* packet = NULL;
264     if (pid == vID) packet = &vPacket;
265     if (pid == aID) packet = &aPacket;
266     if (packet != NULL)
267     {
268       if (packet->write(buf, datalen) == 0)
269       { // Writing to packet failed. It has overflowed.
270         if (!parsed)
271         {
272           parsePacketDetails(*packet);
273           parsed = true;
274         }
275         if (submitPacket(*packet) == 0) return 0;
276         parsed = false;
277         packet->truncate();
278         packet->write((UCHAR*)"\200\000\000", 3);
279         packet->write(buf, datalen);
280       }
281     }
282   }
283
284   return 1;
285 }