source: mediastreamer2/linphone/mediastreamer2/src/msv4m.c @ 205:f65852271c00

Last change on this file since 205:f65852271c00 was 205:f65852271c00, checked in by smorlat <smorlat@…>, 5 years ago

internationalization of mediastreamer2 (thanks to Petr Pisar)

git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@208 3f6dc0c8-ddfe-455d-9043-3cd528dc4637

File size: 12.2 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
24#include <fcntl.h>
25#include <unistd.h>
26#include <sys/stat.h>
27#include <sys/types.h>
28#include <sys/ioctl.h>
29#include <errno.h>
30#include <string.h>
31
32#include "mediastreamer2/msvideo.h"
33#include "mediastreamer2/msticker.h"
34#include "mediastreamer2/msv4l.h"
35#include "nowebcam.h"
36
37// build for carbon
38#define TARGET_API_MAC_CARBON 1
39
40#if __APPLE_CC__
41  #include <Carbon/Carbon.h>
42  #include <QuicKTime/QuickTime.h>
43#else
44  #include <ConditionalMacros.h>
45  #include <QuickTimeComponents.h>
46  #include <TextUtils.h>
47
48  #include <stdio.h>
49#endif
50
51typedef struct V4lState{
52  SeqGrabComponent seqgrab;
53  SGChannel sgchanvideo;
54  GWorldPtr pgworld;
55  ImageSequence   decomseq;
56
57  char *mmapdbuf;
58  int msize;/*mmapped size*/
59  MSVideoSize vsize;
60  MSVideoSize got_vsize;
61  int pix_fmt;
62  int int_pix_fmt; /*internal pixel format */
63  mblk_t *mire;
64  queue_t rq;
65  ms_mutex_t mutex;
66  int frame_ind;
67  int frame_max;
68  float fps;
69  float start_time;
70  int frame_count;
71  int queued;
72  bool_t run;
73  bool_t usemire;
74}V4lState;
75
76static void v4m_init(MSFilter *f){
77        V4lState *s=ms_new0(V4lState,1);
78        s->seqgrab=NULL;
79        s->sgchanvideo=NULL;
80        s->pgworld=NULL;
81        s->decomseq=0;
82
83        s->run=FALSE;
84        s->mmapdbuf=NULL;
85        s->vsize.width=MS_VIDEO_SIZE_CIF_W;
86        s->vsize.height=MS_VIDEO_SIZE_CIF_H;
87        s->pix_fmt=MS_RGB24;
88        qinit(&s->rq);
89        s->mire=NULL;
90        ms_mutex_init(&s->mutex,NULL);
91        s->start_time=0;
92        s->frame_count=-1;
93        s->fps=15;
94        s->usemire=(getenv("DEBUG")!=NULL);
95        s->queued=0;
96        f->data=s;
97}
98
99
100#define BailErr(x) {err = x; if(err != noErr) goto bail;}
101
102pascal OSErr sgdata_callback(SGChannel c, Ptr p, long len, long *offset, long chRefCon, TimeValue time, short writeType, long refCon);
103pascal OSErr sgdata_callback(SGChannel c, Ptr p, long len, long *offset, long chRefCon, TimeValue time, short writeType, long refCon)
104{
105#pragma unused(offset,chRefCon,time,writeType)
106   
107    CodecFlags     ignore;
108    V4lState *s=(V4lState *)refCon;
109    ComponentResult err = noErr;
110   
111    if (!s) goto bail;
112   
113    Rect boundsRect = {0, 0, s->vsize.height, s->vsize.width}; /* 240 , 320*/
114    if (s->pgworld) {
115
116      if (s->decomseq == 0) {
117        Rect sourceRect = { 0, 0 };
118        MatrixRecord scaleMatrix;
119        ImageDescriptionHandle imageDesc = (ImageDescriptionHandle)NewHandle(0);
120       
121        err = SGGetChannelSampleDescription(c,(Handle)imageDesc);
122        BailErr(err);
123       
124        // make a scaling matrix for the sequence
125        sourceRect.right = (**imageDesc).width;
126        sourceRect.bottom = (**imageDesc).height;
127        RectMatrix(&scaleMatrix, &sourceRect, &boundsRect);
128           
129        err = DecompressSequenceBegin(&s->decomseq,  // pointer to field to receive unique ID for sequence
130                                      imageDesc,        // handle to image description structure
131                                      s->pgworld,    // port for the DESTINATION image
132                                      NULL,            // graphics device handle, if port is set, set to NULL
133                                      NULL,            // source rectangle defining the portion of the image to decompress
134                                      &scaleMatrix,        // transformation matrix
135                                      srcCopy,          // transfer mode specifier
136                                      NULL,            // clipping region in dest. coordinate system to use as a mask
137                                      0,            // flags
138                                      codecNormalQuality,    // accuracy in decompression
139                                      bestSpeedCodec);      // compressor identifier or special identifiers ie. bestSpeedCodec
140        BailErr(err);
141       
142        DisposeHandle((Handle)imageDesc);
143        imageDesc = NULL;
144      }
145     
146      // decompress a frame into the GWorld - can queue a frame for async decompression when passed in a completion proc
147      // once the image is in the GWorld it can be manipulated at will
148      err = DecompressSequenceFrameS(s->decomseq,  // sequence ID returned by DecompressSequenceBegin
149                                     p,            // pointer to compressed image data
150                                     len,          // size of the buffer
151                                     0,            // in flags
152                                     &ignore,        // out flags
153                                     NULL);          // async completion proc
154        BailErr(err);
155       
156    {
157      unsigned line;
158      mblk_t *buf;
159      int size = s->vsize.width * s->vsize.height * 3;
160      buf=allocb(size,0);
161     
162      PixMap * pixmap = *GetGWorldPixMap(s->pgworld);
163      uint8_t * data;
164      unsigned rowBytes = pixmap->rowBytes & (((unsigned short) 0xFFFF) >> 2);
165      unsigned pixelSize = pixmap->pixelSize / 8; // Pixel size in bytes
166      unsigned lineOffset = rowBytes - s->vsize.width * pixelSize;
167     
168      data = (uint8_t *) GetPixBaseAddr(GetGWorldPixMap(s->pgworld));
169     
170      for (line = 0 ; line < s->vsize.height ; line++) {
171        unsigned offset = line * (s->vsize.width * pixelSize + lineOffset);
172        memcpy(buf->b_wptr + ((line * s->vsize.width) * pixelSize), data + offset, (rowBytes - lineOffset));
173      }
174
175      if (s->pix_fmt==MS_RGB24)
176        {
177          /* Conversion from top down bottom up (BGR to RGB and flip) */
178          unsigned long Index,nPixels;
179          unsigned char *blue;
180          unsigned char tmp;
181          short iPixelSize;
182
183          blue=buf->b_wptr;
184
185          nPixels=s->vsize.width*s->vsize.height;
186          iPixelSize=24/8;
187
188          for(Index=0;Index!=nPixels;Index++)  // For each pixel
189            {
190              tmp=*blue;
191              *blue=*(blue+2);
192              *(blue+2)=tmp;
193              blue+=iPixelSize;
194            }
195        }
196
197      buf->b_wptr+=size;
198      //ms_mutex_lock(&s->mutex); /* called during SGIdle? */
199      putq(&s->rq, buf);
200      //ms_mutex_unlock(&s->mutex);
201    }
202  }
203
204bail:
205  return err;
206}
207
208static int v4m_close(V4lState *s)
209{
210  if(s->seqgrab)
211    CloseComponent(s->seqgrab);
212  s->seqgrab=NULL;
213  if (s->decomseq)
214    CDSequenceEnd(s->decomseq);
215  s->decomseq=NULL;
216  if (s->pgworld!=NULL)
217    DisposeGWorld(s->pgworld);
218  s->pgworld=NULL;
219  return 0;
220}
221
222static int sequence_grabber_start(V4lState *s)
223{
224  int err;
225  Rect        theRect = {0, 0, s->vsize.height, s->vsize.width};
226
227  err = QTNewGWorld(&(s->pgworld),  // returned GWorld
228                    k24BGRPixelFormat,
229                    &theRect,      // bounding rectangle
230                    0,             // color table
231                    NULL,          // graphic device handle
232                    0);            // flags
233  if (err!=noErr)
234    {
235      return -1;
236    }
237
238  if(!LockPixels(GetPortPixMap(s->pgworld)))
239    {
240      v4m_close(s);
241      return -1;
242    }
243
244  s->seqgrab = OpenDefaultComponent(SeqGrabComponentType, 0);
245  err = SGInitialize(s->seqgrab);
246  if (err!=noErr)
247    {
248      v4m_close(s);
249      return -1;
250    }
251  err = SGSetDataRef(s->seqgrab, 0, 0, seqGrabDontMakeMovie);
252  if (err!=noErr)
253    {
254      v4m_close(s);
255      return -1;
256    }
257
258  err = SGSetGWorld(s->seqgrab, s->pgworld, GetMainDevice());
259  if (err!=noErr)
260    {
261      v4m_close(s);
262      return -1;
263    }
264
265  err = SGNewChannel(s->seqgrab, VideoMediaType, &s->sgchanvideo);
266  if (err!=noErr)
267    {
268      v4m_close(s);
269      return -1;
270    }
271
272  err = SGSetChannelBounds(s->sgchanvideo, &theRect);
273  if (err!=noErr)
274    {
275      v4m_close(s);
276      return -1;
277    }
278
279  err = SGSetChannelUsage(s->sgchanvideo, seqGrabRecord);
280  if (err!=noErr)
281    {
282      v4m_close(s);
283      return -1;
284    }
285
286  err = SGSetDataProc(s->seqgrab,NewSGDataUPP(sgdata_callback),(long)s);
287  if (err!=noErr)
288    {
289      v4m_close(s);
290      return -1;
291    }
292
293  err = SGStartRecord(s->seqgrab);
294  if (err!=noErr)
295    {
296      v4m_close(s);
297      return -1;
298    }
299
300  return 0;
301}
302
303static int v4m_start(MSFilter *f, void *arg)
304{
305        V4lState *s=(V4lState*)f->data;
306        int err=0;
307
308        err = sequence_grabber_start(s);
309
310        if (err!=0)
311          {
312            s->pix_fmt=MS_YUV420P;
313            s->vsize.width=MS_VIDEO_SIZE_CIF_W;
314            s->vsize.height=MS_VIDEO_SIZE_CIF_H;
315            return 0;
316          }
317
318        ms_message("v4m video device opened.");
319        s->pix_fmt=MS_RGB24;
320
321        return 0;
322}
323
324static void v4m_start_capture(V4lState *s){
325        if (s->seqgrab!=NULL){
326                s->run=TRUE;
327        }
328}
329
330static int v4m_stop(MSFilter *f, void *arg){
331        V4lState *s=(V4lState*)f->data;
332        if (s->seqgrab!=NULL){
333          ms_mutex_lock(&s->mutex);
334          SGStop(s->seqgrab);
335          v4m_close(s);
336          flushq(&s->rq,0);
337          ms_mutex_unlock(&s->mutex);
338        }
339        return 0;
340}
341
342static void v4m_stop_capture(V4lState *s){
343        if (s->run){
344                s->run=FALSE;
345                ms_message("v4m capture stopped.");
346        }
347}
348
349
350static void v4m_uninit(MSFilter *f){
351        V4lState *s=(V4lState*)f->data;
352        if (s->seqgrab!=NULL) v4m_stop(f,NULL);
353        //ms_free(s->dev);
354        flushq(&s->rq,0);
355        ms_mutex_destroy(&s->mutex);
356        freemsg(s->mire);
357        ms_free(s);
358}
359
360static mblk_t * v4m_make_mire(V4lState *s){
361        unsigned char *data;
362        int i,j,line,pos;
363        int patternw=s->vsize.width/6; 
364        int patternh=s->vsize.height/6;
365        int red,green=0,blue=0;
366        if (s->mire==NULL){
367                s->mire=allocb(s->vsize.width*s->vsize.height*3,0);
368                s->mire->b_wptr=s->mire->b_datap->db_lim;
369        }
370        data=s->mire->b_rptr;
371        for (i=0;i<s->vsize.height;++i){
372                line=i*s->vsize.width*3;
373                if ( ((i+s->frame_ind)/patternh) & 0x1) red=255;
374                else red= 0;
375                for (j=0;j<s->vsize.width;++j){
376                        pos=line+(j*3);
377                       
378                        if ( ((j+s->frame_ind)/patternw) & 0x1) blue=255;
379                        else blue= 0;
380                       
381                        data[pos]=red;
382                        data[pos+1]=green;
383                        data[pos+2]=blue;
384                }
385        }
386        s->frame_ind++;
387        return s->mire;
388}
389
390static mblk_t * v4m_make_nowebcam(V4lState *s){
391        if (s->mire==NULL && s->frame_ind==0){
392                s->mire=ms_load_nowebcam(&s->vsize, -1);
393        }
394        s->frame_ind++;
395        return s->mire;
396}
397
398static void v4m_process(MSFilter * obj){
399        V4lState *s=(V4lState*)obj->data;
400        uint32_t timestamp;
401        int cur_frame;
402        if (s->frame_count==-1){
403                s->start_time=obj->ticker->time;
404                s->frame_count=0;
405        }
406
407        ms_mutex_lock(&s->mutex);
408
409        if (s->seqgrab!=NULL)
410        {
411          SGIdle(s->seqgrab);
412        }
413
414        cur_frame=((obj->ticker->time-s->start_time)*s->fps/1000.0);
415        if (cur_frame>=s->frame_count){
416                mblk_t *om=NULL;
417                /*keep the most recent frame if several frames have been captured */
418                if (s->seqgrab!=NULL){
419                        om=getq(&s->rq);
420                }else{
421                  if (s->pix_fmt==MS_YUV420P
422                      && s->vsize.width==MS_VIDEO_SIZE_CIF_W
423                      && s->vsize.height==MS_VIDEO_SIZE_CIF_H)
424                    {
425                        if (s->usemire){
426                                om=dupmsg(v4m_make_mire(s));
427                        }else {
428                                mblk_t *tmpm=v4m_make_nowebcam(s);
429                                if (tmpm) om=dupmsg(tmpm);
430                        }
431                    }
432                }
433                if (om!=NULL){
434                        timestamp=obj->ticker->time*90;/* rtp uses a 90000 Hz clockrate for video*/
435                        mblk_set_timestamp_info(om,timestamp);
436                        mblk_set_marker_info(om,TRUE);
437                        ms_queue_put(obj->outputs[0],om);
438                        /*ms_message("picture sent");*/
439                        s->frame_count++;
440                }
441        }else flushq(&s->rq,0);
442
443        ms_mutex_unlock(&s->mutex);
444}
445
446static void v4m_preprocess(MSFilter *f){
447        V4lState *s=(V4lState*)f->data;
448        v4m_start_capture(s);
449}
450
451static void v4m_postprocess(MSFilter *f){
452        V4lState *s=(V4lState*)f->data;
453        v4m_stop_capture(s);
454}
455
456static int v4m_set_fps(MSFilter *f, void *arg){
457        V4lState *s=(V4lState*)f->data;
458        s->fps=*((float*)arg);
459        s->frame_count=-1;
460        return 0;
461}
462
463static int v4m_get_pix_fmt(MSFilter *f,void *arg){
464        V4lState *s=(V4lState*)f->data;
465        *((MSPixFmt*)arg) = s->pix_fmt;
466        return 0;
467}
468
469static int v4m_set_vsize(MSFilter *f, void *arg){
470        V4lState *s=(V4lState*)f->data;
471        s->vsize=*((MSVideoSize*)arg);
472        return 0;
473}
474
475static int v4m_get_vsize(MSFilter *f, void *arg){
476        V4lState *s=(V4lState*)f->data;
477        *(MSVideoSize*)arg=s->vsize;
478        return 0;
479}
480
481static MSFilterMethod methods[]={
482        {       MS_FILTER_SET_FPS       ,       v4m_set_fps     },
483        {       MS_FILTER_GET_PIX_FMT   ,       v4m_get_pix_fmt },
484        {       MS_FILTER_SET_VIDEO_SIZE,       v4m_set_vsize   },
485        {       MS_V4L_START                    ,       v4m_start       },
486        {       MS_V4L_STOP                     ,       v4m_stop        },
487        {       MS_FILTER_GET_VIDEO_SIZE,       v4m_get_vsize },
488        {       0       ,       NULL                    }
489};
490
491MSFilterDesc ms_v4l_desc={
492        .id=MS_V4L_ID,
493        .name="MSV4m",
494        .text=N_("A video for macosx compatible source filter to stream pictures."),
495        .ninputs=0,
496        .noutputs=1,
497        .category=MS_FILTER_OTHER,
498        .init=v4m_init,
499        .preprocess=v4m_preprocess,
500        .process=v4m_process,
501        .postprocess=v4m_postprocess,
502        .uninit=v4m_uninit,
503        .methods=methods
504};
505
506MS_FILTER_DESC_EXPORT(ms_v4l_desc)
507
508#endif
Note: See TracBrowser for help on using the repository browser.