~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjmedia/src/pjmedia-videodev/qt_dev.m

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: qt_dev.m 3979 2012-03-20 08:55:33Z ming $ */
 
2
/*
 
3
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
 */
 
19
#include <pjmedia-videodev/videodev_imp.h>
 
20
#include <pj/assert.h>
 
21
#include <pj/log.h>
 
22
#include <pj/os.h>
 
23
 
 
24
#if PJMEDIA_VIDEO_DEV_HAS_QT
 
25
 
 
26
#include <Foundation/NSAutoreleasePool.h>
 
27
#include <QTKit/QTKit.h>
 
28
 
 
29
#define THIS_FILE               "qt_dev.c"
 
30
#define DEFAULT_CLOCK_RATE      90000
 
31
#define DEFAULT_WIDTH           640
 
32
#define DEFAULT_HEIGHT          480
 
33
#define DEFAULT_FPS             15
 
34
 
 
35
#define kCVPixelFormatType_422YpCbCr8_yuvs 'yuvs'
 
36
 
 
37
typedef struct qt_fmt_info
 
38
{
 
39
    pjmedia_format_id   pjmedia_format;
 
40
    unsigned            qt_format;
 
41
} qt_fmt_info;
 
42
 
 
43
static qt_fmt_info qt_fmts[] =
 
44
{
 
45
    {PJMEDIA_FORMAT_YUY2, kCVPixelFormatType_422YpCbCr8_yuvs},
 
46
    {PJMEDIA_FORMAT_UYVY, kCVPixelFormatType_422YpCbCr8},
 
47
};
 
48
 
 
49
/* qt device info */
 
50
struct qt_dev_info
 
51
{
 
52
    pjmedia_vid_dev_info         info;
 
53
    char                         dev_id[192];
 
54
};
 
55
 
 
56
/* qt factory */
 
57
struct qt_factory
 
58
{
 
59
    pjmedia_vid_dev_factory      base;
 
60
    pj_pool_t                   *pool;
 
61
    pj_pool_t                   *dev_pool;
 
62
    pj_pool_factory             *pf;
 
63
 
 
64
    unsigned                     dev_count;
 
65
    struct qt_dev_info          *dev_info;
 
66
};
 
67
 
 
68
struct qt_stream;
 
69
typedef void (*func_ptr)(struct qt_stream *strm);
 
70
 
 
71
@interface QTDelegate: NSObject
 
72
{
 
73
@public
 
74
    struct qt_stream *strm;
 
75
    func_ptr          func;
 
76
}
 
77
 
 
78
- (void)run_func;
 
79
@end
 
80
 
 
81
/* Video stream. */
 
82
struct qt_stream
 
83
{
 
84
    pjmedia_vid_dev_stream  base;           /**< Base stream           */
 
85
    pjmedia_vid_dev_param   param;          /**< Settings              */
 
86
    pj_pool_t              *pool;           /**< Memory pool.          */
 
87
 
 
88
    pj_timestamp            cap_frame_ts;   /**< Captured frame tstamp */
 
89
    unsigned                cap_ts_inc;     /**< Increment             */
 
90
    
 
91
    pjmedia_vid_dev_cb      vid_cb;         /**< Stream callback.      */
 
92
    void                   *user_data;      /**< Application data.     */
 
93
 
 
94
    pj_bool_t               cap_thread_exited;
 
95
    pj_bool_t               cap_thread_initialized;
 
96
    pj_thread_desc          cap_thread_desc;
 
97
    pj_thread_t            *cap_thread;
 
98
    
 
99
    struct qt_factory      *qf;
 
100
    pj_status_t             status;
 
101
    pj_bool_t               is_running;
 
102
    pj_bool_t               cap_exited;
 
103
    
 
104
    QTCaptureSession                    *cap_session;
 
105
    QTCaptureDeviceInput                *dev_input;
 
106
    QTCaptureDecompressedVideoOutput    *video_output;
 
107
    QTDelegate                          *qt_delegate;
 
108
};
 
109
 
 
110
 
 
111
/* Prototypes */
 
112
static pj_status_t qt_factory_init(pjmedia_vid_dev_factory *f);
 
113
static pj_status_t qt_factory_destroy(pjmedia_vid_dev_factory *f);
 
114
static pj_status_t qt_factory_refresh(pjmedia_vid_dev_factory *f);
 
