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