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

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjmedia/src/pjmedia-videodev/ios_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: ios_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_IOS
25
 
#include "Availability.h"
26
 
#ifdef __IPHONE_4_0
27
 
 
28
 
#import <UIKit/UIKit.h>
29
 
#import <AVFoundation/AVFoundation.h>
30
 
 
31
 
#define THIS_FILE               "ios_dev.c"
32
 
#define DEFAULT_CLOCK_RATE      90000
33
 
#define DEFAULT_WIDTH           480
34
 
#define DEFAULT_HEIGHT          360
35
 
#define DEFAULT_FPS             15
36
 
 
37
 
typedef struct ios_fmt_info
38
 
{
39
 
    pjmedia_format_id   pjmedia_format;
40
 
    UInt32              ios_format;
41
 
} ios_fmt_info;
42
 
 
43
 
static ios_fmt_info ios_fmts[] =
44
 
{
45
 
    {PJMEDIA_FORMAT_BGRA, kCVPixelFormatType_32BGRA} ,
46
 
};
47
 
 
48
 
/* qt device info */
49
 
struct ios_dev_info
50
 
{
51
 
    pjmedia_vid_dev_info         info;
52
 
};
53
 
 
54
 
/* qt factory */
55
 
struct ios_factory
56
 
{
57
 
    pjmedia_vid_dev_factory      base;
58
 
    pj_pool_t                   *pool;
59
 
    pj_pool_factory             *pf;
60
 
 
61
 
    unsigned                     dev_count;
62
 
    struct ios_dev_info         *dev_info;
63
 
};
64
 
 
65
 
@interface VOutDelegate: NSObject 
66
 
                         <AVCaptureVideoDataOutputSampleBufferDelegate>
67
 
{
68
 
@public
69
 
    struct ios_stream *stream;
70
 
}
71
 
@end
72
 
 
73
 
/* Video stream. */
74
 
struct ios_stream
75
 
{
76
 
    pjmedia_vid_dev_stream  base;               /**< Base stream       */
77
 
    pjmedia_vid_dev_param   param;              /**< Settings          */
78
 
    pj_pool_t              *pool;               /**< Memory pool       */
79
 
 
80
 
    pjmedia_vid_dev_cb      vid_cb;             /**< Stream callback   */
81
 
    void                   *user_data;          /**< Application data  */
82
 
 
83
 
    pjmedia_rect_size       size;
84
 
    pj_uint8_t              bpp;
85
 
    unsigned                bytes_per_row;
86
 
    unsigned                frame_size;
87
 
    
88
 
    AVCaptureSession            *cap_session;
89
 
    AVCaptureDeviceInput        *dev_input;
90
 
    AVCaptureVideoDataOutput    *video_output;
91
 
    VOutDelegate                *vout_delegate;
92
 
    
93
 
    UIImageView         *imgView;
94
 
    void                *buf;
95
 
    dispatch_queue_t     render_queue;
96
 
    
97
 
    pj_timestamp         frame_ts;
98
 
    unsigned             ts_inc;
99
 
};
100
 
 
101
 
 
102
 
/* Prototypes */
103
 
static pj_status_t ios_factory_init(pjmedia_vid_dev_factory *f);
104
 
static pj_status_t ios_factory_destroy(pjmedia_vid_dev_factory *f);
105
 
static pj_status_t ios_factory_refresh(pjmedia_vid_dev_factory *f);
106
 
static unsigned    ios_factory_get_dev_count(pjmedia_vid_dev_factory *f);
107
 
static pj_status_t ios_factory_get_dev_info(pjmedia_vid_dev_factory *f,
108
 
                                            unsigned index,
109
 
                                            pjmedia_vid_dev_info *info);
110
 
static pj_status_t ios_factory_default_param(pj_pool_t *pool,
111
 
                                             pjmedia_vid_dev_factory *f,
112
 
                                             unsigned index,
113
 
                                             pjmedia_vid_dev_param *param);
114
 
static pj_status_t ios_factory_create_stream(
115
 
                                        pjmedia_vid_dev_factory *f,
116
 
                                        pjmedia_vid_dev_param *param,
117
 
                                        const pjmedia_vid_dev_cb *cb,
118
 
                                        void *user_data,
119
 
                                        pjmedia_vid_dev_stream **p_vid_strm);
120
 
 
121
 
static pj_status_t ios_stream_get_param(pjmedia_vid_dev_stream *strm,
122
 
                                        pjmedia_vid_dev_param *param);
