]> git.vomp.tv Git - vompclient.git/blob - stream.cc
Rewrite timers class using std::thread/mutex/cond/chrono
[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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 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   }
46   initted = 0;
47 }
48
49 int Stream::init(DrainTarget* tdt, int bufsize)
50 {
51   outbuf = (UCHAR*) malloc(bufsize);
52   if (!outbuf) return 0;
53   draintarget = tdt;
54   bufferSize = bufsize;
55   initted = 1;
56 #ifndef WIN32
57   pthread_mutex_init(&mutex, NULL);
58 #else
59   mutex=CreateMutex(NULL,FALSE,NULL);
60 #endif
61   return 1;
62 }
63
64 void Stream::flush()
65 {
66   lock();
67
68   mediapackets.clear();
69   cur_packet_pos = 0;
70   unLock();
71   if (draintarget) draintarget->ResetTimeOffsets();
72 }
73
74 int Stream::put(const UCHAR* inbuf, int len, UCHAR type,unsigned int index)
75 {
76   int ret = 0;
77   if (!draintarget) return 0;
78   MediaPacket newPacket;
79   newPacket.length = len;
80   newPacket.pos_buffer = 0;
81   newPacket.type = type;
82   newPacket.pts=0;
83   newPacket.dts=0;
84   newPacket.synched=false;
85   newPacket.index=index;
86   newPacket.disconti=false;
87   newPacket.presentation_time=0;
88
89   if (type!=MPTYPE_MPEG_AUDIO_LAYER3) {//no PES
90     //Extract the pts...
91       bool hasdts=false;
92     if ((inbuf[7] & 0x80) && len>14 ) {
93         newPacket.synched=true;
94         newPacket.pts=((ULLONG)(inbuf[9] & 0x0E) << 29 ) |
95                     ( (ULLONG)(inbuf[10])        << 22 ) |
96                     ( (ULLONG)(inbuf[11] & 0xFE) << 14 ) |
97                      ( (ULLONG)(inbuf[12])        <<  7 ) |
98                      ( (ULLONG)(inbuf[13] & 0xFE) >>  1 );
99         if ((inbuf[7] & 0x40) && len>19) {
100             newPacket.dts=((ULLONG)(inbuf[14] & 0x0E) << 29 ) |
101                     ( (ULLONG)(inbuf[15])        << 22 ) |
102                     ( (ULLONG)(inbuf[16] & 0xFE) << 14 ) |
103                      ( (ULLONG)(inbuf[17])        <<  7 ) |
104                      ( (ULLONG)(inbuf[18] & 0xFE) >>  1 );
105             hasdts=true;
106         }
107         //ok we have the pts now convert it to a continously time code in 100ns units
108         if (hasdts && draintarget->dtsTimefix()) newPacket.presentation_time=(ULLONG)(newPacket.dts*10000LL/90LL);
109         else newPacket.presentation_time=(ULLONG)(newPacket.pts*10000LL/90LL);
110
111         //newPacket.presentation_time-=draintarget->SetStartOffset((ULLONG)(newPacket.pts*10000LL/90LL),&newPacket.disconti);
112         newPacket.presentation_time-=draintarget->SetStartOffset((ULLONG)(newPacket.pts*10000LL/90LL),&newPacket.disconti);
113     }
114   }
115
116   lock();
117   int front, back;
118   if (mediapackets.empty())
119   {
120     back = 0; front = bufferSize;
121   }
122   else
123   {
124     front = mediapackets.front().pos_buffer;
125     back = mediapackets.back().pos_buffer + mediapackets.back().length;
126     if (back == bufferSize) back = 0;
127   }
128   unLock();
129
130   if (back <= front)
131   {
132     // The free space (if any) is in one continuous chunk.
133     if (len <= front - back) ret = len; // Is there enough of it?
134   }
135   else if (len <= bufferSize - back)
136   {
137     // There is enough space at the end of the buffer
138     ret = len;
139   }
140   else if (len <= front)
141   {
142     // There is enough space at the start of the buffer
143     back = 0;
144     ret = len;
145   }
146
147   if (ret) // Nonzero if we managed to find room for the packet
148   {
149     memcpy(outbuf + back, inbuf, len);
150     newPacket.pos_buffer = back;
151     lock();
152     mediapackets.push_back(newPacket);
153     unLock();
154   } else {
155      // Log::getInstance()->log("Stream", Log::DEBUG, "We are full %d!",bufferSize);
156   }
157
158   return ret;
159 }
160
161 bool Stream::drain(bool * dataavail)
162 {
163   bool ret = false;
164   if (dataavail) *dataavail=false;
165   if (draintarget->DrainTargetBufferFull()) return false; //We are full, no need to do something else
166   lock();
167   UINT listlength = mediapackets.size();
168   if (listlength != 0)
169   {
170     draintarget->PrepareMediaSample(mediapackets, cur_packet_pos);
171     unLock();
172     if (dataavail && draintarget->DrainTargetReady()) *dataavail=true;
173     UINT consumed = draintarget->DeliverMediaSample(outbuf, &cur_packet_pos);
174     lock();
175     if (consumed != 0) ret = true;
176     if (consumed > listlength) consumed = listlength;
177     while (consumed--) 
178     {
179         mediapackets.pop_front();
180     }
181   }
182   unLock();
183   return ret;
184 }
185
186 void Stream::lock()
187 {
188 #ifndef WIN32
189   pthread_mutex_lock(&mutex);
190   //logger->log("Player", Log::DEBUG, "LOCKED");
191
192 #else
193    WaitForSingleObject(mutex, INFINITE );
194 #endif
195 }
196
197 void Stream::unLock()
198 {
199 #ifndef WIN32
200   //logger->log("Player", Log::DEBUG, "UNLOCKING");
201   pthread_mutex_unlock(&mutex);
202 #else
203    ReleaseMutex(mutex);
204 #endif
205 }