]> git.vomp.tv Git - vompclient.git/blob - stream.cc
Fix for possible crash when removing bar
[vompclient.git] / stream.cc
1 /*
2     Copyright 2005-2006 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 #include "log.h"
23
24 Stream::Stream()
25 {
26   initted = 0;
27   draintarget = NULL;
28   cur_packet_pos = 0;
29 }
30
31 Stream::~Stream()
32 {
33   shutdown();
34 }
35
36 void Stream::shutdown()
37 {
38   if (initted)
39   {
40     free(outbuf);
41 #ifdef WIN32
42     CloseHandle(mutex);
43 #endif
44   }
45   initted = 0;
46 }
47
48 int Stream::init(DrainTarget* tdt, int bufsize)
49 {
50   outbuf = (UCHAR*) malloc(bufsize);
51   if (!outbuf) return 0;
52   draintarget = tdt;
53   bufferSize = bufsize;
54   initted = 1;
55 #ifndef WIN32
56   pthread_mutex_init(&mutex, NULL);
57 #else
58   mutex=CreateMutex(NULL,FALSE,NULL);
59 #endif
60   return 1;
61 }
62
63 void Stream::flush()
64 {
65   lock();
66   mediapackets.clear();
67   unLock();
68   if (draintarget) draintarget->ResetTimeOffsets();
69 }
70
71 int Stream::put(const UCHAR* inbuf, int len, UCHAR type)
72 {
73   int ret = 0;
74   if (!draintarget) return 0;
75   MediaPacket newPacket;
76   newPacket.length = len;
77   newPacket.pos_buffer = 0;
78   newPacket.type = type;
79 #ifdef WIN32
80   newPacket.synched=false;
81   newPacket.disconti=false;
82   newPacket.pts=0;
83   newPacket.presentation_time=0;
84   //Extract the pts...
85   if ((inbuf[7] & 0x80) && len>14 ) {
86     newPacket.synched=true;
87     newPacket.pts=((ULLONG)(inbuf[9] & 0x0E) << 29 ) |
88                 ( (ULLONG)(inbuf[10])        << 22 ) |
89                 ( (ULLONG)(inbuf[11] & 0xFE) << 14 ) |
90                 ( (ULLONG)(inbuf[12])        <<  7 ) |
91                 ( (ULLONG)(inbuf[13] & 0xFE) >>  1 );
92   //ok we have the pts now convert it to a continously time code in 100ns units
93     newPacket.presentation_time=(ULLONG)(newPacket.pts*10000LL/90LL);
94     newPacket.presentation_time-=draintarget->SetStartOffset(newPacket.presentation_time,&newPacket.disconti);
95   }
96 #endif
97
98   lock();
99   int front, back;
100   if (mediapackets.empty())
101   {
102     back = 0; front = bufferSize;
103   }
104   else
105   {
106     front = mediapackets.front().pos_buffer;
107     back = mediapackets.back().pos_buffer + mediapackets.back().length;
108     if (back == bufferSize) back = 0;
109   }
110   unLock();
111
112   if (back <= front)
113   {
114     // The free space (if any) is in one continuous chunk.
115     if (len <= front - back) ret = len; // Is there enough of it?
116   }
117   else if (len <= bufferSize - back)
118   {
119     // There is enough space at the end of the buffer
120     ret = len;
121   }
122   else if (len <= front)
123   {
124     // There is enough space at the start of the buffer
125     back = 0;
126     ret = len;
127   }
128
129   if (ret) // Nonzero if we managed to find room for the packet
130   {
131     memcpy(outbuf + back, inbuf, len);
132     newPacket.pos_buffer = back;
133     lock();
134     mediapackets.push_back(newPacket);
135     unLock();
136   }
137   return ret;
138 }
139
140 bool Stream::drain()
141 {
142   bool ret = false;
143   lock();
144   UINT listlength = mediapackets.size();
145   if (listlength != 0)
146   {
147     draintarget->PrepareMediaSample(mediapackets, cur_packet_pos);
148     unLock();
149     UINT consumed = draintarget->DeliverMediaSample(outbuf, &cur_packet_pos);
150     lock();
151     if (consumed != 0) ret = true;
152     if (consumed > listlength) consumed = listlength;
153     while (consumed--) mediapackets.pop_front();
154   }
155   unLock();
156   return ret;
157 }
158
159 void Stream::lock()
160 {
161 #ifndef WIN32
162   pthread_mutex_lock(&mutex);
163   //logger->log("Player", Log::DEBUG, "LOCKED");
164
165 #else
166    WaitForSingleObject(mutex, INFINITE );
167 #endif
168 }
169
170 void Stream::unLock()
171 {
172 #ifndef WIN32
173   //logger->log("Player", Log::DEBUG, "UNLOCKING");
174   pthread_mutex_unlock(&mutex);
175 #else
176    ReleaseMutex(mutex);
177 #endif
178 }