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