~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-01-07 14:51:16 UTC
  • mfrom: (4.3.5 sid)
  • Revision ID: package-import@ubuntu.com-20150107145116-yxnafinf4lrdvrmx
Tags: 1.4.1-0.1ubuntu1
* Merge with Debian, remaining changes:
 - Drop soprano, nepomuk build-dep
* Drop ubuntu patches, now upstream

Show diffs side-by-side

added added

removed removed

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