]> git.vomp.tv Git - vompclient.git/blob - imagereader.cc
Windows fixes
[vompclient.git] / imagereader.cc
1 /*
2     Copyright 2004-2006 Chris Tallon, Andreas Vogel
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 "imagereader.h"
22 #include "mediaprovider.h"
23 #include "media.h"
24 #include "i18n.h"
25 #include "log.h"
26
27
28 ImageReader::ImageReader(int c, MediaProvider *p) 
29 {
30   logger = Log::getInstance();
31   logger->log("ImageReader", Log::DEBUG, "ctorI");
32   provider=p;
33   channel=c;
34   running=false;
35   readerRunning=false;
36   this->run();
37 }
38
39 ImageReader::~ImageReader()
40 {
41   if (readerRunning) shutdown();
42   for (int i=0;i<MAXCHUNKS;i++) {
43     if (data[i].buffer != NULL) free(data[i].buffer);
44     data[i].buffer=NULL;
45   }
46 }
47
48
49 void ImageReader::run() {
50   if (running) return;
51   running=true;
52   readerRunning=true;
53   threadStart();
54 }
55
56
57 void ImageReader::shutdown()
58 {
59   running=false;
60   if (readerRunning) {
61     logger->log("ImageReader",Log::DEBUG,"shutdown - warting for reader thread to stop");
62     threadSignalNoLock();
63     logger->log("ImageReader",Log::DEBUG,"shutdown notified");
64     //wait for the reader thread to stop
65     //at most wait 10s
66     for (int loopcount=200;readerRunning && loopcount > 0;loopcount--) {
67       MILLISLEEP(50);
68     }
69     if (readerRunning) {
70       logger->log("ImageReader",Log::ERR,"shutdown - unable to stop reader within 10s");
71     }
72   }
73 }
74
75 void ImageReader::stop() {
76   if (readerRunning) {
77     threadLock();
78     int numopen=0;
79     for (int i=0; i< MAXCHUNKS;i++) {
80       if (data[i].state == S_FETCHING) {
81         data[i].state = S_BREAK;
82         numopen++;
83       }
84     }
85     threadUnlock();
86     int loopcount=200;
87     while (numopen > 0 && loopcount > 0) {
88       numopen=0;
89       logger->log("ImageReader",Log::DEBUG,"stop - warting for reader thread to stop");
90       threadSignalNoLock();
91       logger->log("ImageReader",Log::DEBUG,"stop notified");
92       MILLISLEEP(50);
93       threadLock();
94       for (int i=0; i< MAXCHUNKS;i++) {
95         if (data[i].state == S_FETCHING) {
96           data[i].state = S_BREAK;
97           numopen++;
98         }
99       }
100       threadUnlock();
101       loopcount--;
102     }
103     if (numopen > 0) 
104       logger->log("ImageReader",Log::ERR,"stop - unable to stop reader thread");
105   }
106 }
107
108
109
110 bool ImageReader::isReaderRunning() {
111   return readerRunning;
112 }
113
114
115
116 // ----------------------------------- Feed thread
117
118 void ImageReader::waitTimed(int ms) {
119   threadLock();
120   struct timespec nt;
121   int sec=ms/1000;
122   int us=1000*(ms - 1000*sec);
123 #ifndef WIN32
124   struct timeval ct;
125   gettimeofday(&ct,NULL);
126   nt.tv_sec=ct.tv_sec+sec;
127   nt.tv_nsec=1000*us+1000*ct.tv_usec;
128 #else 
129     DWORD ct=timeGetTime();
130     nt.tv_sec=ct/1000+sec;
131     nt.tv_nsec=1000*us+1000*ct*1000;
132 #endif
133   threadWaitForSignalTimed(&nt);
134   threadUnlock();
135 }
136
137 void ImageReader::threadMethod()
138 {
139   logger->log("ImageReader", Log::DEBUG, "player thread started");
140   int currentChunk=-1;
141   while(1)
142   {
143     if (! running) {
144       break;
145     }
146     if (currentChunk < 0) {
147       threadLock();
148       //check if new request is there (used=true && ongoing=true)
149       for (int i=0; i< MAXCHUNKS; i++) {
150         if (data[i].state == S_REQUEST) {
151           //found new chunk request
152           logger->log("ImageReaderThread", Log::DEBUG, "new chunk request found %i, offset=%llu, len=%u",i,data[i].offset,data[i].reqlen);
153           currentChunk=i;
154           data[i].state=S_FETCHING;
155           break;
156           }
157         }
158       threadUnlock();
159     }
160     threadCheckExit();
161     if (currentChunk < 0) {
162       waitTimed(500);
163       continue;
164     }
165     data[currentChunk].len=0;
166     logger->log("ImageReaderThread", Log::DEBUG, "start receive, offset %llu, len %u",data[currentChunk].offset,data[currentChunk].reqlen);
167     data[currentChunk].buffer=NULL;
168     int rt= provider->getMediaBlock(channel,data[currentChunk].offset, data[currentChunk].reqlen , &(data[currentChunk].len),&(data[currentChunk].buffer));
169     //set the chunk to ready
170     logger->log("ImageReaderThread", Log::DEBUG, "chunk received, offset %llu, len %u",data[currentChunk].offset,data[currentChunk].len);
171     if (rt != 0 || !(data[currentChunk].buffer) || data[currentChunk].len == 0 ) {
172         //OK we count this as end of stream
173         logger->log("ImageReaderThread", Log::DEBUG, "stream end");
174         if (data[currentChunk].buffer != NULL) {
175           free(data[currentChunk].buffer);
176           data[currentChunk].buffer=NULL;
177         }
178       }
179     threadLock();
180     //OK - now the chunk is received, try to see if we can read the next
181     //if somebody told us that this chunk is not needed any more we clean up
182     if ( data[currentChunk].state == S_BREAK) {
183       logger->log("ImageReaderThread", Log::DEBUG, "throw away chunk offset %llu, len %u", data[currentChunk].offset,data[currentChunk].reqlen);
184       data[currentChunk].len=0;
185       if (data[currentChunk].buffer) free(data[currentChunk].buffer);
186       data[currentChunk].buffer=NULL;
187       data[currentChunk].state=S_FREE;
188     }
189     data[currentChunk].state=S_READY;
190     if (data[currentChunk].len > 0) {
191       int i=0;
192       for (; i< MAXCHUNKS;i++) {
193         if (data[i].state == S_FREE ) {
194           data[i].state=S_REQUEST;
195           data[i].buffer=NULL;
196           data[i].offset=data[currentChunk].offset+data[currentChunk].len;
197           data[i].reqlen=data[currentChunk].reqlen;
198           logger->log("ImageReaderThread", Log::DEBUG, "follow on for offset %llu, len %u", data[i].offset,data[i].reqlen);
199           break;
200           }
201         }
202         //if we have a free chunk - read the data
203         if (i < MAXCHUNKS) currentChunk=i;
204         else currentChunk=-1;
205       } 
206     else {
207       //OEF or error - don't read next chunk
208       currentChunk=-1;
209       }
210     threadUnlock();
211     threadSignalNoLock();
212     }
213   logger->log("ImageReaderThread", Log::DEBUG, "finished");
214   readerRunning=false;
215   return;
216 }
217
218 void ImageReader::call(void *) {
219   threadSignalNoLock();
220 }
221  
222 // the real entry for receiving data
223 int ImageReader::getImageChunk(ULLONG  offset,UINT len, UINT * rsize, UCHAR **buffer){
224   logger->log("ImageReader", Log::DEBUG, "request chunk offset=%llu, len=%u",offset,len);
225   threadLock();
226   *buffer=NULL;
227   *rsize=0;
228   for (int found=2;found> 0; found--) {
229     //currently simple - we only check if we really have a chunk with exactly matching start
230     for (int i=0; i< MAXCHUNKS; i++ ) {
231       if (data[i].state != S_FREE && data[i].offset == offset) {
232         found=0;
233         while ( data[i].state != S_READY && data[i].state != S_FREE && readerRunning) {
234             threadUnlock();
235             waitTimed(500);
236             threadLock();
237             }
238         if (data[i].state == S_READY) {
239           //data is available
240           *buffer=data[i].buffer;
241           *rsize=data[i].len;
242           //now free the entry
243           data[i].buffer=NULL;
244           data[i].state=S_FREE;
245           logger->log("ImageReader", Log::DEBUG, "ready chunk found at index %u,offset=%llu, len=%u",i,data[i].offset,data[i].len);
246           if ( data[i].len >0) {
247             //check if the next chunk is already on the way
248             ULLONG nexto=data[i].offset+data[i].len;
249             bool nfound=false;
250             for (int x=0;x<MAXCHUNKS;x++) {
251               if (data[x].state != S_FREE && data[x].state != S_BREAK && data[x].offset==nexto) {
252                 nfound=true;
253                 break;
254               }
255             }
256             if (! nfound) {
257               //set up request for next chunk
258               data[i].offset=nexto;
259               data[i].state=S_REQUEST;
260               logger->log("ImageReader", Log::DEBUG, "next chunk requested at index %u,offset=%llu, len=%u",i,data[i].offset,data[i].reqlen);
261             }
262           }
263           break;
264           }
265         else {
266           //thread seems to be stopped
267           logger->log("ImageReader", Log::DEBUG, "no ready chunk found although in list");
268           ;
269           }
270         break;
271         }
272       }
273     if (found == 0) {
274       threadUnlock();
275       logger->log("ImageReader", Log::DEBUG, "returning buffer 0x%p, len %u",*buffer,*rsize);
276       threadSignalNoLock();
277       return 0;
278       }
279     //we found no chunk for us - so set up a new one
280     //remove all chunks 
281     for (int i=0;i<MAXCHUNKS;i++) {
282       if (data[i].state == S_FETCHING) {
283         //the reader is just fetching - let him finish
284         data[i].state = S_BREAK;
285         }
286       else {
287         data[i].state=S_FREE;
288         if (data[i].buffer) free(data[i].buffer);
289         data[i].buffer=NULL;
290       }
291     }
292     //now we should find one free anyway
293     bool ffree=false;
294     for (int i=0;i<MAXCHUNKS;i++) {
295       if (data[i].state==S_FREE) {
296         ffree=true;
297         data[i].offset=offset;
298         data[i].reqlen=len;
299         data[i].state=S_REQUEST;
300         threadSignalNoLock();
301         break;
302         }
303       }
304     if (! ffree) {
305       logger->log("ImageReader", Log::ERR, "no free chunk to load data");
306       threadUnlock();
307       return -1;
308       }
309     }
310   threadUnlock();
311   logger->log("ImageReader", Log::ERR, "unable to get data");
312   return -1;
313   }
314         
315     
316   
317
318