]> git.vomp.tv Git - vompclient-marten.git/blob - stream.cc
Detect mpeg audio frame header changes, and wait at least 4 packets after a change...
[vompclient-marten.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   unLock();
70   if (draintarget) draintarget->ResetTimeOffsets();
71 }
72
73 int Stream::put(const UCHAR* inbuf, int len, UCHAR type,unsigned int index)
74 {
75   int ret = 0;
76   if (!draintarget) return 0;
77   MediaPacket newPacket;
78   newPacket.length = len;
79   newPacket.pos_buffer = 0;
80   newPacket.type = type;
81   newPacket.pts=0;
82   newPacket.dts=0;
83   newPacket.synched=false;
84   newPacket.index=index;
85 #ifndef VOMP_PLATTFORM_MVP
86   newPacket.disconti=false;
87   newPacket.presentation_time=0;
88 #endif
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 #ifndef VOMP_PLATTFORM_MVP
108         //ok we have the pts now convert it to a continously time code in 100ns units
109         if (hasdts && draintarget->dtsTimefix()) newPacket.presentation_time=(ULLONG)(newPacket.dts*10000LL/90LL);
110         else newPacket.presentation_time=(ULLONG)(newPacket.pts*10000LL/90LL);
111
112         //newPacket.presentation_time-=draintarget->SetStartOffset((ULLONG)(newPacket.pts*10000LL/90LL),&newPacket.disconti);
113         newPacket.presentation_time-=draintarget->SetStartOffset((ULLONG)(newPacket.pts*10000LL/90LL),&newPacket.disconti);
114 #endif
115     }
116   }
117
118   lock();
119   int front, back;
120   if (mediapackets.empty())
121   {
122     back = 0; front = bufferSize;
123   }
124   else
125   {
126     front = mediapackets.front().pos_buffer;
127     back = mediapackets.back().pos_buffer + mediapackets.back().length;
128     if (back == bufferSize) back = 0;
129   }
130   unLock();
131
132   if (back <= front)
133   {
134     // The free space (if any) is in one continuous chunk.
135     if (len <= front - back) ret = len; // Is there enough of it?
136   }
137   else if (len <= bufferSize - back)
138   {
139     // There is enough space at the end of the buffer
140     ret = len;
141   }
142   else if (len <= front)
143   {
144     // There is enough space at the start of the buffer
145     back = 0;
146     ret = len;
147   }
148
149   if (ret) // Nonzero if we managed to find room for the packet
150   {
151     memcpy(outbuf + back, inbuf, len);
152     newPacket.pos_buffer = back;
153     lock();
154     mediapackets.push_back(newPacket);
155     unLock();
156   } else {
157      // Log::getInstance()->log("Stream", Log::DEBUG, "We are full %d!",bufferSize);
158   }
159
160   return ret;
161 }
162
163 bool Stream::drain(bool * dataavail)
164 {
165   bool ret = false;
166   if (dataavail) *dataavail=false;
167   if (draintarget->DrainTargetBufferFull()) return false; //We are full, no need to do something else
168   lock();
169   UINT listlength = mediapackets.size();
170   if (listlength != 0)
171   {
172     draintarget->PrepareMediaSample(mediapackets, cur_packet_pos);
173     unLock();
174     if (dataavail && draintarget->DrainTargetReady()) *dataavail=true;
175     UINT consumed = draintarget->DeliverMediaSample(outbuf, &cur_packet_pos);
176     lock();
177     if (consumed != 0) ret = true;
178     if (consumed > listlength) consumed = listlength;
179     while (consumed--) 
180     {
181         mediapackets.pop_front();
182     }
183   }
184   unLock();
185   return ret;
186 }
187
188 void Stream::lock()
189 {
190 #ifndef WIN32
191   pthread_mutex_lock(&mutex);
192   //logger->log("Player", Log::DEBUG, "LOCKED");
193
194 #else
195    WaitForSingleObject(mutex, INFINITE );
196 #endif
197 }
198
199 void Stream::unLock()
200 {
201 #ifndef WIN32
202   //logger->log("Player", Log::DEBUG, "UNLOCKING");
203   pthread_mutex_unlock(&mutex);
204 #else
205    ReleaseMutex(mutex);
206 #endif
207 }