blob: 0d2c4b84d36eaa0327315110e079a589ad6fd91c [file] [log] [blame]
Sauw Ming6e6c2152010-12-14 13:03:10 +00001/* $Id$ */
2/*
3 * Copyright (C) 2008-2010 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 9000
33#define DEFAULT_WIDTH 480
34#define DEFAULT_HEIGHT 360
35#define DEFAULT_FPS 15
36
37typedef struct ios_fmt_info
38{
39 pjmedia_format_id pjmedia_format;
40 UInt32 ios_format;
41} ios_fmt_info;
42
43static ios_fmt_info ios_fmts[] =
44{
45 {PJMEDIA_FORMAT_BGRA, kCVPixelFormatType_32BGRA} ,
46};
47
48/* qt device info */
49struct ios_dev_info
50{
51 pjmedia_vid_dev_info info;
52};
53
54/* qt factory */
55struct 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. */
74struct ios_stream
75{
Sauw Mingb93e6882011-03-19 05:33:21 +000076 pjmedia_vid_dev_stream base; /**< Base stream */
77 pjmedia_vid_param param; /**< Settings */
78 pj_pool_t *pool; /**< Memory pool */
Sauw Ming6e6c2152010-12-14 13:03:10 +000079
Sauw Mingb93e6882011-03-19 05:33:21 +000080 pjmedia_vid_cb vid_cb; /**< Stream callback */
81 void *user_data; /**< Application data */
Sauw Ming6e6c2152010-12-14 13:03:10 +000082
Sauw Mingb93e6882011-03-19 05:33:21 +000083 pjmedia_rect_size size;
84 pj_uint8_t bpp;
85 unsigned bytes_per_row;
86 unsigned frame_size;
Sauw Ming6e6c2152010-12-14 13:03:10 +000087
88 AVCaptureSession *cap_session;
89 AVCaptureDeviceInput *dev_input;
90 AVCaptureVideoDataOutput *video_output;
91 VOutDelegate *vout_delegate;
92
93 UIImageView *imgView;
94 void *buf;
Benny Prijono349037b2011-03-17 11:25:19 +000095
96 pj_timestamp frame_ts;
97 unsigned ts_inc;
Sauw Ming6e6c2152010-12-14 13:03:10 +000098};
99
100
101/* Prototypes */
102static pj_status_t ios_factory_init(pjmedia_vid_dev_factory *f);
103static pj_status_t ios_factory_destroy(pjmedia_vid_dev_factory *f);
104static unsigned ios_factory_get_dev_count(pjmedia_vid_dev_factory *f);
105static pj_status_t ios_factory_get_dev_info(pjmedia_vid_dev_factory *f,
106 unsigned index,
107 pjmedia_vid_dev_info *info);
108static pj_status_t ios_factory_default_param(pj_pool_t *pool,
109 pjmedia_vid_dev_factory *f,
110 unsigned index,
111 pjmedia_vid_param *param);
Sauw Mingb93e6882011-03-19 05:33:21 +0000112static pj_status_t ios_factory_create_stream(
113 pjmedia_vid_dev_factory *f,
114 const pjmedia_vid_param *param,
115 const pjmedia_vid_cb *cb,
116 void *user_data,
117 pjmedia_vid_dev_stream **p_vid_strm);
Sauw Ming6e6c2152010-12-14 13:03:10 +0000118
Sauw Mingb93e6882011-03-19 05:33:21 +0000119static pj_status_t ios_stream_get_param(pjmedia_vid_dev_stream *strm,
Sauw Ming6e6c2152010-12-14 13:03:10 +0000120 pjmedia_vid_param *param);
Sauw Mingb93e6882011-03-19 05:33:21 +0000121static pj_status_t ios_stream_get_cap(pjmedia_vid_dev_stream *strm,
Sauw Ming6e6c2152010-12-14 13:03:10 +0000122 pjmedia_vid_dev_cap cap,
123 void *value);
Sauw Mingb93e6882011-03-19 05:33:21 +0000124static pj_status_t ios_stream_set_cap(pjmedia_vid_dev_stream *strm,
Sauw Ming6e6c2152010-12-14 13:03:10 +0000125 pjmedia_vid_dev_cap cap,
126 const void *value);
Sauw Mingb93e6882011-03-19 05:33:21 +0000127static pj_status_t ios_stream_start(pjmedia_vid_dev_stream *strm);
128static pj_status_t ios_stream_put_frame(pjmedia_vid_dev_stream *strm,
Sauw Ming6e6c2152010-12-14 13:03:10 +0000129 const pjmedia_frame *frame);
Sauw Mingb93e6882011-03-19 05:33:21 +0000130static pj_status_t ios_stream_stop(pjmedia_vid_dev_stream *strm);
131static pj_status_t ios_stream_destroy(pjmedia_vid_dev_stream *strm);
Sauw Ming6e6c2152010-12-14 13:03:10 +0000132
133/* Operations */
134static pjmedia_vid_dev_factory_op factory_op =
135{
136 &ios_factory_init,
137 &ios_factory_destroy,
138 &ios_factory_get_dev_count,
139 &ios_factory_get_dev_info,
140 &ios_factory_default_param,
141 &ios_factory_create_stream
142};
143
Sauw Mingb93e6882011-03-19 05:33:21 +0000144static pjmedia_vid_dev_stream_op stream_op =
Sauw Ming6e6c2152010-12-14 13:03:10 +0000145{
146 &ios_stream_get_param,
147 &ios_stream_get_cap,
148 &ios_stream_set_cap,
149 &ios_stream_start,
150 NULL,
151 &ios_stream_put_frame,
152 &ios_stream_stop,
153 &ios_stream_destroy
154};
155
156
157/****************************************************************************
158 * Factory operations
159 */
160/*
161 * Init ios_ video driver.
162 */
163pjmedia_vid_dev_factory* pjmedia_ios_factory(pj_pool_factory *pf)
164{
165 struct ios_factory *f;
166 pj_pool_t *pool;
167
168 pool = pj_pool_create(pf, "ios video", 512, 512, NULL);
169 f = PJ_POOL_ZALLOC_T(pool, struct ios_factory);
170 f->pf = pf;
171 f->pool = pool;
172 f->base.op = &factory_op;
173
174 return &f->base;
175}
176
177
178/* API: init factory */
179static pj_status_t ios_factory_init(pjmedia_vid_dev_factory *f)
180{
181 struct ios_factory *qf = (struct ios_factory*)f;
182 struct ios_dev_info *qdi;
183 unsigned i, l;
184
185 /* Initialize input and output devices here */
186 qf->dev_info = (struct ios_dev_info*)
187 pj_pool_calloc(qf->pool, 2,
188 sizeof(struct ios_dev_info));
189
190 qf->dev_count = 0;
191 qdi = &qf->dev_info[qf->dev_count++];
192 pj_bzero(qdi, sizeof(*qdi));
193 strcpy(qdi->info.name, "iOS UIView");
194 strcpy(qdi->info.driver, "iOS");
195 qdi->info.dir = PJMEDIA_DIR_RENDER;
Sauw Mingab494302010-12-17 13:17:23 +0000196 qdi->info.has_callback = PJ_FALSE;
197 qdi->info.caps = PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW;
Sauw Ming6e6c2152010-12-14 13:03:10 +0000198
199 if (NSClassFromString(@"AVCaptureSession")) {
200 qdi = &qf->dev_info[qf->dev_count++];
201 pj_bzero(qdi, sizeof(*qdi));
202 strcpy(qdi->info.name, "iOS AVCapture");
203 strcpy(qdi->info.driver, "iOS");
204 qdi->info.dir = PJMEDIA_DIR_CAPTURE;
205 qdi->info.has_callback = PJ_TRUE;
206 }
207
208 for (i = 0; i < qf->dev_count; i++) {
209 qdi = &qf->dev_info[i];
210 qdi->info.fmt_cnt = PJ_ARRAY_SIZE(ios_fmts);
Sauw Mingab494302010-12-17 13:17:23 +0000211 qdi->info.caps |= PJMEDIA_VID_DEV_CAP_FORMAT;
Sauw Ming6e6c2152010-12-14 13:03:10 +0000212 qdi->info.fmt = (pjmedia_format*)
213 pj_pool_calloc(qf->pool, qdi->info.fmt_cnt,
214 sizeof(pjmedia_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 */
233static 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: get number of devices */
245static unsigned ios_factory_get_dev_count(pjmedia_vid_dev_factory *f)
246{
247 struct ios_factory *qf = (struct ios_factory*)f;
248 return qf->dev_count;
249}
250
251/* API: get device info */
252static pj_status_t ios_factory_get_dev_info(pjmedia_vid_dev_factory *f,
253 unsigned index,
254 pjmedia_vid_dev_info *info)
255{
256 struct ios_factory *qf = (struct ios_factory*)f;
257
258 PJ_ASSERT_RETURN(index < qf->dev_count, PJMEDIA_EVID_INVDEV);
259
260 pj_memcpy(info, &qf->dev_info[index].info, sizeof(*info));
261
262 return PJ_SUCCESS;
263}
264
265/* API: create default device parameter */
266static pj_status_t ios_factory_default_param(pj_pool_t *pool,
267 pjmedia_vid_dev_factory *f,
268 unsigned index,
269 pjmedia_vid_param *param)
270{
271 struct ios_factory *qf = (struct ios_factory*)f;
272 struct ios_dev_info *di = &qf->dev_info[index];
273
274 PJ_ASSERT_RETURN(index < qf->dev_count, PJMEDIA_EVID_INVDEV);
275
276 PJ_UNUSED_ARG(pool);
277
278 pj_bzero(param, sizeof(*param));
279 if (di->info.dir & PJMEDIA_DIR_CAPTURE_RENDER) {
280 param->dir = PJMEDIA_DIR_CAPTURE_RENDER;
281 param->cap_id = index;
282 param->rend_id = index;
283 } else if (di->info.dir & PJMEDIA_DIR_CAPTURE) {
284 param->dir = PJMEDIA_DIR_CAPTURE;
285 param->cap_id = index;
286 param->rend_id = PJMEDIA_VID_INVALID_DEV;
287 } else if (di->info.dir & PJMEDIA_DIR_RENDER) {
288 param->dir = PJMEDIA_DIR_RENDER;
289 param->rend_id = index;
290 param->cap_id = PJMEDIA_VID_INVALID_DEV;
291 } else {
292 return PJMEDIA_EVID_INVDEV;
293 }
294
295 param->flags = PJMEDIA_VID_DEV_CAP_FORMAT;
296 param->clock_rate = DEFAULT_CLOCK_RATE;
Sauw Ming6e6c2152010-12-14 13:03:10 +0000297 pj_memcpy(&param->fmt, &di->info.fmt[0], sizeof(param->fmt));
298
299 return PJ_SUCCESS;
300}
301
302@implementation VOutDelegate
303- (void)update_image
304{
305 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
306
307 /* Create a device-dependent RGB color space */
308 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
309
310 /* Create a bitmap graphics context with the sample buffer data */
311 CGContextRef context =
312 CGBitmapContextCreate(stream->buf, stream->size.w, stream->size.h, 8,
313 stream->bytes_per_row, colorSpace,
314 kCGBitmapByteOrder32Little |
315 kCGImageAlphaPremultipliedFirst);
316
317 /**
318 * Create a Quartz image from the pixel data in the bitmap graphics
319 * context
320 */
321 CGImageRef quartzImage = CGBitmapContextCreateImage(context);
322
323 /* Free up the context and color space */
324 CGContextRelease(context);
325 CGColorSpaceRelease(colorSpace);
326
327 /* Create an image object from the Quartz image */
328 UIImage *image = [UIImage imageWithCGImage:quartzImage scale:1.0
329 orientation:UIImageOrientationRight];
330
331 /* Release the Quartz image */
332 CGImageRelease(quartzImage);
333
Sauw Mingab494302010-12-17 13:17:23 +0000334 [stream->imgView performSelectorOnMainThread:@selector(setImage:)
335 withObject:image waitUntilDone:NO];
Sauw Ming6e6c2152010-12-14 13:03:10 +0000336
337 [pool release];
338}
339
340- (void)captureOutput:(AVCaptureOutput *)captureOutput
341 didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
342 fromConnection:(AVCaptureConnection *)connection
343{
344 pjmedia_frame frame;
345 CVImageBufferRef imageBuffer;
346
347 if (!sampleBuffer)
348 return;
349
350 /* Get a CMSampleBuffer's Core Video image buffer for the media data */
351 imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
352
353 /* Lock the base address of the pixel buffer */
354 CVPixelBufferLockBaseAddress(imageBuffer, 0);
355
356 frame.type = PJMEDIA_TYPE_VIDEO;
357 frame.buf = CVPixelBufferGetBaseAddress(imageBuffer);
358 frame.size = stream->frame_size;
359 frame.bit_info = 0;
Benny Prijono349037b2011-03-17 11:25:19 +0000360 frame.timestamp.u64 = stream->frame_ts.u64;
361
Sauw Ming6e6c2152010-12-14 13:03:10 +0000362 if (stream->vid_cb.capture_cb)
363 (*stream->vid_cb.capture_cb)(&stream->base, stream->user_data, &frame);
364
Benny Prijono349037b2011-03-17 11:25:19 +0000365 stream->frame_ts.u64 += stream->ts_inc;
366
Sauw Ming6e6c2152010-12-14 13:03:10 +0000367 /* Unlock the pixel buffer */
368 CVPixelBufferUnlockBaseAddress(imageBuffer,0);
369}
370@end
371
372static ios_fmt_info* get_ios_format_info(pjmedia_format_id id)
373{
374 unsigned i;
375
376 for (i = 0; i < PJ_ARRAY_SIZE(ios_fmts); i++) {
377 if (ios_fmts[i].pjmedia_format == id)
378 return &ios_fmts[i];
379 }
380
381 return NULL;
382}
383
384/* API: create stream */
Sauw Mingb93e6882011-03-19 05:33:21 +0000385static pj_status_t ios_factory_create_stream(
386 pjmedia_vid_dev_factory *f,
387 const pjmedia_vid_param *param,
388 const pjmedia_vid_cb *cb,
389 void *user_data,
390 pjmedia_vid_dev_stream **p_vid_strm)
Sauw Ming6e6c2152010-12-14 13:03:10 +0000391{
392 struct ios_factory *qf = (struct ios_factory*)f;
393 pj_pool_t *pool;
394 struct ios_stream *strm;
Benny Prijono349037b2011-03-17 11:25:19 +0000395 const pjmedia_video_format_detail *vfd;
Sauw Ming6e6c2152010-12-14 13:03:10 +0000396 const pjmedia_video_format_info *vfi;
397 pj_status_t status = PJ_SUCCESS;
398 ios_fmt_info *ifi = get_ios_format_info(param->fmt.id);
399 NSError *error;
400
401 PJ_ASSERT_RETURN(f && param && p_vid_strm, PJ_EINVAL);
402 PJ_ASSERT_RETURN(param->fmt.type == PJMEDIA_TYPE_VIDEO &&
403 param->fmt.detail_type == PJMEDIA_FORMAT_DETAIL_VIDEO,
404 PJ_EINVAL);
405
406 if (!(ifi = get_ios_format_info(param->fmt.id)))
407 return PJMEDIA_EVID_BADFORMAT;
408
409 vfi = pjmedia_get_video_format_info(NULL, param->fmt.id);
410 if (!vfi)
411 return PJMEDIA_EVID_BADFORMAT;
412
413 /* Create and Initialize stream descriptor */
414 pool = pj_pool_create(qf->pf, "ios-dev", 4000, 4000, NULL);
415 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
416
417 strm = PJ_POOL_ZALLOC_T(pool, struct ios_stream);
418 pj_memcpy(&strm->param, param, sizeof(*param));
419 strm->pool = pool;
420 pj_memcpy(&strm->vid_cb, cb, sizeof(*cb));
421 strm->user_data = user_data;
422
423 vfd = pjmedia_format_get_video_format_detail(&strm->param.fmt, PJ_TRUE);
424 pj_memcpy(&strm->size, &vfd->size, sizeof(vfd->size));
425 strm->bpp = vfi->bpp;
426 strm->bytes_per_row = strm->size.w * strm->bpp / 8;
427 strm->frame_size = strm->bytes_per_row * strm->size.h;
Benny Prijono349037b2011-03-17 11:25:19 +0000428 strm->ts_inc = PJMEDIA_SPF2(param->clock_rate, &vfd->fps, 1);
Sauw Ming6e6c2152010-12-14 13:03:10 +0000429
430 /* Create capture stream here */
431 if (param->dir & PJMEDIA_DIR_CAPTURE) {
432 strm->cap_session = [[AVCaptureSession alloc] init];
433 if (!strm->cap_session) {
434 status = PJ_ENOMEM;
435 goto on_error;
436 }
437 strm->cap_session.sessionPreset = AVCaptureSessionPresetMedium;
438
439 /* Open video device */
440 AVCaptureDevice *videoDevice =
441 [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
442 if (!videoDevice) {
443 status = PJMEDIA_EVID_SYSERR;
444 goto on_error;
445 }
446
447 /* Add the video device to the session as a device input */
448 strm->dev_input = [AVCaptureDeviceInput
449 deviceInputWithDevice:videoDevice
450 error: &error];
451 if (!strm->dev_input) {
452 status = PJMEDIA_EVID_SYSERR;
453 goto on_error;
454 }
455 [strm->cap_session addInput:strm->dev_input];
456
457 strm->video_output = [[[AVCaptureVideoDataOutput alloc] init]
458 autorelease];
459 if (!strm->video_output) {
460 status = PJMEDIA_EVID_SYSERR;
461 goto on_error;
462 }
463 [strm->cap_session addOutput:strm->video_output];
464
Sauw Mingab494302010-12-17 13:17:23 +0000465 /* Configure the video output */
Sauw Ming6e6c2152010-12-14 13:03:10 +0000466 strm->vout_delegate = [VOutDelegate alloc];
467 strm->vout_delegate->stream = strm;
468 dispatch_queue_t queue = dispatch_queue_create("myQueue", NULL);
469 [strm->video_output setSampleBufferDelegate:strm->vout_delegate
470 queue:queue];
471 dispatch_release(queue);
472
473 strm->video_output.videoSettings =
474 [NSDictionary dictionaryWithObjectsAndKeys:
475 [NSNumber numberWithInt:ifi->ios_format],
476 kCVPixelBufferPixelFormatTypeKey,
477 [NSNumber numberWithInt: vfd->size.w],
478 kCVPixelBufferWidthKey,
479 [NSNumber numberWithInt: vfd->size.h],
480 kCVPixelBufferHeightKey, nil];
481 strm->video_output.minFrameDuration = CMTimeMake(vfd->fps.denum,
482 vfd->fps.num);
483 }
484
485 /* Create renderer stream here */
486 if (param->dir & PJMEDIA_DIR_RENDER) {
487 /* Get the main window */
488 UIWindow *window = [[UIApplication sharedApplication] keyWindow];
489
Sauw Mingab494302010-12-17 13:17:23 +0000490 if (param->flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW && param->window)
Sauw Mingb93e6882011-03-19 05:33:21 +0000491 window = (UIWindow *)param->window;
Sauw Mingab494302010-12-17 13:17:23 +0000492
Sauw Ming6e6c2152010-12-14 13:03:10 +0000493 pj_assert(window);
494 strm->imgView = [[UIImageView alloc] initWithFrame:[window bounds]];
495 if (!strm->imgView) {
496 status = PJ_ENOMEM;
497 goto on_error;
498 }
499 [window addSubview:strm->imgView];
500
501 if (!strm->vout_delegate) {
502 strm->vout_delegate = [VOutDelegate alloc];
503 strm->vout_delegate->stream = strm;
504 }
505
506 strm->buf = pj_pool_alloc(pool, strm->frame_size);
507 }
508
509 /* Apply the remaining settings */
510 /*
511 if (param->flags & PJMEDIA_VID_DEV_CAP_INPUT_SCALE) {
512 ios_stream_set_cap(&strm->base,
513 PJMEDIA_VID_DEV_CAP_INPUT_SCALE,
514 &param->fmt);
515 }
516 */
517 /* Done */
518 strm->base.op = &stream_op;
519 *p_vid_strm = &strm->base;
520
521 return PJ_SUCCESS;
522
523on_error:
Sauw Mingb93e6882011-03-19 05:33:21 +0000524 ios_stream_destroy((pjmedia_vid_dev_stream *)strm);
Sauw Ming6e6c2152010-12-14 13:03:10 +0000525
526 return status;
527}
528
529/* API: Get stream info. */
Sauw Mingb93e6882011-03-19 05:33:21 +0000530static pj_status_t ios_stream_get_param(pjmedia_vid_dev_stream *s,
Sauw Ming6e6c2152010-12-14 13:03:10 +0000531 pjmedia_vid_param *pi)
532{
533 struct ios_stream *strm = (struct ios_stream*)s;
534
535 PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
536
537 pj_memcpy(pi, &strm->param, sizeof(*pi));
538
539/* if (ios_stream_get_cap(s, PJMEDIA_VID_DEV_CAP_INPUT_SCALE,
540 &pi->fmt.info_size) == PJ_SUCCESS)
541 {
542 pi->flags |= PJMEDIA_VID_DEV_CAP_INPUT_SCALE;
543 }
544*/
545 return PJ_SUCCESS;
546}
547
548/* API: get capability */
Sauw Mingb93e6882011-03-19 05:33:21 +0000549static pj_status_t ios_stream_get_cap(pjmedia_vid_dev_stream *s,
Sauw Ming6e6c2152010-12-14 13:03:10 +0000550 pjmedia_vid_dev_cap cap,
551 void *pval)
552{
553 struct ios_stream *strm = (struct ios_stream*)s;
554
555 PJ_UNUSED_ARG(strm);
556
557 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
558
559 if (cap==PJMEDIA_VID_DEV_CAP_INPUT_SCALE)
560 {
561 return PJMEDIA_EVID_INVCAP;
562// return PJ_SUCCESS;
563 } else {
564 return PJMEDIA_EVID_INVCAP;
565 }
566}
567
568/* API: set capability */
Sauw Mingb93e6882011-03-19 05:33:21 +0000569static pj_status_t ios_stream_set_cap(pjmedia_vid_dev_stream *s,
Sauw Ming6e6c2152010-12-14 13:03:10 +0000570 pjmedia_vid_dev_cap cap,
571 const void *pval)
572{
573 struct ios_stream *strm = (struct ios_stream*)s;
574
575 PJ_UNUSED_ARG(strm);
576
577 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
578
579 if (cap==PJMEDIA_VID_DEV_CAP_INPUT_SCALE)
580 {
581 return PJ_SUCCESS;
582 }
583
584 return PJMEDIA_EVID_INVCAP;
585}
586
587/* API: Start stream. */
Sauw Mingb93e6882011-03-19 05:33:21 +0000588static pj_status_t ios_stream_start(pjmedia_vid_dev_stream *strm)
Sauw Ming6e6c2152010-12-14 13:03:10 +0000589{
590 struct ios_stream *stream = (struct ios_stream*)strm;
591
592 PJ_UNUSED_ARG(stream);
593
594 PJ_LOG(4, (THIS_FILE, "Starting qt video stream"));
595
596 if (stream->cap_session) {
597 [stream->cap_session startRunning];
598
599 if (![stream->cap_session isRunning])
600 return PJ_EUNKNOWN;
601 }
602
603 return PJ_SUCCESS;
604}
605
606
607/* API: Put frame from stream */
Sauw Mingb93e6882011-03-19 05:33:21 +0000608static pj_status_t ios_stream_put_frame(pjmedia_vid_dev_stream *strm,
Sauw Ming6e6c2152010-12-14 13:03:10 +0000609 const pjmedia_frame *frame)
610{
611 struct ios_stream *stream = (struct ios_stream*)strm;
612 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
613
614 pj_assert(stream->frame_size >= frame->size);
615 pj_memcpy(stream->buf, frame->buf, frame->size);
616 /* Perform video display in a background thread */
617// [stream->vout_delegate update_image];
618 [NSThread detachNewThreadSelector:@selector(update_image)
619 toTarget:stream->vout_delegate withObject:nil];
620
621 [pool release];
622
623 return PJ_SUCCESS;
624}
625
626/* API: Stop stream. */
Sauw Mingb93e6882011-03-19 05:33:21 +0000627static pj_status_t ios_stream_stop(pjmedia_vid_dev_stream *strm)
Sauw Ming6e6c2152010-12-14 13:03:10 +0000628{
629 struct ios_stream *stream = (struct ios_stream*)strm;
630
631 PJ_UNUSED_ARG(stream);
632
633 PJ_LOG(4, (THIS_FILE, "Stopping qt video stream"));
634
635 if (stream->cap_session && [stream->cap_session isRunning])
636 [stream->cap_session stopRunning];
637
638 return PJ_SUCCESS;
639}
640
641
642/* API: Destroy stream. */
Sauw Mingb93e6882011-03-19 05:33:21 +0000643static pj_status_t ios_stream_destroy(pjmedia_vid_dev_stream *strm)
Sauw Ming6e6c2152010-12-14 13:03:10 +0000644{
645 struct ios_stream *stream = (struct ios_stream*)strm;
646
647 PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
648
649 ios_stream_stop(strm);
650
651 if (stream->imgView) {
652 [stream->imgView removeFromSuperview];
653 [stream->imgView release];
654 stream->imgView = NULL;
655 }
656
657 if (stream->cap_session) {
658 [stream->cap_session release];
659 stream->cap_session = NULL;
660 }
661/* if (stream->dev_input) {
662 [stream->dev_input release];
663 stream->dev_input = NULL;
664 }
665*/
666 if (stream->vout_delegate) {
667 [stream->vout_delegate release];
668 stream->vout_delegate = NULL;
669 }
670/* if (stream->video_output) {
671 [stream->video_output release];
672 stream->video_output = NULL;
673 }
674*/
675
676 pj_pool_release(stream->pool);
677
678 return PJ_SUCCESS;
679}
680
681#endif
682#endif /* PJMEDIA_VIDEO_DEV_HAS_IOS */