123
 
static pj_status_t ios_stream_get_cap(pjmedia_vid_dev_stream *strm,
124
 
                                      pjmedia_vid_dev_cap cap,
125
 
                                      void *value);
126
 
static pj_status_t ios_stream_set_cap(pjmedia_vid_dev_stream *strm,
127
 
                                      pjmedia_vid_dev_cap cap,
128
 
                                      const void *value);
129
 
static pj_status_t ios_stream_start(pjmedia_vid_dev_stream *strm);
130
 
static pj_status_t ios_stream_put_frame(pjmedia_vid_dev_stream *strm,
131
 
                                        const pjmedia_frame *frame);
132
 
static pj_status_t ios_stream_stop(pjmedia_vid_dev_stream *strm);
133
 
static pj_status_t ios_stream_destroy(pjmedia_vid_dev_stream *strm);
134
 
 
135
 
/* Operations */
136
 
static pjmedia_vid_dev_factory_op factory_op =
137
 
{
138
 
    &ios_factory_init,
139
 
    &ios_factory_destroy,
140
 
    &ios_factory_get_dev_count,
141
 
    &ios_factory_get_dev_info,
142
 
    &ios_factory_default_param,
143
 
    &ios_factory_create_stream,
144
 
    &ios_factory_refresh
145
 
};
146
 
 
147
 
static pjmedia_vid_dev_stream_op stream_op =
148
 
{
149
 
    &ios_stream_get_param,
150
 
    &ios_stream_get_cap,
151
 
    &ios_stream_set_cap,
152
 
    &ios_stream_start,
153
 
    NULL,
154
 
    &ios_stream_put_frame,
155
 
    &ios_stream_stop,
156
 
    &ios_stream_destroy
157
 
};
158
 
 
159
 
 
160
 
/****************************************************************************
161
 
 * Factory operations
162
 
 */
163
 
/*
164
 
 * Init ios_ video driver.
165
 
 */
166
 
pjmedia_vid_dev_factory* pjmedia_ios_factory(pj_pool_factory *pf)
167
 
{
168
 
    struct ios_factory *f;
169
 
    pj_pool_t *pool;
170
 
 
171
 
    pool = pj_pool_create(pf, "ios video", 512, 512, NULL);
172
 
    f = PJ_POOL_ZALLOC_T(pool, struct ios_factory);
173
 
    f->pf = pf;
174
 
    f->pool = pool;
175
 
    f->base.op = &factory_op;
176
 
 
177
 
    return &f->base;
178
 
}
179
 
 
180
 
 
181
 
/* API: init factory */
182
 
static pj_status_t ios_factory_init(pjmedia_vid_dev_factory *f)
183
 
{
184
 
    struct ios_factory *qf = (struct ios_factory*)f;
185
 
    struct ios_dev_info *qdi;
186
 
    unsigned i, l;
187
 
    
188
 
    /* Initialize input and output devices here */
189
 
    qf->dev_info = (struct ios_dev_info*)
190
 
                   pj_pool_calloc(qf->pool, 2,
191
 
                                  sizeof(struct ios_dev_info));
192
 
    
193
 
    qf->dev_count = 0;
194
 
    qdi = &qf->dev_info[qf->dev_count++];
195
 
    pj_bzero(qdi, sizeof(*qdi));
196
 
    strcpy(qdi->info.name, "iOS UIView");
197
 
    strcpy(qdi->info.driver, "iOS");        
198
 
    qdi->info.dir = PJMEDIA_DIR_RENDER;
199
 
    qdi->info.has_callback = PJ_FALSE;
200
 
    qdi->info.caps = PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW;
201
 
    
202
 
    if (NSClassFromString(@"AVCaptureSession")) {
203
 
        qdi = &qf->dev_info[qf->dev_count++];
204
 
        pj_bzero(qdi, sizeof(*qdi));
205
 
        strcpy(qdi->info.name, "iOS AVCapture");
206
 
        strcpy(qdi->info.driver, "iOS");            
207
 
        qdi->info.dir = PJMEDIA_DIR_CAPTURE;
208
 
        qdi->info.has_callback = PJ_TRUE;
209
 
    }
210
 
 
211
 
    for (i = 0; i < qf->dev_count; i++) {
212
 
        qdi = &qf->dev_info[i];
213
 
        qdi->info.fmt_cnt = PJ_ARRAY_SIZE(ios_fmts);        
214
 
        qdi->info.caps |= PJMEDIA_VID_DEV_CAP_FORMAT;
215
 
        
216
 
        for (l = 0; l < PJ_ARRAY_SIZE(ios_fmts); l++) {
217
 
            pjmedia_format *fmt = &qdi->info.fmt[l];
218
 
            pjmedia_format_init_video(fmt,
219
 
                                      ios_fmts[l].pjmedia_format,
220
 
                                      DEFAULT_WIDTH,
221
 
                                      DEFAULT_HEIGHT,
222
 
                                      DEFAULT_FPS, 1);  
223
 
        }
224
 
    }
225
 
    
226
 
    PJ_LOG(4, (THIS_FILE, "iOS video initialized with %d devices",
227
 
               qf->dev_count));
228
 
    
229
 
    return PJ_SUCCESS;
230
 
}
231
 
 
232
 
