~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): 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: 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 */