Changeset 4824 for pjproject


Ignore:
Timestamp:
Apr 24, 2014 8:37:45 AM (8 years ago)
Author:
nanang
Message:

Re #1762:

  • enumerate all capture devices
  • fast switch between capture devices
  • enhance simple renderer (a bit simpler, add capabilities)
File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia-videodev/ios_dev.m

    r4722 r4824  
    3030#import <UIKit/UIKit.h> 
    3131#import <AVFoundation/AVFoundation.h> 
     32#import <QuartzCore/QuartzCore.h> 
    3233 
    3334#define THIS_FILE               "ios_dev.c" 
    3435#define DEFAULT_CLOCK_RATE      90000 
    35 #define DEFAULT_WIDTH           480 
    36 #define DEFAULT_HEIGHT          360 
     36#define DEFAULT_WIDTH           352 
     37#define DEFAULT_HEIGHT          288 
    3738#define DEFAULT_FPS             15 
    3839 
     
    4546static ios_fmt_info ios_fmts[] = 
    4647{ 
    47     {PJMEDIA_FORMAT_BGRA, kCVPixelFormatType_32BGRA} , 
     48    { PJMEDIA_FORMAT_BGRA, kCVPixelFormatType_32BGRA } 
    4849}; 
    4950 
     
    5253{ 
    5354    pjmedia_vid_dev_info         info; 
     55    AVCaptureDevice             *dev; 
    5456}; 
    5557 
     
    7981    pjmedia_vid_dev_param   param;              /**< Settings          */ 
    8082    pj_pool_t              *pool;               /**< Memory pool       */ 
     83    struct ios_factory     *factory;            /**< Factory           */ 
    8184 
    8285    pjmedia_vid_dev_cb      vid_cb;             /**< Stream callback   */ 
     
    9396    VOutDelegate                *vout_delegate; 
    9497     
    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; 
    98102     
    99103    pj_timestamp         frame_ts; 
    100104    unsigned             ts_inc; 
     105 
     106    pj_bool_t            thread_initialized; 
     107    pj_thread_desc       thread_desc; 
     108    pj_thread_t         *thread; 
    101109}; 
    102110 
     
    186194    struct ios_factory *qf = (struct ios_factory*)f; 
    187195    struct ios_dev_info *qdi; 
    188     unsigned i, l; 
     196    unsigned i, l, first_idx, front_idx = -1; 
     197    enum { MAX_DEV_COUNT = 8 }; 
    189198     
    190199    /* Initialize input and output devices here */ 
    191200    qf->dev_info = (struct ios_dev_info*) 
    192                    pj_pool_calloc(qf->pool, 2, 
     201                   pj_pool_calloc(qf->pool, MAX_DEV_COUNT, 
    193202                                  sizeof(struct ios_dev_info)); 
    194      
    195203    qf->dev_count = 0; 
     204     
     205    /* Init output device */ 
    196206    qdi = &qf->dev_info[qf->dev_count++]; 
    197207    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)); 
    200210    qdi->info.dir = PJMEDIA_DIR_RENDER; 
    201211    qdi->info.has_callback = PJ_FALSE; 
    202212    qdi->info.caps = PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW; 
    203213     
     214    /* Init input device */ 
     215    first_idx = qf->dev_count; 
    204216    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 */ 
    213252    for (i = 0; i < qf->dev_count; i++) { 
    214253        qdi = &qf->dev_info[i]; 
     
    226265    } 
    227266     
    228     PJ_LOG(4, (THIS_FILE, "iOS video initialized with %d devices", 
     267    PJ_LOG(4, (THIS_FILE, "iOS video initialized with %d devices:", 
    229268               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 
    231276    return PJ_SUCCESS; 
    232277} 
     
    279324{ 
    280325    struct ios_factory *qf = (struct ios_factory*)f; 
    281     struct ios_dev_info *di = &qf->dev_info[index]; 
     326    struct ios_dev_info *di; 
    282327 
    283328    PJ_ASSERT_RETURN(index < qf->dev_count, PJMEDIA_EVID_INVDEV); 
    284  
    285329    PJ_UNUSED_ARG(pool); 
     330     
     331    di = &qf->dev_info[index]; 
    286332 
    287333    pj_bzero(param, sizeof(*param)); 
     
    309355{     
    310356    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); 
    330364    CGColorSpaceRelease(colorSpace); 
    331365     
    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 
    346369    [pool release]; 
    347370}     
     
    361384     
    362385    /* Lock the base address of the pixel buffer */ 
    363     CVPixelBufferLockBaseAddress(imageBuffer, 0);  
     386    CVPixelBufferLockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly); 
    364387     
    365388    frame.type = PJMEDIA_FRAME_TYPE_VIDEO; 
     
    369392    frame.timestamp.u64 = stream->frame_ts.u64; 
    370393     
    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 
    372403        (*stream->vid_cb.capture_cb)(&stream->base, stream->user_data, &frame); 
     404    } 
    373405 
    374406    stream->frame_ts.u64 += stream->ts_inc; 
    375407     
    376408    /* Unlock the pixel buffer */ 
    377     CVPixelBufferUnlockBaseAddress(imageBuffer,0); 
     409    CVPixelBufferUnlockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly); 
    378410} 
    379411@end 
     
    390422    return NULL; 
    391423} 
     424 
     425 
     426static 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                           &param->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                           &param->orient); 
     457    } 
     458 
     459    return PJ_SUCCESS; 
     460} 
     461 
    392462 
    393463/* API: create stream */ 
     
    402472    pj_pool_t *pool; 
    403473    struct ios_stream *strm; 
    404     const pjmedia_video_format_detail *vfd; 
     474    pjmedia_video_format_detail *vfd; 
    405475    const pjmedia_video_format_info *vfi; 
    406476    pj_status_t status = PJ_SUCCESS; 
    407477    ios_fmt_info *ifi = get_ios_format_info(param->fmt.id); 
    408     NSError *error; 
    409478 
    410479    PJ_ASSERT_RETURN(f && param && p_vid_strm, PJ_EINVAL); 
     
    431500    pj_memcpy(&strm->vid_cb, cb, sizeof(*cb)); 
    432501    strm->user_data = user_data; 
    433  
     502    strm->factory = qf; 
     503     
    434504    vfd = pjmedia_format_get_video_format_detail(&strm->param.fmt, PJ_TRUE); 
    435505    pj_memcpy(&strm->size, &vfd->size, sizeof(vfd->size)); 
     
    446516            goto on_error; 
    447517        } 
    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 
    461546                           error: &error]; 
    462547        if (!strm->dev_input) { 
     
    472557            goto on_error; 
    473558        } 
     559         
     560        strm->video_output.alwaysDiscardsLateVideoFrames = YES; 
    474561        [strm->cap_session addOutput:strm->video_output]; 
    475562         
     
    479566        dispatch_queue_t queue = dispatch_queue_create("myQueue", NULL); 
    480567        [strm->video_output setSampleBufferDelegate:strm->vout_delegate 
    481                             queue:queue]; 
    482         dispatch_release(queue);         
     568                                              queue:queue]; 
     569        dispatch_release(queue); 
    483570         
    484571        strm->video_output.videoSettings = 
    485572            [NSDictionary dictionaryWithObjectsAndKeys: 
    486573                          [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         
    494599    } else if (param->dir & PJMEDIA_DIR_RENDER) { 
     600 
    495601        /* 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         
    511607        if (!strm->vout_delegate) { 
    512608            strm->vout_delegate = [VOutDelegate alloc]; 
     
    514610        } 
    515611         
    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                           &param->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     
    532619    /* Done */ 
    533620    strm->base.op = &stream_op; 
     
    552639    pj_memcpy(pi, &strm->param, sizeof(*pi)); 
    553640 
    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 */ 
    560641    return PJ_SUCCESS; 
    561642} 
     
    567648{ 
    568649    struct ios_stream *strm = (struct ios_stream*)s; 
    569  
    570     PJ_UNUSED_ARG(strm); 
    571  
     650     
    572651    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL); 
    573652 
    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; 
    581667} 
    582668 
     
    588674    struct ios_stream *strm = (struct ios_stream*)s; 
    589675 
    590     PJ_UNUSED_ARG(strm); 
    591  
    592676    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL); 
    593677 
    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; 
    597819    } 
    598820 
     
    607829    PJ_UNUSED_ARG(stream); 
    608830 
    609     PJ_LOG(4, (THIS_FILE, "Starting ios video stream")); 
     831    PJ_LOG(4, (THIS_FILE, "Starting iOS video stream")); 
    610832 
    611833    if (stream->cap_session) { 
     
    625847{ 
    626848    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     
    631856    /* 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(), 
    638858                   ^{[stream->vout_delegate update_image];}); 
    639      
    640     [pool release]; 
     859 
     860    //[pool release]; 
    641861     
    642862    return PJ_SUCCESS; 
     
    650870    PJ_UNUSED_ARG(stream); 
    651871 
    652     PJ_LOG(4, (THIS_FILE, "Stopping ios video stream")); 
     872    PJ_LOG(4, (THIS_FILE, "Stopping iOS video stream")); 
    653873 
    654874    if (stream->cap_session && [stream->cap_session isRunning]) 
     
    668888    ios_stream_stop(strm); 
    669889     
    670     if (stream->imgView) { 
    671         [stream->imgView removeFromSuperview]; 
    672         [stream->imgView release]; 
    673         stream->imgView = NULL; 
    674     } 
    675  
    676890    if (stream->cap_session) { 
     891        [stream->cap_session removeInput:stream->dev_input]; 
     892        [stream->cap_session removeOutput:stream->video_output]; 
    677893        [stream->cap_session release]; 
    678         stream->cap_session = NULL; 
     894        stream->cap_session = nil; 
    679895    }     
    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  
    685900    if (stream->vout_delegate) { 
    686901        [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; 
    697920    } 
    698921 
     
    702925} 
    703926 
    704 #endif 
     927#endif  /* __IPHONE_4_0 */ 
    705928#endif  /* PJMEDIA_VIDEO_DEV_HAS_IOS */ 
Note: See TracChangeset for help on using the changeset viewer.