115
static unsigned    qt_factory_get_dev_count(pjmedia_vid_dev_factory *f);
 
116
static pj_status_t qt_factory_get_dev_info(pjmedia_vid_dev_factory *f,
 
117
                                           unsigned index,
 
118
                                           pjmedia_vid_dev_info *info);
 
119
static pj_status_t qt_factory_default_param(pj_pool_t *pool,
 
120
                                            pjmedia_vid_dev_factory *f,
 
121
                                            unsigned index,
 
122
                                            pjmedia_vid_dev_param *param);
 
123
static pj_status_t qt_factory_create_stream(
 
124
                                        pjmedia_vid_dev_factory *f,
 
125
                                        pjmedia_vid_dev_param *param,
 
126
                                        const pjmedia_vid_dev_cb *cb,
 
127
                                        void *user_data,
 
128
                                        pjmedia_vid_dev_stream **p_vid_strm);
 
129
 
 
130
static pj_status_t qt_stream_get_param(pjmedia_vid_dev_stream *strm,
 
131
                                       pjmedia_vid_dev_param *param);
 
132
static pj_status_t qt_stream_get_cap(pjmedia_vid_dev_stream *strm,
 
133
                                     pjmedia_vid_dev_cap cap,
 
134
                                     void *value);
 
135
static pj_status_t qt_stream_set_cap(pjmedia_vid_dev_stream *strm,
 
136
                                     pjmedia_vid_dev_cap cap,
 
137
                                     const void *value);
 
138
static pj_status_t qt_stream_start(pjmedia_vid_dev_stream *strm);
 
139
static pj_status_t qt_stream_stop(pjmedia_vid_dev_stream *strm);
 
140
static pj_status_t qt_stream_destroy(pjmedia_vid_dev_stream *strm);
 
141
 
 
142
/* Operations */
 
143
static pjmedia_vid_dev_factory_op factory_op =
 
144
{
 
145
    &qt_factory_init,
 
146
    &qt_factory_destroy,
 
147
    &qt_factory_get_dev_count,
 
148
    &qt_factory_get_dev_info,
 
149
    &qt_factory_default_param,
 
150
    &qt_factory_create_stream,
 
151
    &qt_factory_refresh
 
152
};
 
153
 
 
154
static pjmedia_vid_dev_stream_op stream_op =
 
155
{
 
156
    &qt_stream_get_param,
 
157
    &qt_stream_get_cap,
 
158
    &qt_stream_set_cap,
 
159
    &qt_stream_start,
 
160
    NULL,
 
161
    NULL,
 
162
    &qt_stream_stop,
 
163
    &qt_stream_destroy
 
164
};
 
165
 
 
166
 
 
167
/****************************************************************************
 
168
 * Factory operations
 
169
 */
 
170
/*
 
171
 * Init qt_ video driver.
 
172
 */
 
173
pjmedia_vid_dev_factory* pjmedia_qt_factory(pj_pool_factory *pf)
 
174
{
 
175
    struct qt_factory *f;
 
176
    pj_pool_t *pool;
 
177
 
 
178
    pool = pj_pool_create(pf, "qt video", 4000, 4000, NULL);
 
179
    f = PJ_POOL_ZALLOC_T(pool, struct qt_factory);
 
180
    f->pf = pf;
 
181
    f->pool = pool;
 
182
    f->base.op = &factory_op;
 
183
 
 
184
    return &f->base;
 
185
}
 
186
 
 
187
 
 
188
/* API: init factory */
 
189
static pj_status_t qt_factory_init(pjmedia_vid_dev_factory *f)
 
190
{
 
191
    return qt_factory_refresh(f);
 
192
}
 
193
 
 
194
/* API: destroy factory */
 
195
static pj_status_t qt_factory_destroy(pjmedia_vid_dev_factory *f)
 
196
{
 
197
    struct qt_factory *qf = (struct qt_factory*)f;
 
198
    pj_pool_t *pool = qf->pool;
 
199
 
 
200
    if (qf->dev_pool)
 
201
        pj_pool_release(qf->dev_pool);
 
202
    qf->pool = NULL;
 
203
    if (pool)
 
204
        pj_pool_release(pool);
 
205
 
 
206
    return PJ_SUCCESS;
 
207
}
 
208
 
 
209
/* API: refresh the list of devices */
 
210
static pj_status_t qt_factory_refresh(pjmedia_vid_dev_factory *f)
 
