]> git.vomp.tv Git - vompclient.git/blob - stream.cc
Windows port
[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,ULLONG curpos)
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.recording_byte_pos=curpos;
134   newPacket.synched=false;
135   newPacket.disconti=false;
136   newPacket.pts=0;
137   newPacket.presentation_time=0;
138   //Extract the pts...
139   if ((inbuf[7] & 0x80) && len>14 ) {
140     newPacket.synched=true;
141     newPacket.pts=((ULLONG)(inbuf[9] & 0x0E) << 29 ) |
142                 ( (ULLONG)(inbuf[10])        << 22 ) |
143                 ( (ULLONG)(inbuf[11] & 0xFE) << 14 ) |
144                 ( (ULLONG)(inbuf[12])        <<  7 ) |
145                 ( (ULLONG)(inbuf[13] & 0xFE) >>  1 );
146   //ok we have the pts now convert it to a continously time code in 100ns units
147     newPacket.presentation_time=(ULLONG)(newPacket.pts*10000LL/90LL);
148     newPacket.presentation_time-=draintarget->SetStartOffset(newPacket.presentation_time,&newPacket.disconti);
149   }
150
151   if (head < tail)
152   {
153     // The free space is in one continuous chunk.
154     if (len < tail - head)
155     {
156       memcpy(outbuf + head, inbuf, len);
157       bufferHead += len;
158       ret = len;
159       newPacket.pos_buffer=head;
160           lock();
161       mediapackets.push_front(newPacket);
162           unLock();
163     }
164   }
165   else if (len <= bufferSize - head)
166   {
167     // There is enough space above the Head.
168     memcpy(outbuf + head, inbuf, len);
169     if (head + len == bufferSize)
170       bufferHead = 0;
171     else
172       bufferHead += len;
173
174     newPacket.pos_buffer=head;
175         lock();
176     mediapackets.push_front(newPacket);
177         unLock();
178
179     ret = len;
180   }
181   else if (len < tail)
182   {
183     bufferMark = head;
184     memcpy(outbuf, inbuf, len);
185     bufferHead = len;
186     ret = len;
187     newPacket.pos_buffer=0;
188         lock();
189     mediapackets.push_front(newPacket);
190         unLock();
191   }
192   return ret;
193 }
194 #endif
195
196 #ifndef NEW_DEMUXER
197
198 int Stream::drain()
199 {
200   int ret = 0;
201   int head = bufferHead;
202   int tail = bufferTail;
203   int mark = bufferMark;
204   int written;
205
206   if (mark == -1 && tail > head) mark = bufferSize;
207
208   if (mark >= 0)
209   {
210     // Drain up to the marker.
211 #ifndef WIN32
212     written = draintarget->write(outbuf + tail, (mark - tail));
213 #else
214     written=mark-tail;
215     MILLISLEEP(1);
216 #endif
217     if (written < 0) return ret;
218     ret += written;
219     if (written == (mark - tail))
220     {
221       bufferMark = -1;
222       bufferTail = tail = 0;
223     }
224     else
225     {
226       bufferTail += written;
227       return ret;
228     }
229   }
230
231   if (tail == head) return ret; // Empty
232 #ifndef WIN32
233   written = draintarget->write(outbuf + tail, (head - tail));
234 #else
235   written=(head - tail);
236   MILLISLEEP(1);
237 #endif
238   if (written < 0) return ret;
239   ret += written;
240   bufferTail = tail + written;
241   return ret;
242 }
243
244 #else
245
246 int Stream::drain()
247 {
248   int ret = 0;
249   int written=1;
250 //  draintarget=dt; // this is now set in init, is this ok?
251
252
253
254   if (mediapackets.empty()) {
255     return 0;
256   }
257    // using mediapackets, may be this is slower but it is more flexible
258  // while (!mediapackets.empty() && written) {
259
260   int head = bufferHead;
261   int tail = bufferTail;
262   int mark = bufferMark;
263   if (mark == -1 && tail > head) mark = bufferSize;
264   lock();
265   MediaPacket cur_mp=mediapackets.back();
266   unLock();
267   written=0;
268   written=draintarget->DeliverMediaSample(cur_mp,outbuf,&cur_packet_pos);
269
270   ret+=written;
271
272   if (cur_packet_pos==cur_mp.length) {
273     cur_packet_pos=0;
274         lock();
275     mediapackets.pop_back();
276         unLock();
277     if ((((ULONG)tail)+cur_mp.length) < ((ULONG)mark)) {
278       bufferTail=tail+cur_mp.length;
279     } else {
280       bufferTail=0;
281       bufferMark=-1;
282     }
283
284   }
285
286   return ret;
287 }
288
289 void Stream::lock()
290 {
291 #ifndef WIN32
292   pthread_mutex_lock(&mutex);
293   logger->log("Player", Log::DEBUG, "LOCKED");
294
295 #else
296    WaitForSingleObject(mutex, INFINITE );
297 #endif
298 }
299
300 void Stream::unLock()
301 {
302 #ifndef WIN32
303   logger->log("Player", Log::DEBUG, "UNLOCKING");
304   pthread_mutex_unlock(&mutex);
305 #else
306    ReleaseMutex(mutex);
307 #endif
308 }
309
310 #endif