source: mediastreamer2/src/msv4m2.m @ 1084:e6e543dd8242

Last change on this file since 1084:e6e543dd8242 was 1084:e6e543dd8242, checked in by laurent, 2 years ago

bug fix : dealloc msv4m2

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