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