/* API: destroy factory */
233
 
static pj_status_t ios_factory_destroy(pjmedia_vid_dev_factory *f)
234
 
{
235
 
    struct ios_factory *qf = (struct ios_factory*)f;
236
 
    pj_pool_t *pool = qf->pool;
237
 
 
238
 
    qf->pool = NULL;
239
 
    pj_pool_release(pool);
240
 
 
241
 
    return PJ_SUCCESS;
242
 
}
243
 
 
244
 
/* API: refresh the list of devices */
245
 
static pj_status_t ios_factory_refresh(pjmedia_vid_dev_factory *f)
246
 
{
247
 
    PJ_UNUSED_ARG(f);
248
 
    return PJ_SUCCESS;
249
 
}
250
 
 
251
 
/* API: get number of devices */
252
 
static unsigned ios_factory_get_dev_count(pjmedia_vid_dev_factory *f)
253
 
{
254
 
    struct ios_factory *qf = (struct ios_factory*)f;
255
 
    return qf->dev_count;
256
 
}
257
 
 
258
 
/* API: get device info */
259
 
static pj_status_t ios_factory_get_dev_info(pjmedia_vid_dev_factory *f,
260
 
                                            unsigned index,
261
 
                                            pjmedia_vid_dev_info *info)
262
 
{
263
 
    struct ios_factory *qf = (struct ios_factory*)f;
264
 
 
265
 
    PJ_ASSERT_RETURN(index < qf->dev_count, PJMEDIA_EVID_INVDEV);
266
 
 
267
 
    pj_memcpy(info, &qf->dev_info[index].info, sizeof(*info));
268
 
 
269
 
    return PJ_SUCCESS;
270
 
}
271
 
 
272
 
/* API: create default device parameter */
273
 
static pj_status_t ios_factory_default_param(pj_pool_t *pool,
274
 
                                             pjmedia_vid_dev_factory *f,
275
 
                                             unsigned index,
276
 
                                             pjmedia_vid_dev_param *param)
277
 
{
278
 
    struct ios_factory *qf = (struct ios_factory*)f;
279
 
    struct ios_dev_info *di = &qf->dev_info[index];
280
 
 
281
 
    PJ_ASSERT_RETURN(index < qf->dev_count, PJMEDIA_EVID_INVDEV);
282
 
 
283
 
    PJ_UNUSED_ARG(pool);
284
 
 
285
 
    pj_bzero(param, sizeof(*param));
286
 
    if (di->info.dir & PJMEDIA_DIR_CAPTURE) {
287
 
        param->dir = PJMEDIA_DIR_CAPTURE;
288
 
        param->cap_id = index;
289
 
        param->rend_id = PJMEDIA_VID_INVALID_DEV;
290
 
    } else if (di->info.dir & PJMEDIA_DIR_RENDER) {
291
 
        param->dir = PJMEDIA_DIR_RENDER;
292
 
        param->rend_id = index;
293
 
        param->cap_id = PJMEDIA_VID_INVALID_DEV;
294
 
    } else {
295
 
        return PJMEDIA_EVID_INVDEV;
296
 
    }
297
 
    
298
 
    param->flags = PJMEDIA_VID_DEV_CAP_FORMAT;
299
 
    param->clock_rate = DEFAULT_CLOCK_RATE;
300
 
    pj_memcpy(&param->fmt, &di->info.fmt[0], sizeof(param->fmt));
301
 
 
302
 
    return PJ_SUCCESS;
303
 
}
304
 
 
305
 
@implementation VOutDelegate
306
 
