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