211
{
 
212
    struct qt_factory *qf = (struct qt_factory*)f;
 
213
    struct qt_dev_info *qdi;
 
214
    unsigned i, dev_count = 0;
 
215
    NSAutoreleasePool *apool = [[NSAutoreleasePool alloc]init];
 
216
    NSArray *dev_array;
 
217
    
 
218
    if (qf->dev_pool) {
 
219
        pj_pool_release(qf->dev_pool);
 
220
        qf->dev_pool = NULL;
 
221
    }
 
222
    
 
223
    dev_array = [QTCaptureDevice inputDevices];
 
224
    for (i = 0; i < [dev_array count]; i++) {
 
225
        QTCaptureDevice *dev = [dev_array objectAtIndex:i];
 
226
        if ([dev hasMediaType:QTMediaTypeVideo] ||
 
227
            [dev hasMediaType:QTMediaTypeMuxed])
 
228
        {
 
229
            dev_count++;
 
230
        }
 
231
    }
 
232
    
 
233
    /* Initialize input and output devices here */
 
234
    qf->dev_count = 0;
 
235
    qf->dev_pool = pj_pool_create(qf->pf, "qt video", 500, 500, NULL);
 
236
    
 
237
    qf->dev_info = (struct qt_dev_info*)
 
238
    pj_pool_calloc(qf->dev_pool, dev_count,
 
239
                   sizeof(struct qt_dev_info));
 
240
    for (i = 0; i < [dev_array count]; i++) {
 
241
        QTCaptureDevice *dev = [dev_array objectAtIndex:i];
 
242
        if ([dev hasMediaType:QTMediaTypeVideo] ||
 
243
            [dev hasMediaType:QTMediaTypeMuxed])
 
244
        {
 
245
            unsigned k;
 
246
            
 
247
            qdi = &qf->dev_info[qf->dev_count++];
 
248
            pj_bzero(qdi, sizeof(*qdi));
 
249
            [[dev localizedDisplayName] getCString:qdi->info.name
 
250
                                        maxLength:sizeof(qdi->info.name)
 
251
                                        encoding:
 
252
                                        [NSString defaultCStringEncoding]];
 
253
            [[dev uniqueID] getCString:qdi->dev_id
 
254
                            maxLength:sizeof(qdi->dev_id)
 
255
                            encoding:[NSString defaultCStringEncoding]];
 
256
            strcpy(qdi->info.driver, "QT");         
 
257
            qdi->info.dir = PJMEDIA_DIR_CAPTURE;
 
258
            qdi->info.has_callback = PJ_TRUE;
 
259
            
 
260
            qdi->info.fmt_cnt = 0;
 
261
            qdi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT;
 
262
            for (k = 0; k < [[dev formatDescriptions] count]; k++) {
 
263
                unsigned l;
 
264
                QTFormatDescription *desc = [[dev formatDescriptions]
 
265
                                             objectAtIndex:k];
 
266
                for (l = 0; l < PJ_ARRAY_SIZE(qt_fmts); l++) {
 
267
                    if ([desc formatType] == qt_fmts[l].qt_format) {
 
268
                        pjmedia_format *fmt = 
 
269
                            &qdi->info.fmt[qdi->info.fmt_cnt++];
 
270
                        pjmedia_format_init_video(fmt,
 
271
                                                  qt_fmts[l].pjmedia_format,
 
272
                                                  DEFAULT_WIDTH,
 
273
                                                  DEFAULT_HEIGHT,
 
274
                                                  DEFAULT_FPS, 1);
 
275
                        break;
 
276
                    }
 
277
                }
 
278
            }
 
279
            
 
280
            PJ_LOG(4, (THIS_FILE, " dev_id %d: %s", i, qdi->info.name));    
 
281
        }
 
282
    }
 
283
    
 
284
    [apool release];
 
285
    
 
286
    PJ_LOG(4, (THIS_FILE, "qt video has %d devices",
 
287
               qf->dev_count));
 
288
    
 
289
    return PJ_SUCCESS;
 
290
}
 
291
 
 
292
/* API: get number of devices */
 
293
static unsigned qt_factory_get_dev_count(pjmedia_vid_dev_factory *f)
 
294
{
 
295
    struct qt_factory *qf = (struct qt_factory*)f;
 
296
    return qf->dev_count;
 
297
}
 
298
 
 
299
/* API: get device info */
 
