- Timestamp:
- Apr 24, 2014 8:37:45 AM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia-videodev/ios_dev.m
r4722 r4824 30 30 #import <UIKit/UIKit.h> 31 31 #import <AVFoundation/AVFoundation.h> 32 #import <QuartzCore/QuartzCore.h> 32 33 33 34 #define THIS_FILE "ios_dev.c" 34 35 #define DEFAULT_CLOCK_RATE 90000 35 #define DEFAULT_WIDTH 48036 #define DEFAULT_HEIGHT 36036 #define DEFAULT_WIDTH 352 37 #define DEFAULT_HEIGHT 288 37 38 #define DEFAULT_FPS 15 38 39 … … 45 46 static ios_fmt_info ios_fmts[] = 46 47 { 47 { PJMEDIA_FORMAT_BGRA, kCVPixelFormatType_32BGRA} ,48 { PJMEDIA_FORMAT_BGRA, kCVPixelFormatType_32BGRA } 48 49 }; 49 50 … … 52 53 { 53 54 pjmedia_vid_dev_info info; 55 AVCaptureDevice *dev; 54 56 }; 55 57 … … 79 81 pjmedia_vid_dev_param param; /**< Settings */ 80 82 pj_pool_t *pool; /**< Memory pool */ 83 struct ios_factory *factory; /**< Factory */ 81 84 82 85 pjmedia_vid_dev_cb vid_cb; /**< Stream callback */ … … 93 96 VOutDelegate *vout_delegate; 94 97 95 UIImageView *imgView; 96 void *buf; 97 dispatch_queue_t render_queue; 98 void *render_buf; 99 pj_size_t render_buf_size; 100 CGDataProviderRef render_data_provider; 101 UIView *render_view; 98 102 99 103 pj_timestamp frame_ts; 100 104 unsigned ts_inc; 105 106 pj_bool_t thread_initialized; 107 pj_thread_desc thread_desc; 108 pj_thread_t *thread; 101 109 }; 102 110 … … 186 194 struct ios_factory *qf = (struct ios_factory*)f; 187 195 struct ios_dev_info *qdi; 188 unsigned i, l; 196 unsigned i, l, first_idx, front_idx = -1; 197 enum { MAX_DEV_COUNT = 8 }; 189 198 190 199 /* Initialize input and output devices here */ 191 200 qf->dev_info = (struct ios_dev_info*) 192 pj_pool_calloc(qf->pool, 2,201 pj_pool_calloc(qf->pool, MAX_DEV_COUNT, 193 202 sizeof(struct ios_dev_info)); 194 195 203 qf->dev_count = 0; 204 205 /* Init output device */ 196 206 qdi = &qf->dev_info[qf->dev_count++]; 197 207 pj_bzero(qdi, sizeof(*qdi)); 198 strcpy(qdi->info.name, "iOS UIView");199 strcpy(qdi->info.driver, "iOS");208 pj_ansi_strncpy(qdi->info.name, "UIView", sizeof(qdi->info.name)); 209 pj_ansi_strncpy(qdi->info.driver, "iOS", sizeof(qdi->info.driver)); 200 210 qdi->info.dir = PJMEDIA_DIR_RENDER; 201 211 qdi->info.has_callback = PJ_FALSE; 202 212 qdi->info.caps = PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW; 203 213 214 /* Init input device */ 215 first_idx = qf->dev_count; 204 216 if (NSClassFromString(@"AVCaptureSession")) { 205 qdi = &qf->dev_info[qf->dev_count++]; 206 pj_bzero(qdi, sizeof(*qdi)); 207 strcpy(qdi->info.name, "iOS AVCapture"); 208 strcpy(qdi->info.driver, "iOS"); 209 qdi->info.dir = PJMEDIA_DIR_CAPTURE; 210 qdi->info.has_callback = PJ_TRUE; 211 } 212 217 for (AVCaptureDevice *device in [AVCaptureDevice devices]) { 218 if (![device hasMediaType:AVMediaTypeVideo] || 219 qf->dev_count >= MAX_DEV_COUNT) 220 { 221 continue; 222 } 223 224 if (front_idx == -1 && 225 [device position] == AVCaptureDevicePositionFront) 226 { 227 front_idx = qf->dev_count; 228 } 229 230 qdi = &qf->dev_info[qf->dev_count++]; 231 pj_bzero(qdi, sizeof(*qdi)); 232 pj_ansi_strncpy(qdi->info.name, [[device localizedName] UTF8String], 233 sizeof(qdi->info.name)); 234 pj_ansi_strncpy(qdi->info.driver, "iOS", sizeof(qdi->info.driver)); 235 qdi->info.dir = PJMEDIA_DIR_CAPTURE; 236 qdi->info.has_callback = PJ_TRUE; 237 qdi->info.caps = PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW | 238 PJMEDIA_VID_DEV_CAP_SWITCH | 239 PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW; 240 qdi->dev = device; 241 } 242 } 243 244 /* Set front camera to be the first input device (as default dev) */ 245 if (front_idx != -1 && front_idx != first_idx) { 246 struct ios_dev_info tmp_dev_info = qf->dev_info[first_idx]; 247 qf->dev_info[first_idx] = qf->dev_info[front_idx]; 248 qf->dev_info[front_idx] = tmp_dev_info; 249 } 250 251 /* Set supported formats */ 213 252 for (i = 0; i < qf->dev_count; i++) { 214 253 qdi = &qf->dev_info[i]; … … 226 265 } 227 266 228 PJ_LOG(4, (THIS_FILE, "iOS video initialized with %d devices ",267 PJ_LOG(4, (THIS_FILE, "iOS video initialized with %d devices:", 229 268 qf->dev_count)); 230 269 for (i = 0; i < qf->dev_count; i++) { 270 qdi = &qf->dev_info[i]; 271 PJ_LOG(4, (THIS_FILE, "%2d: [%s] %s - %s", i, 272 (qdi->info.dir==PJMEDIA_DIR_CAPTURE? "Capturer":"Renderer"), 273 qdi->info.driver, qdi->info.name)); 274 } 275 231 276 return PJ_SUCCESS; 232 277 } … … 279 324 { 280 325 struct ios_factory *qf = (struct ios_factory*)f; 281 struct ios_dev_info *di = &qf->dev_info[index];326 struct ios_dev_info *di; 282 327 283 328 PJ_ASSERT_RETURN(index < qf->dev_count, PJMEDIA_EVID_INVDEV); 284 285 329 PJ_UNUSED_ARG(pool); 330 331 di = &qf->dev_info[index]; 286 332 287 333 pj_bzero(param, sizeof(*param)); … … 309 355 { 310 356 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 311 312 /* Create a device-dependent RGB color space */ 313 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 314 315 /* Create a bitmap graphics context with the sample buffer data */ 316 CGContextRef context = 317 CGBitmapContextCreate(stream->buf, stream->size.w, stream->size.h, 8, 318 stream->bytes_per_row, colorSpace, 319 kCGBitmapByteOrder32Little | 320 kCGImageAlphaPremultipliedFirst); 321 322 /** 323 * Create a Quartz image from the pixel data in the bitmap graphics 324 * context 325 */ 326 CGImageRef quartzImage = CGBitmapContextCreateImage(context); 327 328 /* Free up the context and color space */ 329 CGContextRelease(context); 357 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 358 CGImageRef cgIm = CGImageCreate(stream->size.w, stream->size.h, 359 8, 32, stream->bytes_per_row, colorSpace, 360 kCGImageAlphaFirst | 361 kCGBitmapByteOrder32Little, 362 stream->render_data_provider, 0, 363 false, kCGRenderingIntentDefault); 330 364 CGColorSpaceRelease(colorSpace); 331 365 332 /* Create an image object from the Quartz image */ 333 UIImage *image = [UIImage imageWithCGImage:quartzImage scale:1.0 334 orientation:UIImageOrientationRight]; 335 336 /* Release the Quartz image */ 337 CGImageRelease(quartzImage); 338 339 dispatch_async(dispatch_get_main_queue(), 340 ^{[stream->imgView setImage:image];}); 341 /* 342 [stream->imgView performSelectorOnMainThread:@selector(setImage:) 343 withObject:image waitUntilDone:NO]; 344 */ 345 366 stream->render_view.layer.contents = (__bridge id)(cgIm); 367 CGImageRelease(cgIm); 368 346 369 [pool release]; 347 370 } … … 361 384 362 385 /* Lock the base address of the pixel buffer */ 363 CVPixelBufferLockBaseAddress(imageBuffer, 0);386 CVPixelBufferLockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly); 364 387 365 388 frame.type = PJMEDIA_FRAME_TYPE_VIDEO; … … 369 392 frame.timestamp.u64 = stream->frame_ts.u64; 370 393 371 if (stream->vid_cb.capture_cb) 394 if (stream->vid_cb.capture_cb) { 395 if (stream->thread_initialized == 0 || !pj_thread_is_registered()) 396 { 397 pj_bzero(stream->thread_desc, sizeof(pj_thread_desc)); 398 pj_thread_register("ios_vdev", stream->thread_desc, 399 &stream->thread); 400 stream->thread_initialized = 1; 401 } 402 372 403 (*stream->vid_cb.capture_cb)(&stream->base, stream->user_data, &frame); 404 } 373 405 374 406 stream->frame_ts.u64 += stream->ts_inc; 375 407 376 408 /* Unlock the pixel buffer */ 377 CVPixelBufferUnlockBaseAddress(imageBuffer, 0);409 CVPixelBufferUnlockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly); 378 410 } 379 411 @end … … 390 422 return NULL; 391 423 } 424 425 426 static pj_status_t ios_init_view(struct ios_stream *strm) 427 { 428 pjmedia_vid_dev_param *param = &strm->param; 429 CGRect view_rect = CGRectMake(0, 0, param->fmt.det.vid.size.w, 430 param->fmt.det.vid.size.h); 431 432 if (param->flags & PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE) { 433 view_rect.size.width = param->disp_size.w; 434 view_rect.size.height = param->disp_size.h; 435 } 436 437 if (param->flags & PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION) { 438 view_rect.origin.x = param->window_pos.x; 439 view_rect.origin.y = param->window_pos.y; 440 } 441 442 strm->render_view = [[UIView alloc] initWithFrame:view_rect]; 443 strm->param.window.info.ios.window = strm->render_view; 444 445 if (param->flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW) { 446 PJ_ASSERT_RETURN(param->window.info.ios.window, PJ_EINVAL); 447 ios_stream_set_cap(&strm->base, PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW, 448 param->window.info.ios.window); 449 } 450 if (param->flags & PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE) { 451 ios_stream_set_cap(&strm->base, PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE, 452 ¶m->window_hide); 453 } 454 if (param->flags & PJMEDIA_VID_DEV_CAP_ORIENTATION) { 455 ios_stream_set_cap(&strm->base, PJMEDIA_VID_DEV_CAP_ORIENTATION, 456 ¶m->orient); 457 } 458 459 return PJ_SUCCESS; 460 } 461 392 462 393 463 /* API: create stream */ … … 402 472 pj_pool_t *pool; 403 473 struct ios_stream *strm; 404 constpjmedia_video_format_detail *vfd;474 pjmedia_video_format_detail *vfd; 405 475 const pjmedia_video_format_info *vfi; 406 476 pj_status_t status = PJ_SUCCESS; 407 477 ios_fmt_info *ifi = get_ios_format_info(param->fmt.id); 408 NSError *error;409 478 410 479 PJ_ASSERT_RETURN(f && param && p_vid_strm, PJ_EINVAL); … … 431 500 pj_memcpy(&strm->vid_cb, cb, sizeof(*cb)); 432 501 strm->user_data = user_data; 433 502 strm->factory = qf; 503 434 504 vfd = pjmedia_format_get_video_format_detail(&strm->param.fmt, PJ_TRUE); 435 505 pj_memcpy(&strm->size, &vfd->size, sizeof(vfd->size)); … … 446 516 goto on_error; 447 517 } 448 strm->cap_session.sessionPreset = AVCaptureSessionPresetMedium; 449 450 /* Open video device */ 451 AVCaptureDevice *videoDevice = 452 [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 453 if (!videoDevice) { 454 status = PJMEDIA_EVID_SYSERR; 455 goto on_error; 456 } 457 458 /* Add the video device to the session as a device input */ 459 strm->dev_input = [AVCaptureDeviceInput 460 deviceInputWithDevice:videoDevice 518 519 /* Just hardcode to always capture 352x288 for now */ 520 strm->cap_session.sessionPreset = AVCaptureSessionPreset352x288; 521 vfd->size.w = 352; 522 vfd->size.h = 288; 523 strm->size = vfd->size; 524 strm->bytes_per_row = strm->size.w * strm->bpp / 8; 525 strm->frame_size = strm->bytes_per_row * strm->size.h; 526 527 /* Update param as output */ 528 param->fmt = strm->param.fmt; 529 530 /* Set frame rate, this may only work on iOS 7 or later */ 531 AVCaptureDevice *dev = qf->dev_info[param->cap_id].dev; 532 if ([dev respondsToSelector:@selector(activeVideoMinFrameDuration)] && 533 [dev lockForConfiguration:NULL]) 534 { 535 dev.activeVideoMinFrameDuration = CMTimeMake(vfd->fps.denum, 536 vfd->fps.num); 537 dev.activeVideoMaxFrameDuration = CMTimeMake(vfd->fps.denum, 538 vfd->fps.num); 539 [dev unlockForConfiguration]; 540 } 541 542 /* Add the video device to the session as a device input */ 543 NSError *error; 544 strm->dev_input = [AVCaptureDeviceInput 545 deviceInputWithDevice:dev 461 546 error: &error]; 462 547 if (!strm->dev_input) { … … 472 557 goto on_error; 473 558 } 559 560 strm->video_output.alwaysDiscardsLateVideoFrames = YES; 474 561 [strm->cap_session addOutput:strm->video_output]; 475 562 … … 479 566 dispatch_queue_t queue = dispatch_queue_create("myQueue", NULL); 480 567 [strm->video_output setSampleBufferDelegate:strm->vout_delegate 481 482 dispatch_release(queue); 568 queue:queue]; 569 dispatch_release(queue); 483 570 484 571 strm->video_output.videoSettings = 485 572 [NSDictionary dictionaryWithObjectsAndKeys: 486 573 [NSNumber numberWithInt:ifi->ios_format], 487 kCVPixelBufferPixelFormatTypeKey, 488 [NSNumber numberWithInt: vfd->size.w], 489 kCVPixelBufferWidthKey, 490 [NSNumber numberWithInt: vfd->size.h], 491 kCVPixelBufferHeightKey, nil]; 492 strm->video_output.minFrameDuration = CMTimeMake(vfd->fps.denum, 493 vfd->fps.num); 574 kCVPixelBufferPixelFormatTypeKey, nil]; 575 576 /* Native preview */ 577 if ((param->flags & PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW) && 578 param->native_preview) 579 { 580 /* Preview layer instantiation should be in main thread! */ 581 dispatch_async(dispatch_get_main_queue(), ^{ 582 /* Create view */ 583 ios_init_view(strm); 584 585 /* Create preview layer */ 586 AVCaptureVideoPreviewLayer *previewLayer = 587 [AVCaptureVideoPreviewLayer layerWithSession: strm->cap_session]; 588 589 /* Attach preview layer to a UIView */ 590 CGRect r = strm->render_view.bounds; 591 previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; 592 previewLayer.frame = r; 593 [[strm->render_view layer] addSublayer:previewLayer]; 594 595 NSLog(@"Native preview initialized."); 596 }); 597 } 598 494 599 } else if (param->dir & PJMEDIA_DIR_RENDER) { 600 495 601 /* Create renderer stream here */ 496 /* Get the main window */ 497 UIWindow *window = [[UIApplication sharedApplication] keyWindow]; 498 499 if (param->flags & PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW && 500 param->window.info.ios.window) 501 window = (UIWindow *)param->window.info.ios.window; 502 503 pj_assert(window); 504 strm->imgView = [[UIImageView alloc] initWithFrame:[window bounds]]; 505 if (!strm->imgView) { 506 status = PJ_ENOMEM; 507 goto on_error; 508 } 509 [window addSubview:strm->imgView]; 510 602 603 status = ios_init_view(strm); 604 if (status != PJ_SUCCESS) 605 goto on_error; 606 511 607 if (!strm->vout_delegate) { 512 608 strm->vout_delegate = [VOutDelegate alloc]; … … 514 610 } 515 611 516 strm->render_queue = dispatch_queue_create("com.pjsip.render_queue", 517 NULL); 518 if (!strm->render_queue) 519 goto on_error; 520 521 strm->buf = pj_pool_alloc(pool, strm->frame_size); 522 } 523 524 /* Apply the remaining settings */ 525 /* 526 if (param->flags & PJMEDIA_VID_DEV_CAP_INPUT_SCALE) { 527 ios_stream_set_cap(&strm->base, 528 PJMEDIA_VID_DEV_CAP_INPUT_SCALE, 529 ¶m->fmt); 530 } 531 */ 612 strm->render_buf = pj_pool_alloc(pool, strm->frame_size); 613 strm->render_buf_size = strm->frame_size; 614 strm->render_data_provider = CGDataProviderCreateWithData(NULL, 615 strm->render_buf, strm->frame_size, 616 NULL); 617 } 618 532 619 /* Done */ 533 620 strm->base.op = &stream_op; … … 552 639 pj_memcpy(pi, &strm->param, sizeof(*pi)); 553 640 554 /* if (ios_stream_get_cap(s, PJMEDIA_VID_DEV_CAP_INPUT_SCALE,555 &pi->fmt.info_size) == PJ_SUCCESS)556 {557 pi->flags |= PJMEDIA_VID_DEV_CAP_INPUT_SCALE;558 }559 */560 641 return PJ_SUCCESS; 561 642 } … … 567 648 { 568 649 struct ios_stream *strm = (struct ios_stream*)s; 569 570 PJ_UNUSED_ARG(strm); 571 650 572 651 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL); 573 652 574 if (cap==PJMEDIA_VID_DEV_CAP_INPUT_SCALE) 575 { 576 return PJMEDIA_EVID_INVCAP; 577 // return PJ_SUCCESS; 578 } else { 579 return PJMEDIA_EVID_INVCAP; 580 } 653 switch (cap) { 654 case PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW: 655 { 656 pjmedia_vid_dev_hwnd *hwnd = (pjmedia_vid_dev_hwnd*) pval; 657 hwnd->type = PJMEDIA_VID_DEV_HWND_TYPE_NONE; 658 hwnd->info.ios.window = (void*)strm->render_view; 659 return PJ_SUCCESS; 660 } 661 662 default: 663 break; 664 } 665 666 return PJMEDIA_EVID_INVCAP; 581 667 } 582 668 … … 588 674 struct ios_stream *strm = (struct ios_stream*)s; 589 675 590 PJ_UNUSED_ARG(strm);591 592 676 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL); 593 677 594 if (cap==PJMEDIA_VID_DEV_CAP_INPUT_SCALE) 595 { 596 return PJ_SUCCESS; 678 switch (cap) { 679 /* Fast switch */ 680 case PJMEDIA_VID_DEV_CAP_SWITCH: 681 { 682 if (!strm->cap_session) return PJ_EINVAL; 683 684 NSError *error; 685 struct ios_dev_info* di = strm->factory->dev_info; 686 pjmedia_vid_dev_switch_param *p = 687 (pjmedia_vid_dev_switch_param*)pval; 688 689 /* Verify target capture ID */ 690 if (p->target_id < 0 || p->target_id >= strm->factory->dev_count) 691 return PJ_EINVAL; 692 693 if (di[p->target_id].info.dir != PJMEDIA_DIR_CAPTURE || 694 !di[p->target_id].dev) 695 { 696 return PJ_EINVAL; 697 } 698 699 /* Just return if current and target device are the same */ 700 if (strm->param.cap_id == p->target_id) 701 return PJ_SUCCESS; 702 703 /* Ok, let's do the switch */ 704 AVCaptureDeviceInput *cur_dev_input = strm->dev_input; 705 //[AVCaptureDeviceInput 706 // deviceInputWithDevice:di[strm->param.cap_id].dev 707 // error:&error]; 708 AVCaptureDeviceInput *new_dev_input = 709 [AVCaptureDeviceInput 710 deviceInputWithDevice:di[p->target_id].dev 711 error:&error]; 712 713 [strm->cap_session beginConfiguration]; 714 [strm->cap_session removeInput:cur_dev_input]; 715 [strm->cap_session addInput:new_dev_input]; 716 [strm->cap_session commitConfiguration]; 717 718 strm->dev_input = new_dev_input; 719 strm->param.cap_id = p->target_id; 720 721 return PJ_SUCCESS; 722 } 723 724 case PJMEDIA_VID_DEV_CAP_FORMAT: 725 { 726 const pjmedia_video_format_info *vfi; 727 pjmedia_video_format_detail *vfd; 728 pjmedia_format *fmt = (pjmedia_format *)pval; 729 ios_fmt_info *ifi; 730 731 if (!(ifi = get_ios_format_info(fmt->id))) 732 return PJMEDIA_EVID_BADFORMAT; 733 734 vfi = pjmedia_get_video_format_info(pjmedia_video_format_mgr_instance(), 735 fmt->id); 736 if (!vfi) 737 return PJMEDIA_EVID_BADFORMAT; 738 739 pjmedia_format_copy(&strm->param.fmt, fmt); 740 741 vfd = pjmedia_format_get_video_format_detail(fmt, PJ_TRUE); 742 pj_memcpy(&strm->size, &vfd->size, sizeof(vfd->size)); 743 strm->bytes_per_row = strm->size.w * strm->bpp / 8; 744 strm->frame_size = strm->bytes_per_row * strm->size.h; 745 if (strm->render_buf_size < strm->frame_size) { 746 strm->render_buf = pj_pool_alloc(strm->pool, strm->frame_size); 747 strm->render_buf_size = strm->frame_size; 748 CGDataProviderRelease(strm->render_data_provider); 749 strm->render_data_provider = CGDataProviderCreateWithData(NULL, 750 strm->render_buf, strm->frame_size, 751 NULL); 752 } 753 754 return PJ_SUCCESS; 755 } 756 757 case PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW: 758 { 759 UIView *view = (UIView *)pval; 760 strm->param.window.info.ios.window = (void *)pval; 761 dispatch_async(dispatch_get_main_queue(), 762 ^{[view addSubview:strm->render_view];}); 763 return PJ_SUCCESS; 764 } 765 766 case PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE: 767 { 768 pj_memcpy(&strm->param.disp_size, pval, 769 sizeof(strm->param.disp_size)); 770 CGRect r = strm->render_view.bounds; 771 r.size = CGSizeMake(strm->param.disp_size.w, 772 strm->param.disp_size.h); 773 dispatch_async(dispatch_get_main_queue(), ^{ 774 strm->render_view.bounds = r; 775 }); 776 return PJ_SUCCESS; 777 } 778 779 case PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION: 780 { 781 pj_memcpy(&strm->param.window_pos, pval, 782 sizeof(strm->param.window_pos)); 783 dispatch_async(dispatch_get_main_queue(), ^{ 784 strm->render_view.center = 785 CGPointMake(strm->param.window_pos.x + 786 strm->param.disp_size.w/2.0, 787 strm->param.window_pos.y + 788 strm->param.disp_size.h/2.0); 789 }); 790 return PJ_SUCCESS; 791 } 792 793 case PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE: 794 { 795 dispatch_async(dispatch_get_main_queue(), ^{ 796 strm->render_view.hidden = (BOOL)(*((pj_bool_t *)pval)); 797 }); 798 return PJ_SUCCESS; 799 } 800 801 /* TODO: orientation for capture device */ 802 case PJMEDIA_VID_DEV_CAP_ORIENTATION: 803 { 804 pj_memcpy(&strm->param.orient, pval, 805 sizeof(strm->param.orient)); 806 if (strm->param.orient == PJMEDIA_ORIENT_UNKNOWN) 807 return PJ_SUCCESS; 808 809 dispatch_async(dispatch_get_main_queue(), ^{ 810 strm->render_view.transform = 811 CGAffineTransformMakeRotation( 812 ((int)strm->param.orient-1) * -M_PI_2); 813 }); 814 return PJ_SUCCESS; 815 } 816 817 default: 818 break; 597 819 } 598 820 … … 607 829 PJ_UNUSED_ARG(stream); 608 830 609 PJ_LOG(4, (THIS_FILE, "Starting i osvideo stream"));831 PJ_LOG(4, (THIS_FILE, "Starting iOS video stream")); 610 832 611 833 if (stream->cap_session) { … … 625 847 { 626 848 struct ios_stream *stream = (struct ios_stream*)strm; 627 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 628 629 pj_assert(stream->frame_size >= frame->size); 630 pj_memcpy(stream->buf, frame->buf, frame->size); 849 //NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 850 851 if (stream->frame_size >= frame->size) 852 pj_memcpy(stream->render_buf, frame->buf, frame->size); 853 else 854 pj_memcpy(stream->render_buf, frame->buf, stream->frame_size); 855 631 856 /* Perform video display in a background thread */ 632 /* 633 [stream->vout_delegate update_image]; 634 [NSThread detachNewThreadSelector:@selector(update_image) 635 toTarget:stream->vout_delegate withObject:nil]; 636 */ 637 dispatch_async(stream->render_queue, 857 dispatch_async(dispatch_get_main_queue(), 638 858 ^{[stream->vout_delegate update_image];}); 639 640 [pool release];859 860 //[pool release]; 641 861 642 862 return PJ_SUCCESS; … … 650 870 PJ_UNUSED_ARG(stream); 651 871 652 PJ_LOG(4, (THIS_FILE, "Stopping i osvideo stream"));872 PJ_LOG(4, (THIS_FILE, "Stopping iOS video stream")); 653 873 654 874 if (stream->cap_session && [stream->cap_session isRunning]) … … 668 888 ios_stream_stop(strm); 669 889 670 if (stream->imgView) {671 [stream->imgView removeFromSuperview];672 [stream->imgView release];673 stream->imgView = NULL;674 }675 676 890 if (stream->cap_session) { 891 [stream->cap_session removeInput:stream->dev_input]; 892 [stream->cap_session removeOutput:stream->video_output]; 677 893 [stream->cap_session release]; 678 stream->cap_session = NULL;894 stream->cap_session = nil; 679 895 } 680 /* if (stream->dev_input) { 681 [stream->dev_input release]; 682 stream->dev_input = NULL; 683 } 684 */ 896 if (stream->dev_input) { 897 stream->dev_input = nil; 898 } 899 685 900 if (stream->vout_delegate) { 686 901 [stream->vout_delegate release]; 687 stream->vout_delegate = NULL; 688 } 689 /* if (stream->video_output) { 690 [stream->video_output release]; 691 stream->video_output = NULL; 692 } 693 */ 694 if (stream->render_queue) { 695 dispatch_release(stream->render_queue); 696 stream->render_queue = NULL; 902 stream->vout_delegate = nil; 903 } 904 if (stream->video_output) { 905 stream->video_output = nil; 906 } 907 908 if (stream->render_view) { 909 dispatch_async(dispatch_get_main_queue(), 910 ^{ 911 [stream->render_view removeFromSuperview]; 912 [stream->render_view release]; 913 }); 914 stream->render_view = NULL; 915 } 916 917 if (stream->render_data_provider) { 918 CGDataProviderRelease(stream->render_data_provider); 919 stream->render_data_provider = NULL; 697 920 } 698 921 … … 702 925 } 703 926 704 #endif 927 #endif /* __IPHONE_4_0 */ 705 928 #endif /* PJMEDIA_VIDEO_DEV_HAS_IOS */
Note: See TracChangeset
for help on using the changeset viewer.