- (void)update_image
307
 
{    
308
 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
309
 
    
310
 
    /* Create a device-dependent RGB color space */
311
 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
312
 
    
313
 
    /* Create a bitmap graphics context with the sample buffer data */
314
 
    CGContextRef context = 
315
 
        CGBitmapContextCreate(stream->buf, stream->size.w, stream->size.h, 8,
316
 
                              stream->bytes_per_row, colorSpace,
317
 
                              kCGBitmapByteOrder32Little |
318
 
                              kCGImageAlphaPremultipliedFirst);
319
 
    
320
 
    /**
321
 
     * Create a Quartz image from the pixel data in the bitmap graphics
322
 
     * context
323
 
     */
324
 
    CGImageRef quartzImage = CGBitmapContextCreateImage(context); 
325
 
    
326
 
    /* Free up the context and color space */
327
 
    CGContextRelease(context); 
328
 
    CGColorSpaceRelease(colorSpace);
329
 
    
330
 
    /* Create an image object from the Quartz image */
331
 
    UIImage *image = [UIImage imageWithCGImage:quartzImage scale:1.0 
332
 
                              orientation:UIImageOrientationRight];
333
 
    
334
 
    /* Release the Quartz image */
335
 
    CGImageRelease(quartzImage);
336
 
    
337
 
    dispatch_async(dispatch_get_main_queue(),
338
 
                   ^{[stream->imgView setImage:image];});
339
 
    /*
340
 
    [stream->imgView performSelectorOnMainThread:@selector(setImage:)
341
 
                     withObject:image waitUntilDone:NO];
342
 
     */
343
 
    
344
 
    [pool release];
345
 
}    
346
 
 
347
 
- (void)captureOutput:(AVCaptureOutput *)captureOutput 
348
 
                      didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
349
 
                      fromConnection:(AVCaptureConnection *)connection
350
 
{
351
 
    pjmedia_frame frame;
352
 
    CVImageBufferRef imageBuffer;
353
 
 
354
 
    if (!sampleBuffer)
355
 
        return;
356
 
    
357
 
    /* Get a CMSampleBuffer's Core Video image buffer for the media data */
358
 
    imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
359
 
    
360
 
    /* Lock the base address of the pixel buffer */
361
 
    CVPixelBufferLockBaseAddress(imageBuffer, 0); 
362
 
    
363
 
    frame.type = PJMEDIA_FRAME_TYPE_VIDEO;
364
 
    frame.buf = CVPixelBufferGetBaseAddress(imageBuffer);
365
 
    frame.size = stream->frame_size;
366
 
    frame.bit_info = 0;
367
 
    frame.timestamp.u64 = stream->frame_ts.u64;
368
 
    
369
 
    if (stream->vid_cb.capture_cb)
370
 
        (*stream->vid_cb.capture_cb)(&stream->base, stream->user_data, &frame);
371
 
 
372
 
    stream->frame_ts.u64 += stream->ts_inc;
373
 
    
374
 
    /* Unlock the pixel buffer */
375
 
    CVPixelBufferUnlockBaseAddress(imageBuffer,0);
376
 
}
377
 
@end
378
 
 
379
 
static ios_fmt_info* get_ios_format_info(pjmedia_format_id id)
380
 
{
381
 
    unsigned i;
382
 
    
383
 
    for (i = 0; i < PJ_ARRAY_SIZE(ios_fmts); i++) {
384
 
        if (ios_fmts[i].pjmedia_format == id)
385
 
            return &ios_fmts[i];
386
 
    }
387
 
    
388
 
    return NULL;
389
 
}
390
 
 
391
 
/* API: create stream */
392
 
static pj_status_t ios_factory_create_stream(
393
 
                                        pjmedia_vid_dev_factory *f,
394
 
                                        pjmedia_vid_dev_param *param,
395
 
                                        const pjmedia_vid_dev_cb *cb,
396
 
                                        void *user_data,
397
 
                                        pjmedia_vid_dev_stream **p_vid_strm)
398
 