300
static pj_status_t qt_factory_get_dev_info(pjmedia_vid_dev_factory *f,
 
301
                                           unsigned index,
 
302
                                           pjmedia_vid_dev_info *info)
 
303
{
 
304
    struct qt_factory *qf = (struct qt_factory*)f;
 
305
 
 
306
    PJ_ASSERT_RETURN(index < qf->dev_count, PJMEDIA_EVID_INVDEV);
 
307
 
 
308
    pj_memcpy(info, &qf->dev_info[index].info, sizeof(*info));
 
309
 
 
310
    return PJ_SUCCESS;
 
311
}
 
312
 
 
313
/* API: create default device parameter */
 
314
static pj_status_t qt_factory_default_param(pj_pool_t *pool,
 
315
                                            pjmedia_vid_dev_factory *f,
 
316
                                            unsigned index,
 
317
                                            pjmedia_vid_dev_param *param)
 
318
{
 
319
    struct qt_factory *qf = (struct qt_factory*)f;
 
320
    struct qt_dev_info *di = &qf->dev_info[index];
 
321
 
 
322
    PJ_ASSERT_RETURN(index < qf->dev_count, PJMEDIA_EVID_INVDEV);
 
323
 
 
324
    PJ_UNUSED_ARG(pool);
 
325
 
 
326
    pj_bzero(param, sizeof(*param));
 
327
    param->dir = PJMEDIA_DIR_CAPTURE;
 
328
    param->cap_id = index;
 
329
    param->rend_id = PJMEDIA_VID_INVALID_DEV;
 
330
    param->flags = PJMEDIA_VID_DEV_CAP_FORMAT;
 
331
    param->clock_rate = DEFAULT_CLOCK_RATE;
 
332
    pj_memcpy(&param->fmt, &di->info.fmt[0], sizeof(param->fmt));
 
333
 
 
334
    return PJ_SUCCESS;
 
335
}
 
336
 
 
337
static qt_fmt_info* get_qt_format_info(pjmedia_format_id id)
 
338
{
 
339
    unsigned i;
 
340
    
 
341
    for (i = 0; i < PJ_ARRAY_SIZE(qt_fmts); i++) {
 
342
        if (qt_fmts[i].pjmedia_format == id)
 
343
            return &qt_fmts[i];
 
344
    }
 
345
    
 
346
    return NULL;
 
347
}
 
348
 
 
349
@implementation QTDelegate
 
350
- (void)captureOutput:(QTCaptureOutput *)captureOutput
 
351
                      didOutputVideoFrame:(CVImageBufferRef)videoFrame
 
352
                      withSampleBuffer:(QTSampleBuffer *)sampleBuffer
 
353
                      fromConnection:(QTCaptureConnection *)connection
 
354
{
 
355
    unsigned size = [sampleBuffer lengthForAllSamples];
 
356
    pjmedia_frame frame;
 
357
 
 
358
    if (!strm->is_running) {
 
359
        strm->cap_exited = PJ_TRUE;
 
360
        return;
 
361
    }
 
362
    
 
363
    if (strm->cap_thread_initialized == 0 || !pj_thread_is_registered())
 
364
    {
 
365
        pj_thread_register("qt_cap", strm->cap_thread_desc,
 
366
                           &strm->cap_thread);
 
367
        strm->cap_thread_initialized = 1;
 
368
        PJ_LOG(5,(THIS_FILE, "Capture thread started"));
 
369
    }
 
370
    
 
371
    if (!videoFrame)
 
372
        return;
 
373
    
 
374
    frame.type = PJMEDIA_FRAME_TYPE_VIDEO;
 
375
    frame.buf = [sampleBuffer bytesForAllSamples];
 
376
    frame.size = size;
 
377
    frame.bit_info = 0;
 
378
    frame.timestamp.u64 = strm->cap_frame_ts.u64;
 
379
    
 
380
    if (strm->vid_cb.capture_cb)
 
381
        (*strm->vid_cb.capture_cb)(&strm->base, strm->user_data, &frame);
 
382
    
 
383
    strm->cap_frame_ts.u64 += strm->cap_ts_inc;
 
384
}
 
385
 
 
386
- (void)run_func
 
387
{
 
388
    (*func)(strm);
 
389
}
 
390
 
 
391
@end
 
392
 
 
393
static void init_qt(struct qt_stream *strm)
 
