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

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* 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 */