]> git.sesse.net Git - vlc/blob - modules/video_filter/atmo/AtmoExternalCaptureInput.cpp
Merge commit 'origin/base'
[vlc] / modules / video_filter / atmo / AtmoExternalCaptureInput.cpp
1 /*
2  * AtmoExternalCaptureInput.cpp: Datasource which gets its data via a COM object call
3  * or some other external method.
4  *
5  *
6  * See the README.txt file for copyright information and how to reach the author(s).
7  *
8  * $Id$
9 */
10
11 #include "AtmoExternalCaptureInput.h"
12 #include "AtmoTools.h"
13
14 #ifndef INT64_C
15 #define INT64_C(c)  c ## LL
16 #endif
17
18 #if defined(_ATMO_VLC_PLUGIN_)
19
20 CAtmoExternalCaptureInput::CAtmoExternalCaptureInput(CAtmoDynData *pAtmoDynData) :
21                            CAtmoInput(pAtmoDynData),
22                            CThread(pAtmoDynData->getAtmoFilter())
23 {
24     m_pCurrentFramePixels = NULL;
25     vlc_cond_init( &m_WakeupCond );
26     vlc_mutex_init( &m_WakeupLock );
27     msg_Dbg( m_pAtmoThread, "CAtmoExternalCaptureInput created.");
28
29 }
30
31 #else
32
33 CAtmoExternalCaptureInput::CAtmoExternalCaptureInput(CAtmoDynData *pAtmoDynData) :
34                            CAtmoInput(pAtmoDynData)
35 {
36     m_hWakeupEvent = CreateEvent(NULL,ATMO_FALSE,ATMO_FALSE,NULL);
37     m_pCurrentFramePixels = NULL;
38 }
39
40 #endif
41
42 CAtmoExternalCaptureInput::~CAtmoExternalCaptureInput(void)
43 {
44    /* if there is still an unprocessed bufferpicture do kill it */
45    if(m_pCurrentFramePixels != NULL)
46       free(m_pCurrentFramePixels);
47
48 #if defined(_ATMO_VLC_PLUGIN_)
49     vlc_cond_destroy( &m_WakeupCond );
50     vlc_mutex_destroy(&m_WakeupLock);
51     msg_Dbg( m_pAtmoThread, "CAtmoExternalCaptureInput destroyed.");
52 #else
53     CloseHandle(m_hWakeupEvent);
54 #endif
55 }
56
57 ATMO_BOOL CAtmoExternalCaptureInput::Open()
58 {
59     this->Run();
60     return ATMO_TRUE;
61 }
62
63 // Closes the input-device.
64 // Returns true if the input-device was closed successfully.
65 ATMO_BOOL CAtmoExternalCaptureInput::Close(void)
66 {
67     this->Terminate();
68     return ATMO_TRUE;
69 }
70
71 tColorPacket CAtmoExternalCaptureInput::GetColorPacket(void)
72 {
73     return this->m_ColorPacket;
74 }
75
76 /*
77   this method will be called from another thread or possible the COM Server to feed
78   new pixeldata into the calculation process it doest just the following:
79   1: check if last buffer was allready processed (!m_pCurrentFramePixels)
80   2. copy the bitmap info structure into the threads own one
81   3. alloc memory for frame
82   4. copy sourcepixeldata into own buffer...
83   5. let the thread wake up and return imediately to the caller
84   so that the real videoout wouldn't be stop for a too long time
85 */
86 void CAtmoExternalCaptureInput::DeliverNewSourceDataPaket(BITMAPINFOHEADER *bmpInfoHeader,void *pixelData)
87 {
88     /*
89        normaly we should protect this area of code by critical_section or a mutex,
90        but I think we can omit this here because the timing this method is called
91        is really slow (in terms of the speed of a modern computer?)
92        so it's nearly impossible that two frames are delivert in the same time
93        the test needs and malloc needs...
94     */
95     if( !m_pCurrentFramePixels )
96     {
97         // Last Frame was processed... take this one...
98         memcpy(&m_CurrentFrameHeader,bmpInfoHeader,bmpInfoHeader->biSize);
99         int PixelDataSize = m_CurrentFrameHeader.biHeight * m_CurrentFrameHeader.biWidth;
100         switch(m_CurrentFrameHeader.biBitCount) {
101             case 8:  /* PixelDataSize = PixelDataSize; */ break;
102             case 16: PixelDataSize = PixelDataSize * 2; break;
103             case 24: PixelDataSize = PixelDataSize * 3; break;
104             case 32: PixelDataSize = PixelDataSize * 4; break;
105         }
106         m_pCurrentFramePixels = malloc(PixelDataSize);
107         memcpy(m_pCurrentFramePixels,pixelData,PixelDataSize);
108     }
109 #if defined(_ATMO_VLC_PLUGIN_)
110    vlc_mutex_lock( &m_WakeupLock );
111    vlc_cond_signal( &m_WakeupCond );
112    vlc_mutex_unlock( &m_WakeupLock );
113 #else
114     SetEvent(m_hWakeupEvent);
115 #endif
116 }
117
118
119
120 /*
121  the real thread Method which is processing the pixeldata into the hardware channel
122  values - which are used by the thread AtmoLiveView...
123 */
124 #if defined (_ATMO_VLC_PLUGIN_)
125
126 DWORD CAtmoExternalCaptureInput::Execute(void)
127 {
128     msg_Dbg( m_pAtmoThread, "CAtmoExternalCaptureInput::Execute(void)");
129     int i = 0;
130
131     vlc_mutex_lock( &m_WakeupLock );
132
133     while ((this->m_bTerminated == ATMO_FALSE) && (!vlc_object_alive (this->m_pAtmoThread) == false)) {
134           int value = vlc_cond_timedwait(&m_WakeupCond, &m_WakeupLock, mdate() + INT64_C(75000));
135           if(!value) {
136              /* DeliverNewSourceDataPaket delivered new work for me... get it! */
137              CalcColors(); // read picture and calculate colors
138              this->m_FrameArrived = ATMO_TRUE;
139           }
140           i++;
141           if(i == 100) {
142              i = 0;
143 #if !defined(WIN32)
144 /* kludge for pthreads? using the same condition variable too often results in hanging the pthread
145    call inside vlc_cond_timedwait...
146 */
147 #ifdef _ATMO_KLUDGE_
148              vlc_cond_destroy( &m_WakeupCond );
149              vlc_cond_init( &m_WakeupCond );
150 #endif
151 #endif
152           }
153     }
154     vlc_mutex_unlock( &m_WakeupLock );
155
156     return 0;
157 }
158
159 #else
160
161 DWORD CAtmoExternalCaptureInput::Execute(void) {
162     HANDLE handles[2];
163     handles[0] = this->m_hTerminateEvent;
164     handles[1] = m_hWakeupEvent;
165
166     while (this->m_bTerminated == ATMO_FALSE) {
167            DWORD event = WaitForMultipleObjects(2,handles,ATMO_FALSE,INFINITE);
168            if(event == WAIT_OBJECT_0) {
169               // Terminate Thread Event was set... say good bye...!
170               break;
171            }
172            if(event == (WAIT_OBJECT_0+1)) {
173               CalcColors(); // read picture and calculate colors
174               this->m_FrameArrived = ATMO_TRUE;
175            }
176     }
177     return 0;
178 }
179
180 #endif
181
182
183 void CAtmoExternalCaptureInput::WaitForNextFrame(DWORD timeout)
184 {
185     this->m_FrameArrived = ATMO_FALSE;
186     for(DWORD i=0;(i<timeout) && !m_FrameArrived;i++)
187 #if defined (_ATMO_VLC_PLUGIN_)
188         msleep(1000);
189 #else
190         Sleep(1);
191 #endif
192
193     if(this->m_pAtmoDynData)
194     {
195         CAtmoConfig *cfg = this->m_pAtmoDynData->getAtmoConfig();
196         if(cfg)
197         {
198             int delay = cfg->getLiveView_FrameDelay();
199             if(delay > 0)
200             {
201 #if defined (_ATMO_VLC_PLUGIN_)
202               msleep(delay * 1000);
203 #else
204               Sleep(delay);
205 #endif
206             }
207         }
208     }
209 }
210
211 void CAtmoExternalCaptureInput::CalcColors() {
212      // take data from m_CurrentFrameHeader and m_pCurrentFramePixels .. process for atmo ...
213     tHSVColor HSV_Img[IMAGE_SIZE];
214     tRGBColor pixelColor;
215     int srcIndex,index = 0;
216     memset(&HSV_Img,0,sizeof(HSV_Img));
217
218      // Convert Data to HSV values.. bla bla....
219     if(m_pCurrentFramePixels!=NULL)
220     {
221         if((m_CurrentFrameHeader.biWidth == CAP_WIDTH) && (m_CurrentFrameHeader.biHeight == CAP_HEIGHT))
222         {
223
224           // HSVI = HSV Image allready in right format just copy the easiest task
225           // und weiterverarbeiten lassen
226 #ifdef _ATMO_VLC_PLUGIN_
227           if(m_CurrentFrameHeader.biCompression ==  VLC_FOURCC('H','S','V','I'))
228 #else
229           if(m_CurrentFrameHeader.biCompression ==  MakeDword('H','S','V','I'))
230 #endif
231           {
232               memcpy( &HSV_Img, m_pCurrentFramePixels, CAP_WIDTH * CAP_HEIGHT * sizeof(tHSVColor));
233           }
234           else if(m_CurrentFrameHeader.biCompression == BI_RGB)
235           {
236              if(m_CurrentFrameHeader.biBitCount == 16)
237              {
238                  unsigned short *buffer = (unsigned short *)m_pCurrentFramePixels;
239
240                  for(int y=0;y<CAP_HEIGHT;y++)
241                  {
242                      srcIndex = y * CAP_WIDTH;
243                      for(int x=0;x<CAP_WIDTH;x++)
244                      {
245                          pixelColor.b = (buffer[srcIndex] & 31) << 3;
246                          pixelColor.g = ((buffer[srcIndex] >> 5) & 31) << 3;
247                          pixelColor.r = ((buffer[srcIndex] >> 10) & 63) << 2;
248                          srcIndex++;
249                          HSV_Img[index++] = RGB2HSV(pixelColor);
250                      }
251                  }
252              }
253              else if(m_CurrentFrameHeader.biBitCount == 24)
254              {
255                  for(int y=0;y<CAP_HEIGHT;y++)
256                  {
257                      srcIndex = y * (CAP_WIDTH*3);
258                      for(int x=0;x<CAP_WIDTH;x++)
259                      {
260                          pixelColor.b = ((unsigned char *)m_pCurrentFramePixels)[srcIndex++];
261                          pixelColor.g = ((unsigned char *)m_pCurrentFramePixels)[srcIndex++];
262                          pixelColor.r = ((unsigned char *)m_pCurrentFramePixels)[srcIndex++];
263                          HSV_Img[index++] = RGB2HSV(pixelColor);
264                      }
265                  }
266              }
267              else if(m_CurrentFrameHeader.biBitCount == 32)
268              {
269                  for(int y=0;y<CAP_HEIGHT;y++)
270                  {
271                      srcIndex = y * (CAP_WIDTH*4);
272                      for(int x=0;x<CAP_WIDTH;x++)
273                      {
274                          pixelColor.b = ((unsigned char *)m_pCurrentFramePixels)[srcIndex++];
275                          pixelColor.g = ((unsigned char *)m_pCurrentFramePixels)[srcIndex++];
276                          pixelColor.r = ((unsigned char *)m_pCurrentFramePixels)[srcIndex++];
277                          srcIndex++;
278                          HSV_Img[index++] = RGB2HSV(pixelColor);
279                      }
280                  }
281              }
282           }
283        }
284
285        /*
286           if the image color format wasn't recognized - the output
287           will be black (memset)
288        */
289
290        /*
291           now convert the pixeldata into one RGB trippel for each channel,
292           this is done by some very sophisticated methods and statistics ...
293
294           the only thing I know - the pixel priority is controled by some
295           gradients for each edge of the picture
296
297           (sorry I don't know how it exactly works because the formulars
298            are done by some one else...)
299        */
300        m_ColorPacket = CalcColorsAnalyzeHSV(this->m_pAtmoDynData->getAtmoConfig(), HSV_Img);
301
302        /* remove the source buffe */
303        free(m_pCurrentFramePixels);
304        /*
305           the buffer zereo so that deliver new data paket will wakeup the
306           thread on  the next frame again
307        */
308        m_pCurrentFramePixels = NULL;
309     }
310 }
311