]> git.vomp.tv Git - vompclient.git/blob - stream.cc
Preparations for dynamic mode switching
[vompclient.git] / stream.cc
1 /*\r
2     Copyright 2005-2006 Mark Calderbank\r
3 \r
4     This file is part of VOMP.\r
5 \r
6     VOMP is free software; you can redistribute it and/or modify\r
7     it under the terms of the GNU General Public License as published by\r
8     the Free Software Foundation; either version 2 of the License, or\r
9     (at your option) any later version.\r
10 \r
11     VOMP is distributed in the hope that it will be useful,\r
12     but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14     GNU General Public License for more details.\r
15 \r
16     You should have received a copy of the GNU General Public License\r
17     along with VOMP; if not, write to the Free Software\r
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
19 */\r
20 \r
21 #include "stream.h"\r
22 #include "log.h"\r
23 \r
24 Stream::Stream()\r
25 {\r
26   initted = 0;\r
27   draintarget = NULL;\r
28   cur_packet_pos = 0;\r
29 }\r
30 \r
31 Stream::~Stream()\r
32 {\r
33   shutdown();\r
34 }\r
35 \r
36 void Stream::shutdown()\r
37 {\r
38   if (initted)\r
39   {\r
40     free(outbuf);\r
41 #ifdef WIN32\r
42     CloseHandle(mutex);\r
43 #endif\r
44       \r
45   }\r
46   initted = 0;\r
47 }\r
48 \r
49 int Stream::init(DrainTarget* tdt, int bufsize)\r
50 {\r
51   outbuf = (UCHAR*) malloc(bufsize);\r
52   if (!outbuf) return 0;\r
53   draintarget = tdt;\r
54   bufferSize = bufsize;\r
55   initted = 1;\r
56 #ifndef WIN32\r
57   pthread_mutex_init(&mutex, NULL);\r
58 #else\r
59   mutex=CreateMutex(NULL,FALSE,NULL);\r
60 #endif\r
61   return 1;\r
62 }\r
63 \r
64 void Stream::flush()\r
65 {\r
66   lock();\r
67 \r
68   mediapackets.clear();\r
69   unLock();\r
70   if (draintarget) draintarget->ResetTimeOffsets();\r
71 }\r
72 \r
73 int Stream::put(const UCHAR* inbuf, int len, UCHAR type,unsigned int index)\r
74 {\r
75   int ret = 0;\r
76   if (!draintarget) return 0;\r
77   MediaPacket newPacket;\r
78   newPacket.length = len;\r
79   newPacket.pos_buffer = 0;\r
80   newPacket.type = type;\r
81   newPacket.pts=0;\r
82   newPacket.dts=0;\r
83   newPacket.synched=false;\r
84   newPacket.index=index;\r
85 #ifndef VOMP_PLATTFORM_MVP\r
86   newPacket.disconti=false;\r
87   newPacket.presentation_time=0;\r
88 #endif\r
89   if (type!=MPTYPE_MPEG_AUDIO_LAYER3) {//no PES\r
90     //Extract the pts...\r
91       bool hasdts=false;\r
92     if ((inbuf[7] & 0x80) && len>14 ) {\r
93         newPacket.synched=true;\r
94         newPacket.pts=((ULLONG)(inbuf[9] & 0x0E) << 29 ) |\r
95                     ( (ULLONG)(inbuf[10])        << 22 ) |\r
96                     ( (ULLONG)(inbuf[11] & 0xFE) << 14 ) |\r
97                      ( (ULLONG)(inbuf[12])        <<  7 ) |\r
98                      ( (ULLONG)(inbuf[13] & 0xFE) >>  1 );\r
99         if ((inbuf[7] & 0x40) && len>19) {\r
100             newPacket.dts=((ULLONG)(inbuf[14] & 0x0E) << 29 ) |\r
101                     ( (ULLONG)(inbuf[15])        << 22 ) |\r
102                     ( (ULLONG)(inbuf[16] & 0xFE) << 14 ) |\r
103                      ( (ULLONG)(inbuf[17])        <<  7 ) |\r
104                      ( (ULLONG)(inbuf[18] & 0xFE) >>  1 );\r
105             hasdts=true;\r
106         }\r
107 #ifndef VOMP_PLATTFORM_MVP\r
108         //ok we have the pts now convert it to a continously time code in 100ns units\r
109         if (hasdts && draintarget->dtsTimefix()) newPacket.presentation_time=(ULLONG)(newPacket.dts*10000LL/90LL);\r
110         else newPacket.presentation_time=(ULLONG)(newPacket.pts*10000LL/90LL);\r
111 \r
112         //newPacket.presentation_time-=draintarget->SetStartOffset((ULLONG)(newPacket.pts*10000LL/90LL),&newPacket.disconti);\r
113         newPacket.presentation_time-=draintarget->SetStartOffset((ULLONG)(newPacket.pts*10000LL/90LL),&newPacket.disconti);\r
114 #endif\r
115     }\r
116   }\r
117 \r
118   lock();\r
119   int front, back;\r
120   if (mediapackets.empty())\r
121   {\r
122     back = 0; front = bufferSize;\r
123   }\r
124   else\r
125   {\r
126     front = mediapackets.front().pos_buffer;\r
127     back = mediapackets.back().pos_buffer + mediapackets.back().length;\r
128     if (back == bufferSize) back = 0;\r
129   }\r
130   unLock();\r
131 \r
132   if (back <= front)\r
133   {\r
134     // The free space (if any) is in one continuous chunk.\r
135     if (len <= front - back) ret = len; // Is there enough of it?\r
136   }\r
137   else if (len <= bufferSize - back)\r
138   {\r
139     // There is enough space at the end of the buffer\r
140     ret = len;\r
141   }\r
142   else if (len <= front)\r
143   {\r
144     // There is enough space at the start of the buffer\r
145     back = 0;\r
146     ret = len;\r
147   }\r
148 \r
149   if (ret) // Nonzero if we managed to find room for the packet\r
150   {\r
151     memcpy(outbuf + back, inbuf, len);\r
152     newPacket.pos_buffer = back;\r
153     lock();\r
154     mediapackets.push_back(newPacket);\r
155     unLock();\r
156   } else {\r
157      // Log::getInstance()->log("Stream", Log::DEBUG, "We are full %d!",bufferSize);\r
158   }\r
159 \r
160   return ret;\r
161 }\r
162 \r
163 bool Stream::drain(bool * dataavail)\r
164 {\r
165   bool ret = false;\r
166   if (dataavail) *dataavail=false;\r
167   lock();\r
168   UINT listlength = mediapackets.size();\r
169   if (listlength != 0)\r
170   {\r
171     draintarget->PrepareMediaSample(mediapackets, cur_packet_pos);\r
172     unLock();\r
173     if (dataavail && draintarget->DrainTargetReady()) *dataavail=true;\r
174     UINT consumed = draintarget->DeliverMediaSample(outbuf, &cur_packet_pos);\r
175     lock();\r
176     if (consumed != 0) ret = true;\r
177     if (consumed > listlength) consumed = listlength;\r
178     while (consumed--) \r
179     {\r
180         mediapackets.pop_front();\r
181     }\r
182   }\r
183   unLock();\r
184   return ret;\r
185 }\r
186 \r
187 void Stream::lock()\r
188 {\r
189 #ifndef WIN32\r
190   pthread_mutex_lock(&mutex);\r
191   //logger->log("Player", Log::DEBUG, "LOCKED");\r
192 \r
193 #else\r
194    WaitForSingleObject(mutex, INFINITE );\r
195 #endif\r
196 }\r
197 \r
198 void Stream::unLock()\r
199 {\r
200 #ifndef WIN32\r
201   //logger->log("Player", Log::DEBUG, "UNLOCKING");\r
202   pthread_mutex_unlock(&mutex);\r
203 #else\r
204    ReleaseMutex(mutex);\r
205 #endif\r
206 }\r