Changeset 4836


Ignore:
Timestamp:
May 6, 2014 12:55:49 PM (11 years ago)
Author:
nanang
Message:

Re #1762: Add I420/IYUV output format to capture devices.

File:
1 edited

Legend:

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

    r4834 r4836  
    4646static ios_fmt_info ios_fmts[] = 
    4747{ 
    48     { PJMEDIA_FORMAT_BGRA, kCVPixelFormatType_32BGRA } 
     48    { PJMEDIA_FORMAT_BGRA, kCVPixelFormatType_32BGRA }, 
     49    { PJMEDIA_FORMAT_I420, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange } 
    4950}; 
    5051 
     
    8788 
    8889    pjmedia_rect_size       size; 
    89     pj_uint8_t              bpp; 
    9090    unsigned                bytes_per_row; 
    91     unsigned                frame_size; 
     91    unsigned                frame_size;         /**< Frame size (bytes)*/ 
     92    pj_bool_t               is_planar; 
    9293     
    9394    AVCaptureSession            *cap_session; 
     
    9596    AVCaptureVideoDataOutput    *video_output; 
    9697    VOutDelegate                *vout_delegate; 
     98    void                        *capture_buf; 
    9799     
    98100    void                *render_buf; 
     
    210212    qdi->info.dir = PJMEDIA_DIR_RENDER; 
    211213    qdi->info.has_callback = PJ_FALSE; 
    212     qdi->info.caps = PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW; 
    213214     
    214215    /* Init input device */ 
     
    230231            qdi = &qf->dev_info[qf->dev_count++]; 
    231232            pj_bzero(qdi, sizeof(*qdi)); 
    232             pj_ansi_strncpy(qdi->info.name, [[device localizedName] UTF8String], 
     233            pj_ansi_strncpy(qdi->info.name, [device.localizedName UTF8String], 
    233234                            sizeof(qdi->info.name)); 
    234235            pj_ansi_strncpy(qdi->info.driver, "iOS", sizeof(qdi->info.driver)); 
     
    236237            qdi->info.has_callback = PJ_TRUE; 
    237238            qdi->info.caps = PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW | 
    238                              PJMEDIA_VID_DEV_CAP_SWITCH | 
    239                              PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW; 
     239                             PJMEDIA_VID_DEV_CAP_SWITCH; 
    240240            qdi->dev = device; 
    241241        } 
     
    252252    for (i = 0; i < qf->dev_count; i++) { 
    253253        qdi = &qf->dev_info[i]; 
    254         qdi->info.fmt_cnt = PJ_ARRAY_SIZE(ios_fmts);         
    255254        qdi->info.caps |= PJMEDIA_VID_DEV_CAP_FORMAT | 
     255                          PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW | 
    256256                          PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE | 
    257257                          PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION | 
     
    260260         
    261261        for (l = 0; l < PJ_ARRAY_SIZE(ios_fmts); l++) { 
    262             pjmedia_format *fmt = &qdi->info.fmt[l]; 
     262            pjmedia_format *fmt; 
     263             
     264            /* Simple renderer UIView only supports BGRA */ 
     265            if (qdi->info.dir == PJMEDIA_DIR_RENDER && 
     266                ios_fmts[l].pjmedia_format != PJMEDIA_FORMAT_BGRA) 
     267            { 
     268                continue; 
     269            } 
     270                 
     271            fmt = &qdi->info.fmt[qdi->info.fmt_cnt++]; 
    263272            pjmedia_format_init_video(fmt, 
    264273                                      ios_fmts[l].pjmedia_format, 
     
    378387                      fromConnection:(AVCaptureConnection *)connection 
    379388{ 
    380     pjmedia_frame frame; 
    381     CVImageBufferRef imageBuffer; 
     389    pjmedia_frame frame = {0}; 
     390    CVImageBufferRef img; 
    382391 
    383392    if (!sampleBuffer) 
     
    385394     
    386395    /* Get a CMSampleBuffer's Core Video image buffer for the media data */ 
    387     imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);  
     396    img = CMSampleBufferGetImageBuffer(sampleBuffer); 
    388397     
    389398    /* Lock the base address of the pixel buffer */ 
    390     CVPixelBufferLockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly); 
     399    CVPixelBufferLockBaseAddress(img, kCVPixelBufferLock_ReadOnly); 
    391400     
    392401    frame.type = PJMEDIA_FRAME_TYPE_VIDEO; 
    393     frame.buf = CVPixelBufferGetBaseAddress(imageBuffer); 
    394402    frame.size = stream->frame_size; 
    395     frame.bit_info = 0; 
    396403    frame.timestamp.u64 = stream->frame_ts.u64; 
     404 
     405    if (stream->is_planar && stream->capture_buf) { 
     406        if (stream->param.fmt.id == PJMEDIA_FORMAT_I420) { 
     407            /* kCVPixelFormatType_420YpCbCr8BiPlanar* is NV12 */ 
     408            pj_uint8_t *p, *p_end, *Y, *U, *V; 
     409            pj_size_t p_len; 
     410             
     411            p = (pj_uint8_t*)CVPixelBufferGetBaseAddressOfPlane(img, 0); 
     412            p_len = stream->size.w * stream->size.h; 
     413            Y = (pj_uint8_t*)stream->capture_buf; 
     414            U = Y + p_len; 
     415            V = U + p_len/4; 
     416            pj_memcpy(Y, p, p_len); 
     417             
     418            p = (pj_uint8_t*)CVPixelBufferGetBaseAddressOfPlane(img, 1); 
     419            p_len >>= 1; 
     420            p_end = p + p_len; 
     421            while (p < p_end) { 
     422                *U++ = *p++; 
     423                *V++ = *p++; 
     424            } 
     425 
     426            frame.buf = stream->capture_buf; 
     427        } 
     428    } else { 
     429        frame.buf = CVPixelBufferGetBaseAddress(img); 
     430    } 
    397431     
    398432    if (stream->vid_cb.capture_cb) { 
     
    411445     
    412446    /* Unlock the pixel buffer */ 
    413     CVPixelBufferUnlockBaseAddress(imageBuffer, kCVPixelBufferLock_ReadOnly); 
     447    CVPixelBufferUnlockBaseAddress(img, kCVPixelBufferLock_ReadOnly); 
    414448} 
    415449@end 
     
    508542    vfd = pjmedia_format_get_video_format_detail(&strm->param.fmt, PJ_TRUE); 
    509543    pj_memcpy(&strm->size, &vfd->size, sizeof(vfd->size)); 
    510     strm->bpp = vfi->bpp; 
    511     strm->bytes_per_row = strm->size.w * strm->bpp / 8; 
     544    strm->bytes_per_row = strm->size.w * vfi->bpp / 8; 
    512545    strm->frame_size = strm->bytes_per_row * strm->size.h; 
    513546    strm->ts_inc = PJMEDIA_SPF2(param->clock_rate, &vfd->fps, 1); 
     547    strm->is_planar = vfi->plane_cnt > 1; 
    514548 
    515549    if (param->dir & PJMEDIA_DIR_CAPTURE) { 
     
    526560        vfd->size.h = 288; 
    527561        strm->size = vfd->size; 
    528         strm->bytes_per_row = strm->size.w * strm->bpp / 8; 
     562        strm->bytes_per_row = strm->size.w * vfi->bpp / 8; 
    529563        strm->frame_size = strm->bytes_per_row * strm->size.h; 
    530564         
     
    578612                          kCVPixelBufferPixelFormatTypeKey, nil]; 
    579613         
     614        /* Prepare capture buffer if it's planar format */ 
     615        if (strm->is_planar) 
     616            strm->capture_buf = pj_pool_alloc(strm->pool, strm->frame_size); 
     617         
    580618        /* Native preview */ 
    581619        if (param->flags & PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW) { 
     
    677715            ios_init_view(strm); 
    678716             
     717            CALayer *view_layer = strm->render_view.layer; 
     718            CGRect r = strm->render_view.bounds; 
     719             
    679720            /* Preview layer instantiation should be in main thread! */ 
    680721            dispatch_async(dispatch_get_main_queue(), ^{ 
    681722                /* Create preview layer */ 
    682                 AVCaptureVideoPreviewLayer *previewLayer = 
    683                 [AVCaptureVideoPreviewLayer layerWithSession:strm->cap_session]; 
     723                AVCaptureVideoPreviewLayer *prev_layer = 
     724                            [AVCaptureVideoPreviewLayer 
     725                             layerWithSession:strm->cap_session]; 
    684726                 
    685727                /* Attach preview layer to a UIView */ 
    686                 CGRect r = strm->render_view.bounds; 
    687                 previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; 
    688                 previewLayer.frame = r; 
    689                 [[strm->render_view layer] addSublayer:previewLayer]; 
     728                prev_layer.videoGravity = AVLayerVideoGravityResizeAspectFill; 
     729                prev_layer.frame = r; 
     730                [view_layer addSublayer:prev_layer]; 
     731                PJ_LOG(4, (THIS_FILE, "Native preview initialized")); 
    690732            }); 
    691              
    692             NSLog(@"Native preview initialized."); 
    693733             
    694734            return PJ_SUCCESS; 
     
    721761            /* Ok, let's do the switch */ 
    722762            AVCaptureDeviceInput *cur_dev_input = strm->dev_input; 
    723                     //[AVCaptureDeviceInput 
    724                     // deviceInputWithDevice:di[strm->param.cap_id].dev 
    725                     // error:&error]; 
    726763            AVCaptureDeviceInput *new_dev_input = 
    727764                    [AVCaptureDeviceInput 
     
    750787                return PJMEDIA_EVID_BADFORMAT; 
    751788         
    752             vfi = pjmedia_get_video_format_info(pjmedia_video_format_mgr_instance(), 
    753                                                 fmt->id); 
     789            vfi = pjmedia_get_video_format_info( 
     790                                        pjmedia_video_format_mgr_instance(), 
     791                                        fmt->id); 
    754792            if (!vfi) 
    755793                return PJMEDIA_EVID_BADFORMAT; 
     
    759797            vfd = pjmedia_format_get_video_format_detail(fmt, PJ_TRUE); 
    760798            pj_memcpy(&strm->size, &vfd->size, sizeof(vfd->size)); 
    761             strm->bytes_per_row = strm->size.w * strm->bpp / 8; 
     799            strm->bytes_per_row = strm->size.w * vfi->bpp / 8; 
    762800            strm->frame_size = strm->bytes_per_row * strm->size.h; 
    763801            if (strm->render_buf_size < strm->frame_size) { 
     802                /* Realloc only when needed */ 
    764803                strm->render_buf = pj_pool_alloc(strm->pool, strm->frame_size); 
    765804                strm->render_buf_size = strm->frame_size; 
    766805                CGDataProviderRelease(strm->render_data_provider); 
    767806                strm->render_data_provider = CGDataProviderCreateWithData(NULL, 
    768                                                         strm->render_buf, strm->frame_size, 
     807                                                        strm->render_buf, 
     808                                                        strm->frame_size, 
    769809                                                        NULL); 
    770810            } 
     
    777817            UIView *view = (UIView *)pval; 
    778818            strm->param.window.info.ios.window = (void *)pval; 
    779             dispatch_async(dispatch_get_main_queue(), 
    780                            ^{[view addSubview:strm->render_view];}); 
     819            dispatch_async(dispatch_get_main_queue(), ^{ 
     820                [view addSubview:strm->render_view]; 
     821            }); 
    781822            return PJ_SUCCESS; 
    782823        } 
Note: See TracChangeset for help on using the changeset viewer.