{
399
 
    struct ios_factory *qf = (struct ios_factory*)f;
400
 
    pj_pool_t *pool;
401
 
    struct ios_stream *strm;
402
 
    const pjmedia_video_format_detail *vfd;
403
 
    const pjmedia_video_format_info *vfi;
404
 
    pj_status_t status = PJ_SUCCESS;
405
 
    ios_fmt_info *ifi = get_ios_format_info(param->fmt.id);
406
 
    NSError *error;
407
 
 
408
 
    PJ_ASSERT_RETURN(f && param && p_vid_strm, PJ_EINVAL);
409
 
    PJ_ASSERT_RETURN(param->fmt.type == PJMEDIA_TYPE_VIDEO &&
410
 
                     param->fmt.detail_type == PJMEDIA_FORMAT_DETAIL_VIDEO &&
411
 
                     (param->dir == PJMEDIA_DIR_CAPTURE ||
412
 
                     param->dir == PJMEDIA_DIR_RENDER),
413
 
                     PJ_EINVAL);
414
 
 
415
 
    if (!(ifi = get_ios_format_info(param->fmt.id)))
416
 
        return PJMEDIA_EVID_BADFORMAT;
417
 
    
418
 
    vfi = pjmedia_get_video_format_info(NULL, param->fmt.id);
419
 
    if (!vfi)
420
 
        return PJMEDIA_EVID_BADFORMAT;
421
 
 
422
 
    /* Create and Initialize stream descriptor */
423
 
    pool = pj_pool_create(qf->pf, "ios-dev", 4000, 4000, NULL);
424
 
    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
425
 
 
426
 
    strm = PJ_POOL_ZALLOC_T(pool, struct ios_stream);
427
 
    pj_memcpy(&strm->param, param, sizeof(*param));
428
 
    strm->pool = pool;
429
 
    pj_memcpy(&strm->vid_cb, cb, sizeof(*cb));
430
 
    strm->user_data = user_data;
431
 
 
432
 
    vfd = pjmedia_format_get_video_format_detail(&strm->param.fmt, PJ_TRUE);
433
 
    pj_memcpy(&strm->size, &vfd->size, sizeof(vfd->size));
434
 
    strm->bpp = vfi->bpp;
435
 
    strm->bytes_per_row = strm->size.w * strm->bpp / 8;
436
 
    strm->frame_size = strm->bytes_per_row * strm->size.h;
437
 
    strm->ts_inc = PJMEDIA_SPF2(param->clock_rate, &vfd->fps, 1);
438
 
 
439
 
    if (param->dir & PJMEDIA_DIR_CAPTURE) {
440
 
        /* Create capture stream here */
441
 
        strm->cap_session = [[AVCaptureSession alloc] init];
442
 
        if (!strm->cap_session) {
443
 
            status = PJ_ENOMEM;
444
 
            goto on_error;
445
 
        }
446
 
        strm->cap_session.sessionPreset = AVCaptureSessionPresetMedium;
447
 
        
448
 
        /* Open video device */
449
 
        AVCaptureDevice *videoDevice = 
450
 
            [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
451
 
        if (!videoDevice) {
452
 
            status = PJMEDIA_EVID_SYSERR;
453
 
            goto on_error;
454
 
        }
455
 
        
456
 
        /* Add the video device to the session as a device input */     
457
 
        strm->dev_input = [AVCaptureDeviceInput 
458
 
                           deviceInputWithDevice:videoDevice
459
 
                           error: &error];
460
 
        if (!strm->dev_input) {
461
 
            status = PJMEDIA_EVID_SYSERR;
462
 
            goto on_error;
463
 
        }
464
 
        [strm->cap_session addInput:strm->dev_input];
465
 
        
466
 
        strm->video_output = [[[AVCaptureVideoDataOutput alloc] init]
467
 
                              autorelease];
468
 
        if (!strm->video_output) {
469
 
            status = PJMEDIA_EVID_SYSERR;
470
 
            goto on_error;
471
 
        }
472
 
        [strm->cap_session addOutput:strm->video_output];
473
 
        
474
 
        /* Configure the video output */
475
 
        strm->vout_delegate = [VOutDelegate alloc];
476
 
        strm->vout_delegate->stream = strm;
477
 
        dispatch_queue_t queue = dispatch_queue_create("myQueue", NULL);
478
 
        [strm->video_output setSampleBufferDelegate:strm->vout_delegate
479
 
                            queue:queue];
480
 
        dispatch_release(queue);        
481
 
        
482
 
        strm->video_output.videoSettings =
483
 
            [NSDictionary dictionaryWithObjectsAndKeys:
484
 
                          [NSNumber numberWithInt:ifi->ios_format],
485
 
                          kCVPixelBufferPixelFormatTypeKey,
486
 
                          [NSNumber numberWithInt: vfd->size.w],
487
 
                          kCVPixelBufferWidthKey,
488
 
                          [NSNumber numberWithInt: vfd->size.h],
489
 
                          kCVPixelBufferHeightKey, nil];
490
 
        strm->video_output.minFrameDuration = CMTimeMake(vfd->fps.denum,
491
 
                                                         vfd->fps.num); 
492
 
    } else if (param->dir & PJMEDIA_DIR_RENDER) {
493
 
        /* Create renderer stream here */
494
 
        /* Get the main window */
495
 
        UIWindow *window = [[UIApplication sharedApplication] keyWindow];
496
 
        
497
 
        if (param->flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW &&
498
 
            param->window.info.ios.window)
499
 
            window = (UIWindow *)param->window.info.ios.window;
500
 
        
501
 
        pj_assert(window);
502
 
        strm->imgView = [[UIImageView alloc] initWithFrame:[window bounds]];
503
 
        if (!strm->imgView) {
504
 
            status = PJ_ENOMEM;
505
 
            goto on_error;
506
 
        }
507
 
        [window addSubview:strm->imgView];
508
 
        
509
 
        if (!strm->vout_delegate) {
510
 
            strm->vout_delegate = [VOutDelegate alloc];
511
 
            strm->vout_delegate->stream = strm;
512
 
        }
513
 
        
514
 
        strm->render_queue = dispatch_queue_create("com.pjsip.render_queue",
515
 
                                                   NULL);
516
 
        if (!strm->render_queue)
517
 
            goto on_error;
518
 
        
519
 
        strm->buf = pj_pool_alloc(pool, strm->frame_size);
520
 
    }    
521
 
    
522
 
    /* Apply the remaining settings */
523
 
    /*    
524
 
     if (param->flags & PJMEDIA_VID_DEV_CAP_INPUT_SCALE) {
525
 
        ios_stream_set_cap(&strm->base,
526
 
                          PJMEDIA_VID_DEV_CAP_INPUT_SCALE,
527
 
                          &param->fmt);
528
 
     }
529
 
     */
530
 
    /* Done */
531
 
    strm->base.op = &stream_op;
532
 
    *p_vid_strm = &strm->base;
533
 
    
534
 
    return PJ_SUCCESS;
535
 
    
536
 
on_error:
537
 
    ios_stream_destroy((pjmedia_vid_dev_stream *)strm);
538
 
    
539
 
    return status;
540
 
}
541
 
 
542
 
/* API: Get stream info. */
543
 
static pj_status_t ios_stream_get_param(pjmedia_vid_dev_stream *s,
544
 
                                        pjmedia_vid_dev_param *pi)
545
 
{
546
 
    struct ios_stream *strm = (struct ios_stream*)s;
547
 
 
548
 
    PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
549
 
 
550
 
    pj_memcpy(pi, &strm->param, sizeof(*pi));
551
 
 
552
 
/*    if (ios_stream_get_cap(s, PJMEDIA_VID_DEV_CAP_INPUT_SCALE,
553
 
                            &pi->fmt.info_size) == PJ_SUCCESS)
554
 
    {
555
 
        pi->flags |= PJMEDIA_VID_DEV_CAP_INPUT_SCALE;
556
 
    }
557
 
*/
558
 
    return PJ_SUCCESS;
559
 
}
560
 
 
561
 
/* API: get capability */
562
 
static pj_status_t ios_stream_get_cap(pjmedia_vid_dev_stream *s,
563
 
                                      pjmedia_vid_dev_cap cap,
564
 
                                      void *pval)
565
 
{
566
 
    struct ios_stream *strm = (struct ios_stream*)s;
567
 
 
568
 
    PJ_UNUSED_ARG(strm);
569
 
 
570
 
    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
571
 
 
572
 
    if (cap==PJMEDIA_VID_DEV_CAP_INPUT_SCALE)
573
 
    {
574
 
        return PJMEDIA_EVID_INVCAP;
575
 
//      return PJ_SUCCESS;
576
 
    } else {
577
 
        return PJMEDIA_EVID_INVCAP;
578
 
    }
579
 
}
580
 
 
581
 
/* API: set capability */
582
 
static pj_status_t ios_stream_set_cap(pjmedia_vid_dev_stream *s,
583
 
                                      pjmedia_vid_dev_cap cap,
584
 
                                      const void *pval)
585
 
{
586
 
    struct ios_stream *strm = (struct ios_stream*)s;
587
 
 
588
 
    PJ_UNUSED_ARG(strm);
589
 
 
590
 
    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
591
 
 
592
 
    if (cap==PJMEDIA_VID_DEV_CAP_INPUT_SCALE)
593
 
    {
594
 
        return PJ_SUCCESS;
595
 
    }
596
 
 
597
 
    return PJMEDIA_EVID_INVCAP;
598
 
}
599
 
 
600
 
/* API: Start stream. */
601
 
static pj_status_t ios_stream_start(pjmedia_vid_dev_stream *strm)
602
 
{
603
 
    struct ios_stream *stream = (struct ios_stream*)strm;
604
 
 
605
 
    PJ_UNUSED_ARG(stream);
606
 
 
607
 
    PJ_LOG(4, (THIS_FILE, "Starting ios video stream"));
608
 
 
609
 
    if (stream->cap_session) {
610
 
        [stream->cap_session startRunning];
611
 
    
612
 
        if (![stream->cap_session isRunning])
613
 
            return PJ_EUNKNOWN;
614
 
    }
615
 
    
616
 
    return PJ_SUCCESS;
617
 
}
618
 
 
619
 
 
620
 
/* API: Put frame from stream */
621
 
static pj_status_t ios_stream_put_frame(pjmedia_vid_dev_stream *strm,
622
 
                                        const pjmedia_frame *frame)
623
 
{
624
 
    struct ios_stream *stream = (struct ios_stream*)strm;
625
 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
626
 
    
627
 
    pj_assert(stream->frame_size >= frame->size);
628
 
    pj_memcpy(stream->buf, frame->buf, frame->size);
629
 
    /* Perform video display in a background thread */
630
 
/*   
631
 
    [stream->vout_delegate update_image];
632
 
    [NSThread detachNewThreadSelector:@selector(update_image)
633
 
              toTarget:stream->vout_delegate withObject:nil];
634
 
*/
635
 
    dispatch_async(stream->render_queue,
636
 
                   ^{[stream->vout_delegate update_image];});
637
 
    
638
 
    [pool release];
639
 
    
640
 
    return PJ_SUCCESS;
641
 
}
642
 
 
643
 
/* API: Stop stream. */
644
 
static pj_status_t ios_stream_stop(pjmedia_vid_dev_stream *strm)
645
 
{
646
 
    struct ios_stream *stream = (struct ios_stream*)strm;
647
 
 
648
 
    PJ_UNUSED_ARG(stream);
649
 
 
650
 
    PJ_LOG(4, (THIS_FILE, "Stopping ios video stream"));
651
 
 
652
 
    if (stream->cap_session && [stream->cap_session isRunning])
653
 
        [stream->cap_session stopRunning];
654
 
    
655
 
    return PJ_SUCCESS;
656
 
}
657
 
 
658
 
 
659
 
/* API: Destroy stream. */
660
 
static pj_status_t ios_stream_destroy(pjmedia_vid_dev_stream *strm)
661
 
{
662
 
    struct ios_stream *stream = (struct ios_stream*)strm;
663
 
 
664
 
    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
665
 
 
666
 
    ios_stream_stop(strm);
667
 
    
668
 
    if (stream->imgView) {
669
 
        [stream->imgView removeFromSuperview];
670
 
        [stream->imgView release];
671
 
        stream->imgView = NULL;
672
 
    }
673
 
 
674
 
    if (stream->cap_session) {
675
 
        [stream->cap_session release];
676
 
        stream->cap_session = NULL;
677
 
    }    
678
 
/*    if (stream->dev_input) {
679
 
        [stream->dev_input release];
680
 
        stream->dev_input = NULL;
681
 
    }
682
 
*/ 
683
 
    if (stream->vout_delegate) {
684
 
        [stream->vout_delegate release];
685
 
        stream->vout_delegate = NULL;
686
 
    }
687
 
/*    if (stream->video_output) {
688
 
        [stream->video_output release];
689
 
        stream->video_output = NULL;
690
 
    }
691
 
*/
692
 
    if (stream->render_queue) {
693
 
        dispatch_release(stream->render_queue);
694
 
        stream->render_queue = NULL;
695
 
    }
696
 
 
697
 
    pj_pool_release(stream->pool);
698
 
 
699
 
    return PJ_SUCCESS;
700
 
}
701
 
 
702
 
#endif
703
 
#endif  /* PJMEDIA_VIDEO_DEV_HAS_IOS */