394
{
 
395
    const pjmedia_video_format_detail *vfd;
 
396
    qt_fmt_info *qfi = get_qt_format_info(strm->param.fmt.id);
 
397
    BOOL success = NO;
 
398
    NSError *error;
 
399
    
 
400
    if (!qfi) {
 
401
        strm->status = PJMEDIA_EVID_BADFORMAT;
 
402
        return;
 
403
    }
 
404
    
 
405
    strm->cap_session = [[QTCaptureSession alloc] init];
 
406
    if (!strm->cap_session) {
 
407
        strm->status = PJ_ENOMEM;
 
408
        return;
 
409
    }
 
410
    
 
411
    /* Open video device */
 
412
    QTCaptureDevice *videoDevice = 
 
413
        [QTCaptureDevice deviceWithUniqueID:
 
414
                         [NSString stringWithCString:
 
415
                                   strm->qf->dev_info[strm->param.cap_id].dev_id
 
416
                                   encoding:
 
417
                                   [NSString defaultCStringEncoding]]];
 
418
    if (!videoDevice || ![videoDevice open:&error]) {
 
419
        strm->status = PJMEDIA_EVID_SYSERR;
 
420
        return;
 
421
    }
 
422
    
 
423
    /* Add the video device to the session as a device input */ 
 
424
    strm->dev_input = [[QTCaptureDeviceInput alloc] 
 
425
                       initWithDevice:videoDevice];
 
426
    success = [strm->cap_session addInput:strm->dev_input error:&error];
 
427
    if (!success) {
 
428
        strm->status = PJMEDIA_EVID_SYSERR;
 
429
        return;
 
430
    }
 
431
    
 
432
    strm->video_output = [[QTCaptureDecompressedVideoOutput alloc] init];
 
433
    success = [strm->cap_session addOutput:strm->video_output
 
434
                                 error:&error];
 
435
    if (!success) {
 
436
        strm->status = PJMEDIA_EVID_SYSERR;
 
437
        return;
 
438
    }
 
439
    
 
440
    vfd = pjmedia_format_get_video_format_detail(&strm->param.fmt,
 
441
                                                 PJ_TRUE);
 
442
    [strm->video_output setPixelBufferAttributes:
 
443
                        [NSDictionary dictionaryWithObjectsAndKeys:
 
444
                                      [NSNumber numberWithInt:qfi->qt_format],
 
445
                                      kCVPixelBufferPixelFormatTypeKey,
 
446
                                      [NSNumber numberWithInt:vfd->size.w],
 
447
                                      kCVPixelBufferWidthKey,
 
448
                                      [NSNumber numberWithInt:vfd->size.h],
 
449
                                      kCVPixelBufferHeightKey, nil]];
 
450
    
 
451
    pj_assert(vfd->fps.num);
 
452
    strm->cap_ts_inc = PJMEDIA_SPF2(strm->param.clock_rate, &vfd->fps, 1);
 
453
    
 
454
    if ([strm->video_output
 
455
         respondsToSelector:@selector(setMinimumVideoFrameInterval)])
 
456
    {
 
457
        [strm->video_output setMinimumVideoFrameInterval:
 
458
                            (1.0f * vfd->fps.denum / (double)vfd->fps.num)];
 
459
    }
 
460
    
 
461
    strm->qt_delegate = [[QTDelegate alloc]init];
 
462
    strm->qt_delegate->strm = strm;
 
463
    [strm->video_output setDelegate:strm->qt_delegate];
 
464
}    
 
465
 
 
466
static void run_func_on_main_thread(struct qt_stream *strm, func_ptr func)
 
467
{
 
468
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
469
    QTDelegate *delg = [[QTDelegate alloc] init];
 
470
    
 
471
    delg->strm = strm;
 
472
    delg->func = func;
 
473
    [delg performSelectorOnMainThread:@selector(run_func)
 
474
                           withObject:nil waitUntilDone:YES];
 
475
    
 
476
    CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
 
477
 
 
478
    [delg release];
 
479
    [pool release];    
 
480
}
 
481
 
 
482
/* API: create stream */
 
483
static pj_status_t qt_factory_create_stream(
 
484
                                        pjmedia_vid_dev_factory *f,
 
485
                                        pjmedia_vid_dev_param *param,
 
486
                                        const pjmedia_vid_dev_cb *cb,
 
487
                                        void *user_data,
 
488
                                        pjmedia_vid_dev_stream **p_vid_strm)
 
