source: mediastreamer2/src/qtcapture.m @ 1363:e5ea97496c08

Last change on this file since 1363:e5ea97496c08 was 1363:e5ea97496c08, checked in by Simon Morlat <simon.morlat@…>, 2 years ago

build with correct video options on macosx.

File size: 9.9 KB
Line 
1#ifdef __APPLE__
2
3#include "mediastreamer-config.h"
4#include "mediastreamer2/msvideo.h"
5#include "mediastreamer2/msticker.h"
6#include "mediastreamer2/msv4l.h"
7#include "mediastreamer2/mswebcam.h"
8#include "nowebcam.h"
9
10#import <QTKit/QTKit.h>
11
12struct v4mState;
13
14@interface NsMsWebCam :NSObject
15{
16        QTCaptureDeviceInput *input;
17        QTCaptureDecompressedVideoOutput * output;
18        QTCaptureSession *session;
19        //QTCaptureDevice *device;
20       
21        ms_mutex_t mutex;
22        queue_t rq;
23};
24
25-(id) init;
26-(void) dealloc;
27-(int) start;
28-(int) stop;
29-(void) setSize:(MSVideoSize) size;
30-(MSVideoSize) getSize;
31-(void) setName:(char*) name;
32-(int) getPixFmt;
33
34-(QTCaptureSession *) session;
35-(queue_t*) rq;
36-(ms_mutex_t *) mutex;
37
38@end
39
40@implementation NsMsWebCam
41
42-(void)captureOutput:(QTCaptureOutput *)captureOutput didOutputVideoFrame:(CVImageBufferRef)videoFrame withSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:
43(QTCaptureConnection *)connection
44{
45        ms_mutex_lock(&mutex); 
46        mblk_t *buf;
47        uint8_t * data = (uint8_t *)[sampleBuffer bytesForAllSamples];
48        int size = [sampleBuffer lengthForAllSamples];
49        buf=allocb(size,0);
50        memcpy(buf->b_wptr, data, size);
51        buf->b_wptr+=size;                     
52        putq(&rq, buf);
53        ms_mutex_unlock(&mutex);
54}
55
56-(id) init {
57        qinit(&rq);
58        ms_mutex_init(&mutex,NULL);
59       
60        session = [[QTCaptureSession alloc] init];
61        output = [[QTCaptureDecompressedVideoOutput alloc] init];
62       
63        [output setDelegate: self];
64       
65       
66        return self;
67}
68
69-(void) dealloc {
70        [self stop];
71       
72        if(session)
73        {               
74                [session release];
75                session = nil;
76        }
77               
78        if(input)
79        {
80                [input release];
81                input = nil;
82        }
83       
84        if(output)
85        {
86                [output release];
87                output = nil;
88        }
89       
90        flushq(&rq,0);
91        ms_mutex_destroy(&mutex);
92
93        [super dealloc];
94}
95
96-(int) start {
97       
98        [session startRunning];
99       
100        return 0;
101}
102
103-(int) stop {
104       
105        [session stopRunning];
106       
107        return 0;
108}
109
110-(int) getPixFmt{
111       
112        QTCaptureDevice *device = [input device];
113        if([device isOpen])
114        {       
115                NSArray * array = [device formatDescriptions];
116       
117                NSEnumerator *enumerator = [array objectEnumerator];
118                QTFormatDescription *desc;
119                while ((desc = [enumerator nextObject]))
120                {
121                        if ([desc mediaType] == QTMediaTypeVideo)
122                        {
123                                UInt32 fmt = [desc formatType];
124                               
125                                if( fmt == kCVPixelFormatType_420YpCbCr8Planar)
126                                        return MS_YUV420P;
127                               
128                                //else if( fmt == MS_YUYV)
129                                //      return;
130                               
131                                else if( fmt == kCVPixelFormatType_24RGB)
132                                        return MS_RGB24;
133                               
134                                //else if( fmt == MS_RGB24_REV)
135                                //      return;
136                                //else if( fmt == MS_MJPEG)
137                                //      return;
138                                else if( fmt == kUYVY422PixelFormat)
139                                        return MS_UYVY;
140                               
141                                else if( fmt == kYUVSPixelFormat)
142                                        return MS_YUY2;
143                               
144                                else if( fmt == k32RGBAPixelFormat)
145                                        return MS_RGBA32;
146                               
147            }
148        }
149    }
150       
151        return MS_YUV420P;
152}
153
154-(void) setName:(char*) name
155{
156        NSError *error = nil;
157        unsigned int i = 0;
158         
159        QTCaptureDevice * device = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeVideo];
160         
161        if(name != nil)
162        {
163                NSArray * array = [QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo];
164         
165                for(i = 0 ; i < [array count]; i++)
166                {
167                        QTCaptureDevice * deviceTmp = [array objectAtIndex:i];
168                        if(!strcmp([[device localizedDisplayName] UTF8String], name))
169                        {
170                                device = deviceTmp;
171                                break;
172                        }
173                }
174        }
175       
176        if(device)
177                if(![device open:&error])
178                        return;
179       
180        input = [[QTCaptureDeviceInput alloc] initWithDevice:device];
181       
182        [session addInput:input error:&error];
183        [session addOutput:output error:&error];
184
185}
186
187-(void) setSize:(MSVideoSize) size
188{       
189        NSDictionary * dic = [NSDictionary dictionaryWithObjectsAndKeys:
190         [NSNumber numberWithInteger:size.width], (id)kCVPixelBufferWidthKey,
191         [NSNumber numberWithInteger:size.height],(id)kCVPixelBufferHeightKey,
192         //[NSNumber numberWithInteger:kCVPixelFormatType_420YpCbCr8Planar], (id)kCVPixelBufferPixelFormatTypeKey,
193                                                  nil];
194       
195        [output setPixelBufferAttributes:dic];
196}
197
198-(MSVideoSize) getSize
199{
200        MSVideoSize size;
201       
202        size.width = MS_VIDEO_SIZE_QCIF_W;
203        size.height = MS_VIDEO_SIZE_QCIF_H;
204       
205        if(output)
206        {
207                NSDictionary * dic = [output pixelBufferAttributes];
208               
209                size.width = [[dic objectForKey:(id)kCVPixelBufferWidthKey] integerValue];
210                size.height = [[dic objectForKey:(id)kCVPixelBufferHeightKey] integerValue];
211        }
212       
213        return size;
214}
215
216-(QTCaptureSession *) session
217{
218        return  session;
219}
220
221-(queue_t*) rq
222{
223        return &rq;
224}
225
226-(ms_mutex_t *) mutex
227{
228        return &mutex;
229}
230
231@end
232
233typedef struct v4mState{       
234        NsMsWebCam * webcam;
235        NSAutoreleasePool* myPool;
236        mblk_t *mire;
237        int frame_ind; 
238        float fps;
239        float start_time;
240        int frame_count;
241        bool_t usemire;
242}v4mState;
243
244static void v4m_init(MSFilter *f){
245        v4mState *s=ms_new0(v4mState,1);
246        s->myPool = [[NSAutoreleasePool alloc] init];
247        s->webcam= [[NsMsWebCam alloc] init];
248        [s->webcam retain];
249        s->mire=NULL;   
250        s->start_time=0;
251        s->frame_count=-1;
252        s->fps=15;
253        s->usemire=(getenv("DEBUG")!=NULL);
254        f->data=s;
255}
256
257static int v4m_start(MSFilter *f, void *arg) {
258        v4mState *s=(v4mState*)f->data;
259        [s->webcam start];
260        ms_message("v4m video device opened.");
261        return 0;
262}
263
264static int v4m_stop(MSFilter *f, void *arg){
265        v4mState *s=(v4mState*)f->data;
266        [s->webcam stop];
267        ms_message("v4m video device closed.");
268       
269        return 0;
270}
271
272static void v4m_uninit(MSFilter *f){
273        v4mState *s=(v4mState*)f->data;
274        v4m_stop(f,NULL);
275       
276        freemsg(s->mire);
277        [s->webcam release];
278        [s->myPool release];
279        ms_free(s);
280}
281
282static mblk_t * v4m_make_mire(v4mState *s){
283        unsigned char *data;
284        int i,j,line,pos;
285        MSVideoSize vsize = [s->webcam getSize];
286        int patternw=vsize.width/6;
287        int patternh=vsize.height/6;
288        int red,green=0,blue=0;
289        if (s->mire==NULL){
290                s->mire=allocb(vsize.width*vsize.height*3,0);
291                s->mire->b_wptr=s->mire->b_datap->db_lim;
292        }
293        data=s->mire->b_rptr;
294        for (i=0;i<vsize.height;++i){
295                line=i*vsize.width*3;
296                if ( ((i+s->frame_ind)/patternh) & 0x1) red=255;
297                else red= 0;
298                for (j=0;j<vsize.width;++j){
299                        pos=line+(j*3);
300                       
301                        if ( ((j+s->frame_ind)/patternw) & 0x1) blue=255;
302                        else blue= 0;
303                       
304                        data[pos]=red;
305                        data[pos+1]=green;
306                        data[pos+2]=blue;
307                }
308        }
309        s->frame_ind++;
310        return s->mire;
311}
312
313static mblk_t * v4m_make_nowebcam(v4mState *s){
314        if (s->mire==NULL && s->frame_ind==0){
315                //s->mire=ms_load_nowebcam(&s->vsize, -1);
316        }
317        s->frame_ind++;
318        return s->mire;
319}
320
321static void v4m_process(MSFilter * obj){
322        v4mState *s=(v4mState*)obj->data;
323        uint32_t timestamp;
324        int cur_frame;
325        if (s->frame_count==-1){
326                s->start_time=obj->ticker->time;
327                s->frame_count=0;
328        }
329
330        ms_mutex_lock([s->webcam mutex]);
331
332        cur_frame=((obj->ticker->time-s->start_time)*s->fps/1000.0);
333        if (cur_frame>=s->frame_count)
334        {
335                mblk_t *om=NULL;
336                /*keep the most recent frame if several frames have been captured */
337                if ([[s->webcam session] isRunning])
338                {
339                        om=getq([s->webcam rq]);
340                }
341                else
342                {
343                        /*if (s->pix_fmt==MS_YUV420P && s->vsize.width==MS_VIDEO_SIZE_CIF_W && s->vsize.height==MS_VIDEO_SIZE_CIF_H)
344                    {
345                                if (s->usemire)
346                                {
347                                        om=dupmsg(v4m_make_mire(s));
348                                }
349                                else
350                                {
351                                        mblk_t *tmpm=v4m_make_nowebcam(s);
352                                        if (tmpm)
353                                                om=dupmsg(tmpm);
354                                }
355                    }*/
356                }
357               
358                if (om!=NULL)
359                {
360                        timestamp=obj->ticker->time*90;/* rtp uses a 90000 Hz clockrate for video*/
361                        mblk_set_timestamp_info(om,timestamp);
362                        mblk_set_marker_info(om,TRUE); 
363                        ms_queue_put(obj->outputs[0],om);
364                        s->frame_count++;
365                }
366        }
367        else
368                flushq([s->webcam rq],0);
369
370        ms_mutex_unlock([s->webcam mutex]);
371}
372
373static void v4m_preprocess(MSFilter *f){
374        v4m_start(f,NULL);
375       
376}
377
378static void v4m_postprocess(MSFilter *f){
379        v4m_stop(f,NULL);
380}
381
382static int v4m_set_fps(MSFilter *f, void *arg){
383        v4mState *s=(v4mState*)f->data;
384        s->fps=*((float*)arg);
385        s->frame_count=-1;
386        return 0;
387}
388
389static int v4m_get_pix_fmt(MSFilter *f,void *arg){
390        v4mState *s=(v4mState*)f->data;
391        *((MSPixFmt*)arg) = [s->webcam getPixFmt];
392        return 0;
393}
394
395static int v4m_set_vsize(MSFilter *f, void *arg){
396        v4mState *s=(v4mState*)f->data;
397        [s->webcam setSize:*((MSVideoSize*)arg)];
398        return 0;
399}
400
401static int v4m_get_vsize(MSFilter *f, void *arg){
402        v4mState *s=(v4mState*)f->data;
403        *(MSVideoSize*)arg = [s->webcam getSize];
404        return 0;
405}
406
407static MSFilterMethod methods[]={
408        {       MS_FILTER_SET_FPS               ,       v4m_set_fps             },
409        {       MS_FILTER_GET_PIX_FMT   ,       v4m_get_pix_fmt },
410        {       MS_FILTER_SET_VIDEO_SIZE,       v4m_set_vsize   },
411        {       MS_V4L_START                    ,       v4m_start               },
412        {       MS_V4L_STOP                             ,       v4m_stop                },
413        {       MS_FILTER_GET_VIDEO_SIZE,       v4m_get_vsize   },
414        {       0                                               ,       NULL                    }
415};
416
417MSFilterDesc ms_v4m_desc={
418        .id=MS_V4L_ID,
419        .name="MSV4m",
420        .text="A video for macosx compatible source filter to stream pictures.",
421        .ninputs=0,
422        .noutputs=1,
423        .category=MS_FILTER_OTHER,
424        .init=v4m_init,
425        .preprocess=v4m_preprocess,
426        .process=v4m_process,
427        .postprocess=v4m_postprocess,
428        .uninit=v4m_uninit,
429        .methods=methods
430};
431
432MS_FILTER_DESC_EXPORT(ms_v4m_desc)
433       
434static void ms_v4m_detect(MSWebCamManager *obj);
435
436static void ms_v4m_cam_init(MSWebCam *cam)
437{
438}
439
440static int v4m_set_device(MSFilter *f, void *arg)
441{       
442        v4mState *s=(v4mState*)f->data;
443       
444        /*s->id = (char*) malloc(sizeof(char)*strlen((char*)arg));
445        strcpy(s->id,(char*)arg);*/
446
447        return 0;
448}
449
450static int v4m_set_name(MSFilter *f, void *arg){
451       
452        v4mState *s=(v4mState*)f->data;
453       
454        //s->name = (char*) malloc(sizeof(char)*strlen((char*)arg));
455        //strcpy(s->name,(char*)arg);
456       
457        [s->webcam setName:(char*)arg];
458
459        return 0;
460}
461
462static MSFilter *ms_v4m_create_reader(MSWebCam *obj)
463{       
464        MSFilter *f= ms_filter_new_from_desc(&ms_v4m_desc);
465       
466        v4m_set_device(f,obj->id);
467        v4m_set_name(f,obj->data);
468       
469        return f;
470}
471
472MSWebCamDesc ms_v4m_cam_desc={
473        "VideoForMac grabber",
474        &ms_v4m_detect,
475        &ms_v4m_cam_init,
476        &ms_v4m_create_reader,
477        NULL
478};
479
480
481static void ms_v4m_detect(MSWebCamManager *obj){
482 
483        unsigned int i = 0;
484        NSAutoreleasePool* myPool = [[NSAutoreleasePool alloc] init];
485       
486        NSArray * array = [QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo];
487       
488        for(i = 0 ; i < [array count]; i++)
489        {
490                QTCaptureDevice * device = [array objectAtIndex:i];
491                MSWebCam *cam=ms_web_cam_new(&ms_v4m_cam_desc);
492               
493                cam->name= ms_strdup([[device localizedDisplayName] UTF8String]);
494                cam->id = ms_strdup([[device uniqueID] UTF8String]);
495                cam->data = NULL;
496                ms_web_cam_manager_add_cam(obj,cam);
497        }
498        [myPool release];
499}
500       
501#endif       
Note: See TracBrowser for help on using the repository browser.