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