489
{
 
490
    struct qt_factory *qf = (struct qt_factory*)f;
 
491
    pj_pool_t *pool;
 
492
    struct qt_stream *strm;
 
493
    const pjmedia_video_format_info *vfi;
 
494
    pj_status_t status = PJ_SUCCESS;
 
495
 
 
496
    PJ_ASSERT_RETURN(f && param && p_vid_strm, PJ_EINVAL);
 
497
    PJ_ASSERT_RETURN(param->fmt.type == PJMEDIA_TYPE_VIDEO &&
 
498
                     param->fmt.detail_type == PJMEDIA_FORMAT_DETAIL_VIDEO &&
 
499
                     param->dir == PJMEDIA_DIR_CAPTURE,
 
500
                     PJ_EINVAL);
 
501
 
 
502
    vfi = pjmedia_get_video_format_info(NULL, param->fmt.id);
 
503
    if (!vfi)
 
504
        return PJMEDIA_EVID_BADFORMAT;
 
505
 
 
506
    /* Create and Initialize stream descriptor */
 
507
    pool = pj_pool_create(qf->pf, "qt-dev", 4000, 4000, NULL);
 
508
    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
 
509
 
 
510
    strm = PJ_POOL_ZALLOC_T(pool, struct qt_stream);
 
511
    pj_memcpy(&strm->param, param, sizeof(*param));
 
512
    strm->pool = pool;
 
513
    pj_memcpy(&strm->vid_cb, cb, sizeof(*cb));
 
514
    strm->user_data = user_data;
 
515
    strm->qf = qf;
 
516
 
 
517
    /* Create capture stream here */
 
518
    if (param->dir & PJMEDIA_DIR_CAPTURE) {        
 
519
        strm->status = PJ_SUCCESS;
 
520
        run_func_on_main_thread(strm, init_qt);
 
521
        if ((status = strm->status) != PJ_SUCCESS)
 
522
            goto on_error;
 
523
    }
 
524
    
 
525
    /* Apply the remaining settings */
 
526
    /*    
 
527
     if (param->flags & PJMEDIA_VID_DEV_CAP_INPUT_SCALE) {
 
528
        qt_stream_set_cap(&strm->base,
 
529
                          PJMEDIA_VID_DEV_CAP_INPUT_SCALE,
 
530
                          &param->fmt);
 
531
     }
 
532
     */
 
533
    /* Done */
 
534
    strm->base.op = &stream_op;
 
535
    *p_vid_strm = &strm->base;
 
536
    
 
537
    return PJ_SUCCESS;
 
538
    
 
539
on_error:
 
540
    qt_stream_destroy((pjmedia_vid_dev_stream *)strm);
 
541
    
 
542
    return status;
 
543
}
 
544
 
 
545
/* API: Get stream info. */
 
546
static pj_status_t qt_stream_get_param(pjmedia_vid_dev_stream *s,
 
547
                                       pjmedia_vid_dev_param *pi)
 
548
{
 
549
    struct qt_stream *strm = (struct qt_stream*)s;
 
550
 
 
551
    PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
 
552
 
 
553
    pj_memcpy(pi, &strm->param, sizeof(*pi));
 
554
 
 
555
/*    if (qt_stream_get_cap(s, PJMEDIA_VID_DEV_CAP_INPUT_SCALE,
 
556
                            &pi->fmt.info_size) == PJ_SUCCESS)
 
557
    {
 
558
        pi->flags |= PJMEDIA_VID_DEV_CAP_INPUT_SCALE;
 
559
    }
 
560
*/
 
561
    return PJ_SUCCESS;
 
562
}
 
563
 
 
564
/* API: get capability */
 
565
static pj_status_t qt_stream_get_cap(pjmedia_vid_dev_stream *s,
 
566
                                     pjmedia_vid_dev_cap cap,
 
567
                                     void *pval)
 
568
{
 
569
    struct qt_stream *strm = (struct qt_stream*)s;
 
570
 
 
571
    PJ_UNUSED_ARG(strm);
 
572
 
 
573
    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
 
574
 
 
575
    if (cap==PJMEDIA_VID_DEV_CAP_INPUT_SCALE)
 
576
    {
 
577
        return PJMEDIA_EVID_INVCAP;
 
578
//      return PJ_SUCCESS;
 
579
    } else {
 
580
        return PJMEDIA_EVID_INVCAP;
 
581
    }
 
582
}
 
