Move the sources to trunk
[opencv] / otherlibs / cvcam / src / unix / cvvideo.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include <glob.h>
43 #include <stdio.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <fcntl.h>
47 #include <assert.h>
48 #include <sys/ioctl.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <sys/mman.h>
52 #include <malloc.h>
53 #include <errno.h>
54 #include <pthread.h>
55 #include "dialogs.h"
56
57
58 #include "cvcam.h"
59 #include "cvvidtypes.h"
60 #include "videodev.h"
61 #include "icvvideo.h"
62 #include "render.h"
63
64 //#define DEBUG_CVCAM 1
65 //#define DEBUG_THREADS 1
66
67 #ifdef DEBUG_THREADS
68 #define pthread_mutex_lock(x) printf("locking mutex "#x" from thread %p\n",pthread_self()),pthread_mutex_lock(x)
69 #define pthread_mutex_unlock(x) printf("unlocking mutex "#x" from thread %p\n",pthread_self()),pthread_mutex_unlock(x)
70 #define pthread_rwlock_rdlock(x) printf("rdlocking rwlock "#x" from thread %p\n",pthread_self()),pthread_rwlock_rdlock(x)
71 #define pthread_rwlock_wrlock(x) printf("wrlocking rwlock "#x" from thread %p\n",pthread_self()),pthread_rwlock_wrlock(x)
72 #define pthread_rwlock_unlock(x) printf("unlocking rwlock "#x" from thread %p\n",pthread_self()),pthread_rwlock_unlock(x)
73 #define pthread_create(a,b,c,d) printf("starting new thread from thread %p\n",pthread_self()),pthread_create(a,b,c,d)
74 #endif
75
76 const int FRAMES_FORMAT=0;
77 const int TIME_FORMAT = 1;
78
79 CvVideoCamera* cameras = NULL;
80 static int ncameras = 0;
81
82 static void icvVideoPicture2ImageBuffer(int camera);
83 static IplImage * icvVideoGetImage(int cameraid);
84
85 /* Returns the actual number of currently available cameras */
86 int cvcamGetCamerasCount()
87 {
88     glob_t               pglob;
89     int                     count, count1;
90     int                     CamerasCount =  0;
91     int*                    descriptors;
92     
93     struct video_capability VidCap;
94     struct video_channel    Channel;
95     
96 #ifdef DEBUG_CVCAM
97     printf("cvcamGetCamerasCount(), ncameras=%d\n",ncameras);
98 #endif
99     if(ncameras)
100         return ncameras;
101     
102     if(glob("/dev/video*",GLOB_MARK,NULL, &pglob))
103     {
104         fprintf(stderr, "cvcamGetCamerasCount:no video devices /dev/video(n)"
105                         "found\n");
106         return 0;
107     }
108
109     descriptors = (int*)malloc(pglob.gl_pathc*sizeof(int));
110     
111     for(count = 0; count < pglob.gl_pathc; count++)
112     {
113         descriptors[count] = open(pglob.gl_pathv[count],O_RDWR);
114         if (descriptors[count]  != -1 )
115         {
116             if(ioctl(descriptors[count], VIDIOCGCAP, &VidCap)==-1)
117             {
118                 close(descriptors[count]);
119                 break;
120             }
121             
122             for(count1=0; count1<VidCap.channels; count1++)
123                 
124             {
125                 Channel.channel = count1;
126                 
127                 if((ioctl(descriptors[count], VIDIOCGCHAN, &Channel) != -1))
128                 {
129                     
130                     Channel.norm = 1;
131                     Channel.channel = count1;
132                     
133                     if((ioctl(descriptors[count],VIDIOCSCHAN, &Channel) != -1)&&
134                         (ioctl(descriptors[count], VIDIOCGCAP, &VidCap)    != -1))
135                     {
136                         if(Channel.type&VIDEO_TYPE_CAMERA)
137                         {
138                             
139                             cameras =
140                                 (CvVideoCamera*)realloc(cameras,
141                                 (CamerasCount+1)*sizeof(CvVideoCamera));
142                             if(!icvVideoSetDefaultValues(CamerasCount, 
143                                 descriptors[count],
144                                 count1, VidCap))
145                             {
146                                 printf("icvVideoSetDefaultValues failed for camera %d, channel %d\n",count,count1);
147                                 break; 
148                             }
149                             
150                             strcpy(cameras[CamerasCount].description.device,
151                                 pglob.gl_pathv[count]);
152                             
153                             strcpy(cameras[CamerasCount].description.DeviceDescription,
154                                 VidCap.name);
155                             
156                             strcpy(cameras[CamerasCount].description.ChannelDescription,
157                                 Channel.name);
158                             
159                             CamerasCount++;
160                             break;
161                             
162                         }//if(Channel.type&VIDEO_TYPE_CAMERA)
163                     }//if((ioctl(descriptors[count],VIDIOCSCHAN, &Channel) != -1)&&
164                     //(ioctl(descriptors[count], VIDIOCGCAP, &VidCap)!=-1))
165                 }//if(ioctl(fd, VIDIOCSCHAN, &Channel) != -1)
166             }//for(count1=0; count1<VidCap.channels; count1++)
167             if(count1 == VidCap.channels) // no valid channel found
168             {
169                 printf("closing  descriptors[%d]=%d\n",count,descriptors[count]);
170                 close(descriptors[count]);
171             }
172         }//if (descriptors[count] = open(pglob.gl_pathv[count],O_RDWR)  != -1 )
173     }//for (count = 0; count < pglob.gl_pathc; count++)
174     globfree(&pglob);
175     free(descriptors);
176     ncameras = CamerasCount;
177     XInitThreads();
178 #ifdef DEBUG_CVCAM
179     printf("cvcamGetCamerasCount() found %d cameras\n",ncameras);
180 #endif
181     return CamerasCount;
182 }
183 ///////////////////////////////////////////////////////////////////////////////
184 /* get/set the property of the camera. returns 0 if the property is not supported */
185 int cvcamGetProperty(int cameraid, const char* property, void* value)
186 {
187     CvVideoCamera *const camera = &(cameras[cameraid]);
188
189 #ifdef DEBUG_CVCAM
190     printf("cvcamGetProperty(camera=%d,property=%s)\n",cameraid, property);
191 #endif
192     if(!cameras||cameraid>ncameras-1||cameraid<0)
193     {
194         fprintf(stderr,"cvcamGetProperty:no such camera\n");
195         return 0;
196     }//if(!cameras||camera>ncameras-1||camera<0)
197
198     IF_GETTING_PROPERTY("description")
199     {
200         strcpy(((CameraDescription*)value)->DeviceDescription,camera->description.DeviceDescription);
201         strcpy(((CameraDescription*)value)->device, camera->description.device);
202         strcpy(((CameraDescription*)value)->ChannelDescription,camera->description.ChannelDescription);
203         
204         ((CameraDescription*)value)->channel = camera->description.channel;
205         
206         ((CameraDescription*)value)->maxwidth = camera->description.maxwidth;
207         ((CameraDescription*)value)->maxheight = camera->description.maxheight;
208         ((CameraDescription*)value)->minwidth = camera->description.minwidth;
209         ((CameraDescription*)value)->minheight = camera->description.minheight;
210         
211         return 1;
212     }//IF_GETTING_PROPERTY("description")
213     
214     IF_GETTING_PROPERTY("enable")
215     {
216         *(int*)value = camera->enabled;
217         return 1;
218     }//IF_GETTING_PROPERTY("enable")
219     
220     IF_GETTING_PROPERTY("render")
221     {
222         *(int*)value = camera->rendered;
223         //TODO: real call to rendering ioctl(if after initialisation)
224         
225         return 1;
226     }//IF_GETTING_PROPERTY("render")
227     
228     IF_GETTING_PROPERTY("window")
229     {
230         *(Window*)value = camera->window;
231         return 1;
232     }//IF_GETTING_PROPERTY("window")
233     
234     IF_GETTING_PROPERTY("callback")
235     {
236         fprintf(stdout,"The property \"callback\" is set-only\n");
237         return 0;
238     }//IF_GETTING_PROPERTY("callback")
239     
240     IF_GETTING_PROPERTY("camera_pp")
241     {
242         icvVideoCameraPPDialog(cameraid);
243         return 1;
244     }//IF_GETTING_PROPERTY("camera_pp")
245     
246     IF_GETTING_PROPERTY("set_video_format")
247     {
248         /*
249         if(!camera->initialised)
250         {
251         fprintf(stderr, "cvcamGetProperty, property = video_pp, camera\
252         isn't initialised");
253         return 0;
254         }
255         */
256         ((VideoFormat*)value)->width = camera->videopp.width;
257         ((VideoFormat*)value)->height = camera->videopp.height;
258         
259         ((VideoFormat*)value)->picture.brightness =
260             camera->videopp.picture.brightness;
261         
262         ((VideoFormat*)value)->picture.hue =
263             camera->videopp.picture.hue;
264         
265         ((VideoFormat*)value)->picture.colour =
266             camera->videopp.picture.colour;
267         
268         ((VideoFormat*)value)->picture.contrast =
269             camera->videopp.picture.contrast;
270         
271         ((VideoFormat*)value)->picture.whiteness   =
272             camera->videopp.picture.whiteness;
273         
274         ((VideoFormat*)value)->picture.depth =
275             camera->videopp.picture.depth;
276         
277         ((VideoFormat*)value)->picture.palette =
278             camera->videopp.picture.palette;
279         
280         return 1;
281     }//IF_GETTING_PROPERTY("set_video_format")
282     
283     IF_GETTING_PROPERTY("rectify_parameters")
284     {
285         fprintf(stdout,"TODO get prop rectify_parameters\n");
286         return 1;
287     }//IF_GETTING_PROPERTY("rectify_parameters")
288     
289     IF_GETTING_PROPERTY("stereo_parameters")
290     {
291         fprintf(stdout,"TODO get prop stereo_parameters\n");
292         return 1;
293     }//IF_GETTING_PROPERTY("stereo_parameters")
294     
295     IF_GETTING_PROPERTY("raw_image")
296     {
297         *((IplImage**)value) = icvVideoGetImage(cameraid);
298         if(*((IplImage**)value) != NULL)
299             return 1;
300         else
301             return 0;
302     }//IF_GETTING_PROPERTY("raw_image")
303     
304     IF_GETTING_PROPERTY("disparity")
305     {
306         fprintf(stdout,"TODO get prop disparity\n");
307         return 1;
308     }//IF_GETTING_PROPERTY("disparity")
309     
310     IF_GETTING_PROPERTY("stereo_image")
311     {
312         fprintf(stdout,"TODO get prop stereo_image\n");
313         return 1;
314     }//IF_GETTING_PROPERTY("stereo_image")
315     
316     IF_GETTING_PROPERTY("video_pp")
317     {
318         icvVideoVideoPPDialog(cameraid);
319         return 1;
320     }//IF_GETTING_PROPERTY("video_pp")
321
322     IF_GETTING_PROPERTY(CVCAM_RNDWIDTH)
323     {
324         *(int*)value = camera->renderwidth;
325         return 1;
326     }//IF_GETTING_PROPERTY (CVCAM_RNDWIDTH)
327
328     IF_GETTING_PROPERTY(CVCAM_RNDHEIGHT)
329     {
330      *(int*)value = camera->renderheight;
331         return 1;
332     }//IF_GETTING_PROPERTY("CVCAM_RNDHEIGHT")
333
334
335     return 0;
336 }
337 //////////////////////////////////////////////////////////////////////////////////////////////////////////
338
339
340 /* gets all property names. the actual number of properties is returned. */
341 int cvcamGetPropertiesList(int camera, const char** properties, int count)
342 {
343 #ifdef DEBUG_CVCAM
344     printf("cvcamGetPropertiesList()\n");
345 #endif
346     assert(properties);
347     
348     properties[0] = "description" ;
349     properties[1] = "enable";
350     properties[2] = "render";
351     properties[3] = "window";
352     properties[4] = "callback";
353     properties[5] = "camera_pp";
354     properties[6] = "video_pp" ;
355     properties[7] = "raw_image";
356     properties[8] = "set_video_format" ;
357     
358     return 9;
359 }
360 ///////////////////////////////////////////////////////////////////////////////////////////////////////////
361
362
363 int cvcamSetProperty(int cameraid, const char* property, void* value)
364 {
365     int k;
366     CvVideoCamera *const camera = &(cameras[cameraid]);
367     
368 #ifdef DEBUG_CVCAM
369     printf("cvcamSetProperty(camera=%d,property=%s)\n",cameraid, property);
370 #endif
371     if(!cameras||cameraid>ncameras-1||cameraid<0)
372     {
373         fprintf(stderr,"cvcamSetProperty: no such camera\n");
374         return 0;
375     }//if(!cameras||camera>ncameras-1)
376     
377     IF_SETTING_PROPERTY("description")
378     {
379         fprintf(stdout, "cvcamSetProperty: The property \"description\" cannot be "
380                         "set\n");
381         return 0;
382     }//IF_SETTING_PROPERTY("description")
383     
384     IF_SETTING_PROPERTY("enable")
385     {
386         camera->enabled = (int)value;
387         return 1;
388     }//IF_SETTING_PROPERTY("enable")
389     
390     IF_SETTING_PROPERTY("render")
391     {
392         camera->rendered = (int)value;
393         return 1;
394     }//IF_SETTING_PROPERTY("render")
395     
396     IF_SETTING_PROPERTY("window")
397     {
398         camera->window = *(Window*)value;
399         
400         //fprintf(stdout,"TODO get prop window\n");
401         return 1;
402     }//IF_SETTING_PROPERTY("window")
403     
404     IF_SETTING_PROPERTY("callback")
405     {
406         camera->callback = ( void (*)(IplImage*) )value;
407         return 1;
408     }//IF_SETTING_PROPERTY("callback")
409
410     IF_SETTING_PROPERTY("camera_pp")
411     {
412         fprintf(stdout,"TODO get prop camera_pp\n");
413         return 1;
414     }//IF_SETTING_PROPERTY("camera_pp")
415     
416     IF_SETTING_PROPERTY("description")
417     {
418         fprintf(stdout,"TODO get prop camera_pp\n");
419         return 1;
420     }//IF_SETTING_PROPERTY("camera_pp")
421     
422     IF_SETTING_PROPERTY("set_video_format")
423     {
424         k = icvVideoStop(cameraid);
425         if(
426             (((VideoFormat*)value)->picture.brightness>0xffff)||
427             (((VideoFormat*)value)->picture.hue>0xffff)||
428             (((VideoFormat*)value)->picture.colour>0xffff)||
429             (((VideoFormat*)value)->picture.contrast>0xffff)||
430             (((VideoFormat*)value)->picture.whiteness>0xffff)||
431             (((VideoFormat*)value)->width > camera->description.maxwidth)||
432             (((VideoFormat*)value)->height > camera->description.maxheight)||
433             (((VideoFormat*)value)->width < camera->description.minwidth)||
434             (((VideoFormat*)value)->height < camera->description.minheight)
435             )
436         {
437 #ifdef DEBUG_CVCAM
438             printf("cvcamSetProperty(camera=%d,property=%s): values out of bounds\n",cameraid, property);
439 #endif
440             if(k)
441                 icvVideoStart(cameraid);
442             return 0;
443         }
444         
445         if(
446             ((((VideoFormat*)value)->width == camera->description.maxwidth)&&
447             (((VideoFormat*)value)->height == camera->description.maxheight))||
448             ((((VideoFormat*)value)->width == camera->description.minwidth)&&
449             (((VideoFormat*)value)->height == camera->description.minheight))||
450             ((((VideoFormat*)value)->width == 320)&&                
451             (((VideoFormat*)value)->height == 240))
452             )
453         {
454             camera->videopp.width = ((VideoFormat*)value)->width;
455             camera->videopp.height= ((VideoFormat*)value)->height;
456         }
457         else
458         {
459             if(
460                 ((((VideoFormat*)value)->width > 320)&&
461                 ((VideoFormat*)value)->height > 240)
462                 )
463             {
464                 camera->videopp.width = 320;
465                 camera->videopp.height= 240;
466             }else
467             {
468                 camera->videopp.width=
469                     camera->description.minwidth;
470                 
471                 camera->videopp.height=
472                     camera->description.minheight;
473             }
474         }
475         
476         camera->videopp.picture.brightness=
477             ((VideoFormat*)value)->picture.brightness;
478         
479         camera->videopp.picture.hue=
480             ((VideoFormat*)value)->picture.hue;
481         
482         camera->videopp.picture.colour=
483             ((VideoFormat*)value)->picture.colour;
484         
485         camera->videopp.picture.contrast=
486             ((VideoFormat*)value)->picture.contrast ;
487         
488         camera->videopp.picture.whiteness=
489             ((VideoFormat*)value)->picture.whiteness;
490         
491         camera->videopp.picture.palette=
492             ((VideoFormat*)value)->picture.palette;
493         if(camera->videopp.picture.palette == VIDEO_PALETTE_YUV420P)
494             camera->imagepalette = VIDEO_PALETTE_RGB24;
495
496         camera->videopp.picture.depth = icvVideoFormat2Depth(camera->imagepalette);
497         
498         if(!camera->videopp.picture.depth)
499             return 0;
500
501
502         //cvcamInit();
503
504         if(k)
505             icvVideoStart(cameraid);
506         //fprintf(stdout,"TODO get prop video_pp\n");
507         return 1;
508     }//IF_SETTING_PROPERTY("set_video_format")
509     
510     IF_SETTING_PROPERTY("rectify_parameters")
511     {
512         fprintf(stdout,"TODO get prop rectify_parameters\n");
513         return 1;
514     }//IF_SETTING_PROPERTY("rectify_parameters")
515     
516     IF_SETTING_PROPERTY("stereo_parameters")
517     {
518         fprintf(stdout,"TODO get prop stereo_parameters\n");
519         return 1;
520     }//IF_SETTING_PROPERTY("stereo_parameters")
521     
522     IF_SETTING_PROPERTY("raw_image")
523     {
524         fprintf(stdout,"TODO get prop raw_image\n");
525         return 1;
526     }//IF_SETTING_PROPERTY("raw_image")
527     
528     IF_SETTING_PROPERTY("disparity")
529     {
530         fprintf(stdout,"TODO get prop disparity\n");
531         return 1;
532     }//IF_SETTING_PROPERTY("disparity")
533     
534     IF_SETTING_PROPERTY("stereo_image")
535     {
536         fprintf(stdout,"TODO get prop stereo_image\n");
537         return 1;
538     }//IF_SETTING_PROPERTY("stereo_image")
539
540     IF_SETTING_PROPERTY("video_pp")
541     {
542         fprintf(stdout,"TODO get prop set_video_format\n");
543         return 1;
544     }//IF_SETTING_PROPERTY( "video_pp" )
545
546
547     IF_SETTING_PROPERTY(CVCAM_RNDWIDTH)
548     {
549         k=icvVideoStop(cameraid);
550         camera->renderwidth = *(int*)value;
551         if(k)
552             icvVideoStart(cameraid);
553         return 1;
554
555     }//IF_SETTING_PROPERTY(CVCAM_RNDWIDTH)
556
557     IF_SETTING_PROPERTY(CVCAM_RNDHEIGHT)
558     {
559         k=icvVideoStop(cameraid);
560         camera->renderheight = *(int*)value;
561         if(k)
562             icvVideoStart(cameraid);
563         return 1;
564
565     }//IF_SETTING_PROPERTY(CVCAM_RNDHEIGHT)
566
567     return 0;
568 }
569 ///////////////////////////////////////////////////////////////////////////////
570
571 /* Prepares the currently enabled cameras for work */
572 int cvcamInit()
573 {
574     int camera;
575 #ifdef DEBUG_CVCAM
576     printf("cvcamInit()\n");
577 #endif
578     for(camera=0; camera<ncameras; camera++)
579     {
580         icvVideoInit(camera);
581     }//for(camera=0; camera<ncameras; camera++)
582
583     return 1;
584 }
585
586 ///////////////////////////////////////////////////////////////////////////////
587 /* Start the video */
588 int cvcamStart()
589 {
590     int cameraid;
591     
592 #ifdef DEBUG_CVCAM
593     printf("cvcamStart()\n");
594 #endif
595     for(cameraid=0; cameraid<ncameras; cameraid++)
596     {
597         if(cameras[cameraid].enabled)
598         {
599             if(!icvVideoStart(cameraid))
600             {
601                 return 0;
602             }
603         }
604     }//for(cameraid=0; cameraid<ncameras; cameraid++)
605
606     return 1;
607 }
608
609 int icvVideoStart(int cameraid)
610 {
611     CvVideoCamera *const camera = &(cameras[cameraid]);
612     int frame;
613
614     pthread_mutex_lock(&(camera->capturestatemutex));
615     if(camera->capturestate != READY)
616     {
617         fprintf(stderr,"icvVideoStart: camera %d not ready\n",camera);
618         pthread_mutex_unlock(&(camera->capturestatemutex));
619         return 0;
620     }
621     camera->capturestate = STARTING;
622     pthread_cond_signal(&(camera->capturestatecond));
623     pthread_mutex_unlock(&(camera->capturestatemutex));
624
625     pthread_mutex_lock(&(camera->ioctlmutex));
626     if(ioctl(camera->device, VIDIOCGMBUF,
627              &(camera->mbuf)) == -1)
628     {
629         pthread_mutex_unlock(&(camera->ioctlmutex));
630         return 0;
631     }
632     pthread_mutex_unlock(&(camera->ioctlmutex));
633 #ifdef DEBUG_CVCAM
634     printf("mbuf: size=%d, frames=%d, offsets=",camera->mbuf.size,
635            camera->mbuf.frames);
636 #endif
637     camera->memorymap = (char*)mmap(0,
638                     camera->mbuf.size,
639                     PROT_READ|PROT_WRITE, MAP_SHARED,
640                     camera->device,
641                     0);
642         
643     if((int)camera->memorymap == -1)
644         {
645         fprintf(stderr, "icvVideoStart: mmap failed");
646         return 0;
647     }
648
649     // acquire first frame
650     camera->vid_mmap.frame  = 0;
651     camera->vid_mmap.width  = camera->videopp.width;
652     camera->vid_mmap.height = camera->videopp.height;
653     camera->vid_mmap.format = camera->videopp.picture.palette;
654     camera->lastframe = 0;
655
656     pthread_mutex_lock(&(camera->ioctlmutex));
657     
658     if(ioctl(camera->device, VIDIOCMCAPTURE, &(camera->vid_mmap)) < 0)
659     {
660         fprintf(stderr, "icvVideoInit: ioctl VIDIOCMCAPTURE failed \n");
661         return 0;
662     }
663     if(ioctl(camera->device, VIDIOCSYNC, &(camera->vid_mmap.frame) ) < 0)
664     {
665         fprintf(stderr, "icvVideoInit: ioctl VIDIOCSYNC failed \n");
666         return 0;
667     }//if ioctl(..., VIDIOCSYNK, ...)
668     pthread_mutex_unlock(&(camera->ioctlmutex));
669         
670     assert(camera->videopp.picture.palette);
671     assert(icvVideoFormat2Depth(camera->imagepalette));
672     
673     pthread_mutex_lock(&(camera->capturestatemutex));
674     camera->capturestate = CAPTURING;
675     pthread_cond_signal(&(camera->capturestatecond));
676     pthread_mutex_unlock(&(camera->capturestatemutex));
677
678     // initialize frame locks.
679     pthread_mutex_init(&(camera->lastframemutex), NULL);
680     camera->framelock = (pthread_rwlock_t *)malloc(camera->mbuf.frames *
681                                                    sizeof(pthread_rwlock_t));
682     for(frame = 0; frame < camera->mbuf.frames; frame++)
683     {
684         pthread_rwlock_init(&(camera->framelock[frame]),NULL);
685     }
686
687     camera->updated = 1;
688
689     // start capture thread
690     if(pthread_create((&(camera->thread)),NULL,
691                       icvVideoCaptureProc, (void*)cameraid))
692     {
693         fprintf(stderr, "icvVideoStart: couldn't start thread for "
694                 "camera %d\n", camera);
695         return 0;
696     }//if pthread_create ...
697 #ifdef DEBUG_THREADS
698     printf("started icvVideoCaptureProc thread %p from thread %p\n",
699            camera->thread, pthread_self());
700 #endif
701     
702     if(camera->rendered)
703     {
704 #ifdef DEBUG_CVCAM
705         printf("icvVideoStart: start rendering\n");
706 #endif
707         icvVideoRenderStart(cameraid);
708     }
709     return 1;
710 }
711
712
713 ////////////////////////////////////////////////////////////////////////////////
714 void* icvVideoCaptureProc(void* arg)
715 {
716     int cameraid = (int) arg;
717     CvVideoCamera* const camera = &(cameras[cameraid]);
718     
719     assert(cameras != NULL);
720     assert(cameraid>=0 && cameraid <ncameras);
721     assert(camera->mbuf.frames>0);
722     pthread_mutex_lock(&(camera->capturestatemutex));
723     while(camera->capturestate == CAPTURING)
724     {
725         pthread_mutex_unlock(&(camera->capturestatemutex));
726 #ifdef DEBUG_CVCAM
727         printf("*");
728         fflush(stdout);
729 #endif
730         // I don't need to rdlock lastframe, since I'm the one who writes it
731         //pthread_mutex_lock(&(camera->lastframemutex));
732         camera->vid_mmap.frame  = (camera->lastframe + 1)%camera->mbuf.frames;
733         //pthread_mutex_unlock(&(camera->lastframemutex));
734
735         pthread_rwlock_wrlock(&(camera->framelock[camera->vid_mmap.frame]));
736         pthread_mutex_lock(&(camera->ioctlmutex));
737         if(ioctl(camera->device, VIDIOCMCAPTURE, &(camera->vid_mmap)) < 0)
738         {
739             fprintf(stderr, "icvVideoCaptureProc: ioctl VIDIOCMCAPTURE failed \n");
740             pthread_mutex_lock(&(camera->capturestatemutex));
741             camera->capturestate = FINISHED;
742             pthread_cond_signal(&(camera->capturestatecond));
743             pthread_mutex_unlock(&(camera->capturestatemutex));
744         }
745         if(ioctl(camera->device, VIDIOCSYNC, &(camera->vid_mmap.frame) ) < 0)
746         {
747             fprintf(stderr, "icvVideoCaptureProc: ioctl VIDIOCSYNC failed \n");
748             pthread_mutex_lock(&(camera->capturestatemutex));
749             camera->capturestate = FINISHED;
750             pthread_cond_signal(&(camera->capturestatecond));
751             pthread_mutex_unlock(&(camera->capturestatemutex));
752         }//if ioctl(..., VIDIOCSYNK, ...)
753         pthread_mutex_unlock(&(camera->ioctlmutex));
754         pthread_rwlock_unlock(&(camera->framelock[camera->vid_mmap.frame]));
755         pthread_mutex_lock(&(camera->lastframemutex));
756         camera->lastframe = camera->vid_mmap.frame;
757         pthread_mutex_unlock(&(camera->lastframemutex));
758         // if the camera is not rendered, call the callback myself
759         if (!camera->rendered && (camera->callback != NULL))
760         {
761             IplImage *image = icvVideoGetImage(cameraid);
762             if(image != NULL) {
763                 camera->callback(image);
764                 cvReleaseImage(&image);
765             } else {
766                 fprintf(stderr, "icvVideoCaptureProc: icvVideoGetImage() returned NULL\n");
767             }
768         }
769         // signal that the rendering should be updated, since the image changed
770         if (camera->rendered)
771         {
772             pthread_mutex_lock(&(camera->updatedmutex));
773             if(camera->updated == 0)
774             {
775                 pthread_cond_signal(&(camera->updatedcond));
776                 camera->updated = 1;
777             }
778             pthread_mutex_unlock(&(camera->updatedmutex));
779         }
780         // stop here if we're paused
781         pthread_mutex_lock(&(camera->pausemutex));
782         pthread_mutex_unlock(&(camera->pausemutex));
783         pthread_mutex_lock(&(camera->capturestatemutex));
784     }
785     pthread_mutex_unlock(&(camera->capturestatemutex));
786     pthread_mutex_lock(&(camera->capturestatemutex));
787     camera->capturestate = FINISHED;
788     pthread_cond_signal(&(camera->capturestatecond));
789     pthread_mutex_unlock(&(camera->capturestatemutex));
790     pthread_exit(NULL);
791 }
792 ////////////////////////////////////////////////////////////////////////////////
793
794 /* Frees all resources */
795 int cvcamExit()
796 {
797     int cameraid, frame;
798
799 #ifdef DEBUG_CVCAM
800     printf("cvcamExit(), ncameras = %d\n",ncameras);
801 #endif
802     cvcamStop();
803     for(cameraid=0; cameraid<ncameras; cameraid++) {
804         CvVideoCamera *const camera = &(cameras[cameraid]);
805         close(camera->device);
806         pthread_mutex_destroy(&(camera->ioctlmutex));
807         pthread_mutex_destroy(&(camera->pausemutex));
808         pthread_mutex_destroy(&(camera->capturestatemutex));
809         pthread_cond_destroy(&(camera->capturestatecond));
810         for(frame=0; frame< camera->mbuf.frames; frame++)
811         {
812             pthread_rwlock_destroy(&(camera->framelock[frame]));
813         }
814         free(camera->framelock);
815         pthread_mutex_destroy(&(camera->lastframemutex));
816         pthread_cond_destroy(&(camera->updatedcond));
817         pthread_mutex_destroy(&(camera->updatedmutex));
818         camera->initialised = 0;
819     }
820     free(cameras);
821     cameras = NULL;
822     ncameras = 0;
823     return 1;
824 }
825
826 ////////////////////////////////////////////////////////////////////////////////
827
828 int icvVideoPauseCamera(int cameraid)
829 {
830     CvVideoCamera *const camera = &(cameras[cameraid]);
831
832     pthread_mutex_lock(&(camera->capturestatemutex));
833     if(!(camera->capturestate==CAPTURING))
834     {
835         pthread_mutex_unlock(&(camera->capturestatemutex));
836         return 1;
837     }
838     pthread_mutex_unlock(&(camera->capturestatemutex));
839     // taking this lock will stop grabbing
840     if(!camera->paused) {
841         pthread_mutex_lock(&(camera->pausemutex));
842         camera->paused = 1;
843     }
844     return 0;
845 }
846 ////////////////////////////////////////////////////////////////////////////////
847
848 int icvVideoResumeCamera(int cameraid)
849 {
850     CvVideoCamera *const camera = &(cameras[cameraid]);
851
852     pthread_mutex_lock(&(camera->capturestatemutex));
853     if(!(camera->capturestate==CAPTURING))
854     {
855         pthread_mutex_unlock(&(camera->capturestatemutex));
856         return 1;
857     }
858     pthread_mutex_unlock(&(camera->capturestatemutex));
859     if(camera->paused) {
860         camera->paused = 0;
861         pthread_mutex_unlock(&(camera->pausemutex));
862     }
863     return 0;
864 }
865 ////////////////////////////////////////////////////////////////////////////////
866
867 /* Pause the video; should be used for preventing data changes during frame reading 
868         using "frame" and other properties */
869 int cvcamPause()
870 {
871     int i;
872     
873 #ifdef DEBUG_CVCAM
874     printf("cvcamPause()\n");
875 #endif
876     for(i=0; i<ncameras; i++)
877     {
878         icvVideoPauseCamera(i);
879     }
880     
881     
882     return 0;
883
884 }
885 ////////////////////////////////////////////////////////////////////////////////
886
887 /* Resume the video */
888 int cvcamResume()
889 {
890     int i;
891     
892 #ifdef DEBUG_CVCAM
893     printf("cvcamResume()\n");
894 #endif
895     for(i=0; i<ncameras; i++)
896     {
897         icvVideoResumeCamera(i);
898     }
899     
900     return 0;
901     
902 }
903 ////////////////////////////////////////////////////////////////////////////////
904
905 int icvVideoInit(int cameraid)
906 {
907     struct video_channel Channel;
908     struct video_capability VidCap;
909     CvVideoCamera *const camera = &(cameras[cameraid]);
910
911 #ifdef DEBUG_CVCAM
912     printf("icvVideoInit(%d)\n",cameraid);
913 #endif
914     char *rgbframe;
915
916     if(camera->initialised)
917     {
918     /*
919     fprintf(stderr, "icvVideoInit:camera %d is already "
920                         "initialized\n",camera);*/
921         return 0;
922     }
923     
924     if(camera->enabled)
925     {
926         pthread_mutex_lock(&(camera->ioctlmutex));
927         if(ioctl(camera->device,VIDIOCSPICT,
928             &(camera->videopp.picture) )==-1)
929         {
930             pthread_mutex_unlock(&(camera->ioctlmutex));
931             fprintf(stdout, "icvVideoInit: ioctl VIDIOCSPICT failed\n");
932             fprintf(stdout,"camera=%d,brightness=%d,hue=%d,colour=%d,contrast=%d,whiteness=%d,depth=%d,palette=%d\n",
933                     camera,
934                     camera->videopp.picture.brightness,
935                     camera->videopp.picture.hue,
936                     camera->videopp.picture.colour,
937                     camera->videopp.picture.contrast,camera->videopp.picture.whiteness,camera->videopp.picture.depth,camera->videopp.picture.palette);
938             return 0;
939         }
940         pthread_mutex_unlock(&(camera->ioctlmutex));
941         
942         Channel.norm = 1;
943         Channel.channel = camera->channel;
944         pthread_mutex_lock(&(camera->ioctlmutex));
945         if((ioctl(camera->device,VIDIOCSCHAN, &Channel) == -1)||
946             (ioctl(camera->device, VIDIOCGCAP, &VidCap)==-1))
947         {
948             fprintf(stderr,
949                 "icvVideoInit: ioctl VIDIOCSCHAN or VIDIOCGCAP failed\n");
950             pthread_mutex_unlock(&(camera->ioctlmutex));
951             return 0;
952         }
953         pthread_mutex_unlock(&(camera->ioctlmutex));
954         
955         pthread_mutex_lock(&(camera->ioctlmutex));
956         if(ioctl(camera->device, VIDIOCGMBUF,
957             &(camera->mbuf)) == -1)
958         {
959             pthread_mutex_unlock(&(camera->ioctlmutex));
960             fprintf(stdout, "icvVideoInit: ioctl VIDIOCGMBUF failed\n");
961             return 0;
962         }
963         pthread_mutex_unlock(&(camera->ioctlmutex));
964         
965         pthread_mutex_lock(&(camera->ioctlmutex));
966         if(ioctl(camera->device,
967             VIDIOCSCHAN, &Channel)==-1)
968         {
969             fprintf(stderr, "icvVideoInit: couldn't set channel %d",
970                 Channel.channel);
971             pthread_mutex_unlock(&(camera->ioctlmutex));
972             return 0;
973         }
974         pthread_mutex_unlock(&(camera->ioctlmutex));
975         
976         camera->initialised = 1;
977         pthread_mutex_lock(&(camera->capturestatemutex));
978         camera->capturestate = READY;
979         pthread_cond_signal(&(camera->capturestatecond));
980         pthread_mutex_unlock(&(camera->capturestatemutex));
981         
982    }//if(camera->IsEnabled)
983    return 1;
984 }
985 ////////////////////////////////////////////////////////////
986
987 int icvVideoStop(int cameraid)
988 {
989     int i, frame;
990     CvVideoCamera *const camera = &(cameras[cameraid]);
991
992 #ifdef DEBUG_CVCAM
993     printf("icvVideoStop(%d)\n",cameraid);
994 #endif
995     pthread_mutex_lock(&(camera->capturestatemutex));
996     if(camera->capturestate != CAPTURING)
997     {
998 #ifdef DEBUG_CVCAM
999         printf("icvVideoStop: not capturing (state=%d), returning 0\n",camera->capturestate);
1000 #endif
1001         pthread_mutex_unlock(&(camera->capturestatemutex));
1002         return 0;
1003     }
1004     camera->capturestate = STOPPING;
1005     pthread_cond_signal(&(camera->capturestatecond));
1006     pthread_mutex_unlock(&(camera->capturestatemutex));
1007     if(camera->paused)
1008         icvVideoResumeCamera(cameraid);
1009
1010     pthread_mutex_lock(&(camera->capturestatemutex));
1011     // wait for the end of capture proc
1012     while (camera->capturestate != FINISHED )
1013     {
1014         pthread_cond_wait(&(camera->capturestatecond),&(camera->capturestatemutex));
1015     }
1016     // wait for the end of rendering
1017     while (camera->renderstate)
1018     {
1019         // the rendering loop may be waiting for an update
1020         pthread_mutex_lock(&(camera->updatedmutex));
1021         camera->updated = 1;
1022         pthread_cond_signal(&(camera->updatedcond));
1023         pthread_mutex_unlock(&(camera->updatedmutex));
1024         pthread_cond_wait(&(camera->capturestatecond),&(camera->capturestatemutex));
1025     }
1026     pthread_mutex_unlock(&(camera->capturestatemutex));
1027
1028     munmap(camera->memorymap,
1029         camera->mbuf.size);
1030     
1031     pthread_mutex_lock(&(camera->capturestatemutex));
1032     camera->capturestate = READY;
1033     pthread_cond_signal(&(camera->capturestatecond));
1034     pthread_mutex_unlock(&(camera->capturestatemutex));
1035 #ifdef DEBUG_CVCAM
1036         printf("icvVideoStop: returning 1\n",camera->capturestate);
1037 #endif
1038     return 1;
1039 }
1040 //////////////////////////////////////////////////////////////////
1041
1042 /* Stop the video */
1043 int cvcamStop()
1044 {
1045     int camera;
1046 #ifdef DEBUG_CVCAM
1047     printf("cvcamStop()\n");
1048 #endif
1049     for(camera=0; camera<ncameras; camera++)
1050     {
1051         icvVideoStop(camera);
1052     }//for(camera=0; camera<ncameras; camera++)
1053     return 1;
1054 }
1055 ////////////////////////////////////////////////////////////////////////////////
1056
1057 ////////////////////////////////////////////////////////////////////////////////
1058 int icvVideoFormat2Depth(int format)
1059 {
1060     switch (format)
1061     {
1062     case VIDEO_PALETTE_RGB24:
1063         return 24;
1064         
1065     case VIDEO_PALETTE_RGB32:
1066         return 32;
1067         
1068     case VIDEO_PALETTE_RGB565:
1069         return 16;
1070         
1071     case VIDEO_PALETTE_RGB555:
1072         return 16;
1073         
1074     default:
1075         return 0;
1076     }
1077 }
1078 ////////////////////////////////////////////////////////////////////////////////
1079 ////////////////////////////////////////////////////////////////////////////////
1080 int icvVideoSetDefaultValues(int cameraid, int device, int channel, 
1081      struct video_capability VidCap)
1082 {
1083     CvVideoCamera *const camera = &(cameras[cameraid]);
1084
1085     camera->device                = device;
1086     camera->channel               = channel;
1087     camera->description.channel   = channel;
1088     pthread_mutex_init(&(camera->ioctlmutex), NULL);
1089     camera->enabled               = 0;
1090     camera->rendered              = 0;
1091     camera->initialised           = 0;
1092     camera->paused                = 0;
1093     pthread_mutex_init(&(camera->pausemutex), NULL);
1094     pthread_mutex_init(&(camera->capturestatemutex), NULL);
1095     pthread_cond_init(&(camera->capturestatecond), NULL);
1096     camera->capturestate          = FINISHED;
1097     camera->memorymap             = NULL;
1098     camera->renderstate           = 0;
1099     pthread_mutex_init(&(camera->updatedmutex), NULL);
1100     pthread_cond_init(&(camera->updatedcond), NULL);
1101     camera->updated               = 0;
1102     camera->videopp.picture.palette = VIDEO_PALETTE_RGB24;
1103     camera->imagepalette = VIDEO_PALETTE_RGB24;
1104     
1105     camera->description.maxwidth    = VidCap.maxwidth;
1106     
1107     camera->description.maxheight   = VidCap.maxheight;
1108     
1109     camera->description.minwidth    = VidCap.minwidth;
1110
1111     if(camera->description.minwidth<160)
1112         camera->description.minwidth = 160;
1113     
1114     camera->description.minheight   = VidCap.minheight;
1115     
1116     if(camera->description.minheight<120)
1117         camera->description.minheight = 120;
1118     
1119     if(ioctl(device,VIDIOCGPICT,
1120         &(camera->videopp.picture) )==-1)
1121         return 0;   
1122     
1123     camera->videopp.picture.palette   = VIDEO_PALETTE_RGB24;
1124     camera->imagepalette = VIDEO_PALETTE_RGB24;
1125     camera->videopp.width             = camera->description.maxwidth;
1126     
1127     camera->videopp.height            = camera->description.maxheight;
1128     camera->videopp.picture.depth      = 24;
1129     camera->videopp.picture.brightness = 30000;
1130     camera->videopp.picture.hue        = 30000;
1131     camera->videopp.picture.colour     = 30000;
1132     camera->videopp.picture.contrast   = 30000;
1133     camera->videopp.picture.whiteness  = 30000;
1134     camera->callback                   = NULL;
1135
1136     camera->renderwidth                = 0;
1137     camera->renderheight               = 0;
1138     
1139     if(ioctl(device,VIDIOCSPICT,
1140         &(camera->videopp.picture) )==-1)
1141     {
1142 #ifdef DEBUG_CVCAM
1143         fprintf(stdout, "icvSetDefaultValues: ioctl VIDIOCSPICT failed, trying YUV420P format\n");
1144 #endif
1145         camera->videopp.picture.palette   = VIDEO_PALETTE_YUV420P;
1146         if(ioctl(device,VIDIOCSPICT,
1147                  &(camera->videopp.picture) )==-1)
1148         {
1149             fprintf(stdout, "icvSetDefaultValues: ioctl VIDIOCSPICT failed even in YUV420P format\n");
1150 #ifdef DEBUG_CVCAM
1151             fprintf(stdout,"camera=%d,brightness=%d,hue=%d,colour=%d,contrast=%d,whiteness=%d,depth=%d,palette=%d\n",
1152                     camera,
1153                     camera->videopp.picture.brightness,
1154                     camera->videopp.picture.hue,
1155                     camera->videopp.picture.colour,
1156                     camera->videopp.picture.contrast,
1157                     camera->videopp.picture.whiteness,
1158                     camera->videopp.picture.depth,
1159                     camera->videopp.picture.palette);
1160 #endif
1161             return 0;
1162         }
1163     }
1164 #ifdef DEBUG_CVCAM
1165     fprintf(stdout,"OK! camera=%d,brightness=%d,hue=%d,colour=%d,contrast=%d,whiteness=%d,depth=%d,palette=%d\n",
1166             camera,
1167                     camera->videopp.picture.brightness,
1168                     camera->videopp.picture.hue,
1169                     camera->videopp.picture.colour,
1170                     camera->videopp.picture.contrast,camera->videopp.picture.whiteness,camera->videopp.picture.depth,camera->videopp.picture.palette);
1171 #endif
1172     return 1;
1173 }
1174
1175 /**********************************************************************
1176  *
1177  * Color correction functions
1178  *
1179  **********************************************************************/
1180
1181 /*
1182  * Turn a YUV4:2:0 block into an RGB block
1183  *
1184  * Video4Linux seems to use the blue, green, red channel
1185  * order convention-- rgb[0] is blue, rgb[1] is green, rgb[2] is red.
1186  *
1187  * Color space conversion coefficients taken from the excellent
1188  * http://www.inforamp.net/~poynton/ColorFAQ.html
1189  * In his terminology, this is a CCIR 601.1 YCbCr -> RGB.
1190  * Y values are given for all 4 pixels, but the U (Pb)
1191  * and V (Pr) are assumed constant over the 2x2 block.
1192  *
1193  * To avoid floating point arithmetic, the color conversion
1194  * coefficients are scaled into 16.16 fixed-point integers.
1195  * They were determined as follows:
1196  *
1197  *      double brightness = 1.0;  (0->black; 1->full scale) 
1198  *      double saturation = 1.0;  (0->greyscale; 1->full color)
1199  *      double fixScale = brightness * 256 * 256;
1200  *      int rvScale = (int)(1.402 * saturation * fixScale);
1201  *      int guScale = (int)(-0.344136 * saturation * fixScale);
1202  *      int gvScale = (int)(-0.714136 * saturation * fixScale);
1203  *      int buScale = (int)(1.772 * saturation * fixScale);
1204  *      int yScale = (int)(fixScale);   
1205  */
1206
1207 /* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */
1208 #define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
1209
1210 static inline void
1211 move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, 
1212                int rowPixels, unsigned char * rgb, int bits)
1213 {
1214         const int rvScale = 91881;
1215         const int guScale = -22553;
1216         const int gvScale = -46801;
1217         const int buScale = 116129;
1218         const int yScale  = 65536;
1219         int r, g, b;
1220
1221         g = guScale * u + gvScale * v;
1222 //      if (force_rgb) {
1223 //              r = buScale * u;
1224 //              b = rvScale * v;
1225 //      } else {
1226                 r = rvScale * v;
1227                 b = buScale * u;
1228 //      }
1229
1230         yTL *= yScale; yTR *= yScale;
1231         yBL *= yScale; yBR *= yScale;
1232
1233         if (bits == 24) {
1234                 /* Write out top two pixels */
1235                 rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL);
1236                 rgb[2] = LIMIT(r+yTL);
1237
1238                 rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR);
1239                 rgb[5] = LIMIT(r+yTR);
1240
1241                 /* Skip down to next line to write out bottom two pixels */
1242                 rgb += 3 * rowPixels;
1243                 rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL);
1244                 rgb[2] = LIMIT(r+yBL);
1245
1246                 rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR);
1247                 rgb[5] = LIMIT(r+yBR);
1248         } else if (bits == 16) {
1249                 /* Write out top two pixels */
1250                 rgb[0] = ((LIMIT(b+yTL) >> 3) & 0x1F) 
1251                         | ((LIMIT(g+yTL) << 3) & 0xE0);
1252                 rgb[1] = ((LIMIT(g+yTL) >> 5) & 0x07)
1253                         | (LIMIT(r+yTL) & 0xF8);
1254
1255                 rgb[2] = ((LIMIT(b+yTR) >> 3) & 0x1F) 
1256                         | ((LIMIT(g+yTR) << 3) & 0xE0);
1257                 rgb[3] = ((LIMIT(g+yTR) >> 5) & 0x07) 
1258                         | (LIMIT(r+yTR) & 0xF8);
1259
1260                 /* Skip down to next line to write out bottom two pixels */
1261                 rgb += 2 * rowPixels;
1262
1263                 rgb[0] = ((LIMIT(b+yBL) >> 3) & 0x1F)
1264                         | ((LIMIT(g+yBL) << 3) & 0xE0);
1265                 rgb[1] = ((LIMIT(g+yBL) >> 5) & 0x07)
1266                         | (LIMIT(r+yBL) & 0xF8);
1267
1268                 rgb[2] = ((LIMIT(b+yBR) >> 3) & 0x1F)
1269                         | ((LIMIT(g+yBR) << 3) & 0xE0);
1270                 rgb[3] = ((LIMIT(g+yBR) >> 5) & 0x07)
1271                         | (LIMIT(r+yBR) & 0xF8);
1272         }
1273 }
1274
1275 /* Converts from planar YUV420 to RGB24. */
1276 static void 
1277 yuv420p_to_rgb(int width, int height,
1278                unsigned char *pIn0, unsigned char *pOut0, int bits)
1279 {
1280         const int numpix = width * height;
1281         const int bytes = bits >> 3;
1282         int i, j, y00, y01, y10, y11, u, v;
1283         unsigned char *pY = pIn0;
1284         unsigned char *pU = pY + numpix;
1285         unsigned char *pV = pU + numpix / 4;
1286         unsigned char *pOut = pOut0;
1287
1288         for (j = 0; j <= height - 2; j += 2) {
1289                 for (i = 0; i <= width - 2; i += 2) {
1290                         y00 = *pY;
1291                         y01 = *(pY + 1);
1292                         y10 = *(pY + width);
1293                         y11 = *(pY + width + 1);
1294                         u = (*pU++) - 128;
1295                         v = (*pV++) - 128;
1296
1297                         move_420_block(y00, y01, y10, y11, u, v,
1298                                        width, pOut, bits);
1299         
1300                         pY += 2;
1301                         pOut += 2 * bytes;
1302
1303                 }
1304                 pY += width;
1305                 pOut += width * bytes;
1306         }
1307 }
1308
1309
1310 // allocates a nes iplimage containing the last grabbed image.
1311 // Can be called from the main thread or the render thread, via
1312 //   GetProperty("raw_image"), or from the capturing thread, via
1313 //   the callback
1314 static IplImage *
1315 icvVideoGetImage(int cameraid)
1316 {
1317     CvSize size;
1318     CvVideoCamera *const camera = &(cameras[cameraid]);
1319     IplImage *image;
1320     void *data;
1321     int lastframe;
1322     int depth = icvVideoFormat2Depth(camera->imagepalette);
1323
1324     pthread_mutex_lock(&(camera->capturestatemutex));
1325     if(!(camera->capturestate==CAPTURING))
1326     {
1327         pthread_mutex_unlock(&(camera->capturestatemutex));
1328         return NULL;
1329     }
1330     pthread_mutex_unlock(&(camera->capturestatemutex));
1331     size.width = camera->videopp.width;
1332     size.height = camera->videopp.height;
1333     
1334     assert(camera->videopp.picture.palette);
1335     assert(icvVideoFormat2Depth(camera->imagepalette));
1336
1337     image = cvCreateImageHeader(size,IPL_DEPTH_8U,depth/8);
1338     pthread_mutex_lock(&(camera->lastframemutex));
1339     lastframe = camera->lastframe;
1340     pthread_mutex_unlock(&(camera->lastframemutex));
1341     pthread_rwlock_rdlock(&(camera->framelock[lastframe]));
1342     if (camera->imagepalette == camera->videopp.picture.palette)
1343     {
1344         IplImage *buffer = cvCreateImageHeader(size,IPL_DEPTH_8U,depth/8);
1345         cvSetImageData(buffer,
1346                        (void*)(camera->memorymap+
1347                        camera->mbuf.offsets[camera->lastframe]),
1348                        size.width*(depth/8));
1349         cvCreateImageData(image);
1350         cvCopyImage(buffer, image);
1351         pthread_rwlock_unlock(&(camera->framelock[lastframe]));
1352         cvReleaseImageHeader(&buffer);
1353         return image;
1354     }
1355     // only one conversion is implemented, for now
1356     assert(camera->videopp.picture.palette == VIDEO_PALETTE_YUV420P);
1357     assert((camera->imagepalette == VIDEO_PALETTE_RGB24) ||
1358            (camera->imagepalette == VIDEO_PALETTE_RGB565));
1359     
1360     data = (void*)cvAlloc(size.width*size.height*(depth/8));
1361     cvSetImageData(image, data, size.width*(depth/8));
1362     yuv420p_to_rgb(camera->videopp.width,
1363                    camera->videopp.height,
1364                    (unsigned char*)(camera->memorymap+
1365                    camera->mbuf.offsets[camera->lastframe]),
1366                    (unsigned char*)(data),
1367                    depth);
1368     pthread_rwlock_unlock(&(camera->framelock[lastframe]));
1369     return image;
1370 }
1371
1372 //Stubs for avi files
1373
1374 /*Plays a specified avi file into a specified window
1375 if file is NULL, file browser is opened. if window is 0,
1376 it is created. width and height mean output size's 0 means
1377 those of avi file are used. __cdecl (*callback)(IplImage*) would be
1378 called on every frame. NULL means no callback*/
1379 CVCAM_API int cvcamPlayAVI(const char* file,
1380                            void* window,
1381                            int width,
1382                            int height,
1383                            void* callback)
1384 {
1385
1386 return -1;
1387 }
1388
1389
1390 /*Advanced API for dealing with AVI files*/
1391
1392
1393
1394
1395 /*Opens a given file or pops up a dialog if file is NULL
1396 returns a handle to the file opened for success or -1 for failure*/
1397 CVCAM_API cvcamAVIFILE cvcamAVIOpenFile(char* file)
1398 {
1399     return (cvcamAVIFILE)-1;
1400 }
1401
1402 /*The next functions just do what they say and return 0
1403 for success, anything other for failure*/
1404
1405 CVCAM_API int cvcamAVICloseFile(cvcamAVIFILE file)
1406 {
1407     return -1;
1408 }
1409
1410 CVCAM_API int cvcamAVISetWindow(cvcamAVIFILE file, void* window)
1411 {
1412     return -1;
1413 }
1414
1415 CVCAM_API int cvcamAVISetCallback(cvcamAVIFILE file, void* callback)
1416 {
1417     return -1;
1418 }
1419
1420 CVCAM_API int cvcamAVISetSize(cvcamAVIFILE file, int width, int height)
1421 {
1422     return -1;
1423 }
1424
1425 CVCAM_API int cvcamAVIRun(cvcamAVIFILE file)
1426 {
1427     return -1;
1428 }
1429
1430 CVCAM_API int cvcamAVIStop(cvcamAVIFILE file)
1431 {
1432     return -1;
1433 }
1434
1435 CVCAM_API int cvcamAVIPause(cvcamAVIFILE file)
1436 {
1437     return -1;
1438 }
1439
1440 CVCAM_API int cvcamAVIResume(cvcamAVIFILE file)
1441 {
1442     return -1;
1443 }
1444
1445 CVCAM_API int cvcamAVIWaitCompletion(cvcamAVIFILE file)
1446 {
1447     return -1;
1448 }
1449
1450 CVCAM_API int cvcamAVIIsRunning(cvcamAVIFILE file)
1451 {
1452     return -1;
1453 }
1454