]> git.vomp.tv Git - vompclient.git/blob - stream.cc
MVP/Windows convergence
[vompclient.git] / stream.cc
1 /*
2     Copyright 2005 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 "stream.h"
22
23 Stream::Stream()
24 {
25   initted = 0;
26   draintarget=NULL;
27 #ifdef NEW_DEMUXER
28   cur_packet_pos=0;
29 #endif
30 }
31
32 Stream::~Stream()
33 {
34   shutdown();
35 }
36
37 void Stream::shutdown()
38 {
39   if (initted) {
40           free(outbuf);
41 #ifdef NEW_DEMUXER
42 #ifdef WIN32
43   CloseHandle(mutex);
44 #endif
45 #endif
46   }
47   initted = 0;
48
49 }
50
51 int Stream::init(DrainTarget* tdt, int bufsize)
52 {
53   outbuf = (UCHAR*) malloc(bufsize);
54   if (!outbuf) return 0;
55   draintarget = tdt;
56   bufferSize = bufsize;
57   bufferHead = 0;
58   bufferTail = 0;
59   bufferMark = -1;
60   initted = 1;
61 #ifdef NEW_DEMUXER
62 #ifndef WIN32
63   pthread_mutex_init(&mutex, NULL);
64 #else
65   mutex=CreateMutex(NULL,FALSE,NULL);
66 #endif
67 #endif
68   return 1;
69 }
70
71 void Stream::flush()
72 {
73 #ifdef NEW_DEMUXER
74   lock();
75   mediapackets.clear();
76   unLock();
77   if (draintarget) draintarget->ResetTimeOffsets();
78 #endif
79   bufferHead = 0;
80   bufferTail = 0;
81   bufferMark = -1;
82 }
83
84 #ifndef NEW_DEMUXER
85 int Stream::put(UCHAR* inbuf, int len)
86 {
87   int ret = 0;
88   int tail = bufferTail;
89   int head = bufferHead;
90   if (tail == 0) tail = bufferSize;
91
92   if (head < tail)
93   {
94     // The free space is in one continuous chunk.
95     if (len < tail - head)
96     {
97       memcpy(outbuf + head, inbuf, len);
98       bufferHead += len;
99       ret = len;
100     }
101   }
102   else if (len <= bufferSize - head)
103   {
104     // There is enough space above the Head.
105     memcpy(outbuf + head, inbuf, len);
106     if (head + len == bufferSize)
107       bufferHead = 0;
108     else
109       bufferHead += len;
110     ret = len;
111   }
112   else if (len < tail)
113   {
114     bufferMark = head;
115     memcpy(outbuf, inbuf, len);
116     bufferHead = len;
117     ret = len;
118   }
119   return ret;
120 }
121 #else
122 int Stream::put(UCHAR* inbuf, int len)
123 {
124   int ret = 0;
125   int tail = bufferTail;
126   int head = bufferHead;
127   if (tail == 0) tail = bufferSize;
128
129   if (!draintarget) return 0;
130   MediaPacket newPacket;
131   newPacket.length=len;
132   newPacket.pos_buffer=0;
133   newPacket.synched=false;
134   newPacket.disconti=false;
135   newPacket.pts=0;
136   newPacket.presentation_time=0;
137   //Extract the pts...
138   if ((inbuf[7] & 0x80) && len>14 ) {
139     newPacket.synched=true;
140     newPacket.pts=((ULLONG)(inbuf[9] & 0x0E) << 29 ) |
141                 ( (ULLONG)(inbuf[10])        << 22 ) |
142                 ( (ULLONG)(inbuf[11] & 0xFE) << 14 ) |
143                 ( (ULLONG)(inbuf[12])        <<  7 ) |
144                 ( (ULLONG)(inbuf[13] & 0xFE) >>  1 );
145   //ok we have the pts now convert it to a continously time code in 100ns units
146     newPacket.presentation_time=(ULLONG)(newPacket.pts*10000LL/90LL);
147     newPacket.presentation_time-=draintarget->SetStartOffset(newPacket.presentation_time,&newPacket.disconti);
148   }
149
150   if (head < tail)
151   {
152     // The free space is in one continuous chunk.
153     if (len < tail - head)
154     {
155       memcpy(outbuf + head, inbuf, len);
156       bufferHead += len;
157       ret = len;
158       newPacket.pos_buffer=head;
159           lock();
160       mediapackets.push_front(newPacket);
161           unLock();
162     }
163   }
164   else if (len <= bufferSize - head)
165   {
166     // There is enough space above the Head.
167     memcpy(outbuf + head, inbuf, len);
168     if (head + len == bufferSize)
169       bufferHead = 0;
170     else
171       bufferHead += len;
172
173     newPacket.pos_buffer=head;
174         lock();
175     mediapackets.push_front(newPacket);
176         unLock();
177
178     ret = len;
179   }
180   else if (len < tail)
181   {
182     bufferMark = head;
183     memcpy(outbuf, inbuf, len);
184     bufferHead = len;
185     ret = len;
186     newPacket.pos_buffer=0;
187         lock();
188     mediapackets.push_front(newPacket);
189         unLock();
190   }
191   return ret;
192 }
193 #endif
194
195 #ifndef NEW_DEMUXER
196
197 int Stream::drain()
198 {
199   int ret = 0;
200   int head = bufferHead;
201   int tail = bufferTail;
202   int mark = bufferMark;
203   int written;
204
205   if (mark == -1 && tail > head) mark = bufferSize;
206
207   if (mark >= 0)
208   {
209     // Drain up to the marker.
210 #ifndef WIN32
211     written = draintarget->write(outbuf + tail, (mark - tail));
212 #else
213     written=mark-tail;
214     MILLISLEEP(1);
215 #endif
216     if (written < 0) return ret;
217     ret += written;
218     if (written == (mark - tail))
219     {
220       bufferMark = -1;
221       bufferTail = tail = 0;
222     }
223     else
224     {
225       bufferTail += written;
226       return ret;
227     }
228   }
229
230   if (tail == head) return ret; // Empty
231 #ifndef WIN32
232   written = draintarget->write(outbuf + tail, (head - tail));
233 #else
234   written=(head - tail);
235   MILLISLEEP(1);
236 #endif
237   if (written < 0) return ret;
238   ret += written;
239   bufferTail = tail + written;
240   return ret;
241 }
242
243 #else
244
245 int Stream::drain()
246 {
247   int ret = 0;
248   int written=1;
249 //  draintarget=dt; // this is now set in init, is this ok?
250
251
252
253   if (mediapackets.empty()) {
254     return 0;
255   }
256    // using mediapackets, may be this is slower but it is more flexible
257  // while (!mediapackets.empty() && written) {
258
259   int head = bufferHead;
260   int tail = bufferTail;
261   int mark = bufferMark;
262   if (mark == -1 && tail > head) mark = bufferSize;
263   lock();
264   MediaPacket cur_mp=mediapackets.back();
265   unLock();
266   written=0;
267   written=draintarget->DeliverMediaSample(cur_mp,outbuf,&cur_packet_pos);
268
269   ret+=written;
270
271   if (cur_packet_pos==cur_mp.length) {
272     cur_packet_pos=0;
273         lock();
274     mediapackets.pop_back();
275         unLock();
276     if ((((ULONG)tail)+cur_mp.length) < ((ULONG)mark)) {
277       bufferTail=tail+cur_mp.length;
278     } else {
279       bufferTail=0;
280       bufferMark=-1;
281     }
282
283   }
284
285   return ret;
286 }
287
288 void Stream::lock()
289 {
290 #ifndef WIN32
291   pthread_mutex_lock(&mutex);
292   logger->log("Player", Log::DEBUG, "LOCKED");
293
294 #else
295    WaitForSingleObject(mutex, INFINITE );
296 #endif
297 }
298
299 void Stream::unLock()
300 {
301 #ifndef WIN32
302   logger->log("Player", Log::DEBUG, "UNLOCKING");
303   pthread_mutex_unlock(&mutex);
304 #else
305    ReleaseMutex(mutex);
306 #endif
307 }
308
309 #endif