583
 
 
584
/* API: set capability */
 
585
static pj_status_t qt_stream_set_cap(pjmedia_vid_dev_stream *s,
 
586
                                     pjmedia_vid_dev_cap cap,
 
587
                                     const void *pval)
 
588
{
 
589
    struct qt_stream *strm = (struct qt_stream*)s;
 
590
 
 
591
    PJ_UNUSED_ARG(strm);
 
592
 
 
593
    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
 
594
 
 
595
    if (cap==PJMEDIA_VID_DEV_CAP_INPUT_SCALE)
 
596
    {
 
597
        return PJ_SUCCESS;
 
598
    }
 
599
 
 
600
    return PJMEDIA_EVID_INVCAP;
 
601
}
 
602
 
 
603
static void start_qt(struct qt_stream *strm)
 
604
{
 
605
    [strm->cap_session startRunning];
 
606
}
 
607
 
 
608
static void stop_qt(struct qt_stream *strm)
 
609
{
 
610
    [strm->cap_session stopRunning];
 
611
}
 
612
 
 
613
/* API: Start stream. */
 
614
static pj_status_t qt_stream_start(pjmedia_vid_dev_stream *strm)
 
615
{
 
616
    struct qt_stream *stream = (struct qt_stream*)strm;
 
617
 
 
618
    PJ_UNUSED_ARG(stream);
 
619
 
 
620
    PJ_LOG(4, (THIS_FILE, "Starting qt video stream"));
 
621
 
 
622
    if (stream->cap_session) {
 
623
        run_func_on_main_thread(stream, start_qt);
 
624
    
 
625
        if (![stream->cap_session isRunning])
 
626
            return PJMEDIA_EVID_NOTREADY;
 
627
        
 
628
        stream->is_running = PJ_TRUE;
 
629
    }
 
630
 
 
631
    return PJ_SUCCESS;
 
632
}
 
633
 
 
634
/* API: Stop stream. */
 
635
static pj_status_t qt_stream_stop(pjmedia_vid_dev_stream *strm)
 
636
{
 
637
    struct qt_stream *stream = (struct qt_stream*)strm;
 
638
 
 
639
    PJ_UNUSED_ARG(stream);
 
640
 
 
641
    PJ_LOG(4, (THIS_FILE, "Stopping qt video stream"));
 
642
 
 
643
    if (stream->cap_session && [stream->cap_session isRunning]) {
 
644
        int i;
 
645
        
 
646
        stream->cap_exited = PJ_FALSE;
 
647
        run_func_on_main_thread(stream, stop_qt);
 
648
        
 
649
        stream->is_running = PJ_FALSE;
 
650
        for (i = 50; i >= 0 && !stream->cap_exited; i--) {
 
651
            pj_thread_sleep(10);
 
652
        }
 
653
    }
 
654
    
 
655
    return PJ_SUCCESS;
 
656
}
 
657
 
 
658
static void destroy_qt(struct qt_stream *strm)
 
659
{
 
660
    if (strm->dev_input && [[strm->dev_input device] isOpen])
 
661
        [[strm->dev_input device] close];
 
662
    
 
663
    if (strm->cap_session) {
 
664
        [strm->cap_session release];
 
665
        strm->cap_session = NULL;
 
666
    }
 
667
    if (strm->dev_input) {
 
668
        [strm->dev_input release];
 
669
        strm->dev_input = NULL;
 
670
    }
 
671
    if (strm->qt_delegate) {
 
672
        [strm->qt_delegate release];
 
673
        strm->qt_delegate = NULL;
 
674
    }
 
675
    if (strm->video_output) {
 
676
        [strm->video_output release];
 
677
        strm->video_output = NULL;
 
678
    }
 
679
}
 
680
 
 
681
/* API: Destroy stream. */
 
682
static pj_status_t qt_stream_destroy(pjmedia_vid_dev_stream *strm)
 
683
{
 
684
    struct qt_stream *stream = (struct qt_stream*)strm;
 
685
 
 
686
    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
 
687
 
 
688
    qt_stream_stop(strm);
 
689
 
 
690
    run_func_on_main_thread(stream, destroy_qt);
 
691
    
 
692
    pj_pool_release(stream->pool);
 
693
 
 
694
    return PJ_SUCCESS;
 
695
}
 
696
 
 
697
#endif  /* PJMEDIA_VIDEO_DEV_HAS_QT */