Ignore:
Timestamp:
Jun 25, 2015 8:17:52 AM (9 years ago)
Author:
ming
Message:

Re #1861: Initial implementation of video orientation support

  • Utility to resize and rotate video frame
  • Support for iOS + sample
  • pjsua API to set video device's orientation
File:
1 edited

Legend:

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

    r5054 r5118  
    1717 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
    1818 */ 
     19#include "util.h" 
    1920#include <pjmedia-videodev/videodev_imp.h> 
    2021#include <pj/assert.h> 
     
    3738#define DEFAULT_HEIGHT          288 
    3839#define DEFAULT_FPS             15 
     40 
     41/* Define whether we should maintain the aspect ratio when rotating the image. 
     42 * For more details, please refer to vid_util.h. 
     43 */ 
     44#define MAINTAIN_ASPECT_RATIO PJ_TRUE 
    3945 
    4046typedef struct ios_fmt_info 
     
    109115    NSLock                 *frame_lock; 
    110116    void                   *capture_buf; 
     117    void                   *frame_buf; 
     118     
     119    pjmedia_vid_dev_conv    conv; 
     120    pjmedia_rect_size       vid_size; 
    111121     
    112122    AVCaptureSession            *cap_session; 
     
    314324                                                       ios_sizes[m].preset_str]) 
    315325                    { 
     326                        /* Landscape video */ 
    316327                        fmt = &qdi->info.fmt[qdi->info.fmt_cnt++]; 
    317328                        pjmedia_format_init_video(fmt, 
     
    319330                                                  ios_sizes[m].supported_size_w, 
    320331                                                  ios_sizes[m].supported_size_h, 
     332                                                  DEFAULT_FPS, 1); 
     333                        /* Portrait video */ 
     334                        fmt = &qdi->info.fmt[qdi->info.fmt_cnt++]; 
     335                        pjmedia_format_init_video(fmt, 
     336                                                  ios_fmts[l].pjmedia_format, 
     337                                                  ios_sizes[m].supported_size_h, 
     338                                                  ios_sizes[m].supported_size_w, 
    321339                                                  DEFAULT_FPS, 1); 
    322340                    } 
     
    436454{ 
    437455    CVImageBufferRef img; 
     456    pj_status_t status; 
     457    void *frame_buf; 
    438458 
    439459    /* Refrain from calling pjlib functions which require thread registration 
     
    452472    /* Lock the base address of the pixel buffer */ 
    453473    CVPixelBufferLockBaseAddress(img, kCVPixelBufferLock_ReadOnly); 
    454      
    455474 
    456475    [stream->frame_lock lock]; 
     
    464483             */ 
    465484            pj_size_t stride = CVPixelBufferGetBytesPerRowOfPlane(img, 0); 
    466             pj_bool_t need_clip = (stride != stream->size.w); 
     485            pj_size_t height = CVPixelBufferGetHeight(img); 
     486            pj_bool_t need_clip; 
     487             
     488            /* Auto detect rotation */ 
     489            if (height != stream->vid_size.h) { 
     490                stream->vid_size.w = stream->vid_size.h; 
     491                stream->vid_size.h = height; 
     492            } 
     493             
     494            need_clip = (stride != stream->vid_size.w); 
    467495             
    468496            p = (pj_uint8_t*)CVPixelBufferGetBaseAddressOfPlane(img, 0); 
    469             p_len = stream->size.w * stream->size.h; 
     497            p_len = stream->vid_size.w * stream->vid_size.h; 
    470498            Y = (pj_uint8_t*)stream->capture_buf; 
    471499            U = Y + p_len; 
     
    476504            } else { 
    477505                int i = 0; 
    478                 for (;i<stream->size.h;++i) { 
    479                     pj_memcpy(Y+(i*stream->size.w), p+(i*stride), 
    480                               stream->size.w); 
     506                for (; i < stream->vid_size.h; ++i) { 
     507                    pj_memcpy(Y, p, stream->vid_size.w); 
     508                    Y += stream->vid_size.w; 
     509                    p += stride; 
    481510                } 
    482511            } 
     
    493522            } else { 
    494523                int i = 0; 
    495                 for (;i<(stream->size.h)/2;++i) { 
     524                for (;i<(stream->vid_size.h)/2;++i) { 
    496525                    int y=0; 
    497                     for (;y<(stream->size.w)/2;++y) { 
     526                    for (;y<(stream->vid_size.w)/2;++y) { 
    498527                        *U++ = *p++; 
    499528                        *V++ = *p++; 
    500529                    } 
    501                     p += (stride - stream->size.w); 
     530                    p += (stride - stream->vid_size.w); 
    502531                } 
    503532            } 
     
    506535        pj_memcpy(stream->capture_buf, CVPixelBufferGetBaseAddress(img), 
    507536                  stream->frame_size); 
     537    } 
     538     
     539    status = pjmedia_vid_dev_conv_resize_and_rotate(&stream->conv,  
     540                                                    stream->capture_buf, 
     541                                                    &frame_buf); 
     542    if (status == PJ_SUCCESS) { 
     543        stream->frame_buf = frame_buf; 
    508544    } 
    509545 
     
    528564     
    529565    [stream->frame_lock lock]; 
    530     pj_memcpy(frame->buf, stream->capture_buf, stream->frame_size); 
     566    pj_memcpy(frame->buf, stream->frame_buf, stream->frame_size); 
    531567    [stream->frame_lock unlock]; 
    532568     
     
    646682  
    647683        for (i = PJ_ARRAY_SIZE(ios_sizes)-1; i > 0; --i) { 
    648             if ((vfd->size.w == ios_sizes[i].supported_size_w) && 
    649                 (vfd->size.h == ios_sizes[i].supported_size_h)) 
     684            if (((vfd->size.w == ios_sizes[i].supported_size_w) && 
     685                 (vfd->size.h == ios_sizes[i].supported_size_h)) || 
     686                ((vfd->size.w == ios_sizes[i].supported_size_h) && 
     687                 (vfd->size.h == ios_sizes[i].supported_size_w))) 
    650688            { 
    651689                break; 
     
    655693        strm->cap_session.sessionPreset = ios_sizes[i].preset_str; 
    656694         
    657         vfd->size.w = ios_sizes[i].supported_size_w; 
    658         vfd->size.h = ios_sizes[i].supported_size_h; 
     695        /* If the requested size is portrait (or landscape), we make 
     696         * our natural orientation portrait (or landscape) as well. 
     697         */ 
     698        if (vfd->size.w > vfd->size.h) { 
     699            vfd->size.w = ios_sizes[i].supported_size_w; 
     700            vfd->size.h = ios_sizes[i].supported_size_h; 
     701        } else { 
     702            vfd->size.h = ios_sizes[i].supported_size_w; 
     703            vfd->size.w = ios_sizes[i].supported_size_h; 
     704        } 
    659705        strm->size = vfd->size; 
     706        strm->vid_size = vfd->size; 
    660707        strm->bytes_per_row = strm->size.w * vfi->bpp / 8; 
    661708        strm->frame_size = strm->bytes_per_row * strm->size.h; 
     
    724771         
    725772        strm->capture_buf = pj_pool_alloc(strm->pool, strm->frame_size); 
     773        strm->frame_buf = strm->capture_buf; 
    726774        strm->frame_lock = [[NSLock alloc]init]; 
    727775         
     
    730778            ios_stream_set_cap(&strm->base, PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW, 
    731779                               &param->native_preview); 
     780        } 
     781 
     782        /* Video orientation. 
     783         * If we send in portrait, we need to set up orientation converter 
     784         * as well. 
     785         */ 
     786        if ((param->flags & PJMEDIA_VID_DEV_CAP_ORIENTATION) || 
     787            (vfd->size.h > vfd->size.w)) 
     788        { 
     789            if (param->orient == PJMEDIA_ORIENT_UNKNOWN) 
     790                param->orient = PJMEDIA_ORIENT_NATURAL; 
     791            ios_stream_set_cap(&strm->base, PJMEDIA_VID_DEV_CAP_ORIENTATION, 
     792                               &param->orient); 
    732793        } 
    733794         
     
    9881049        } 
    9891050             
    990         /* TODO: orientation for capture device */ 
    9911051        case PJMEDIA_VID_DEV_CAP_ORIENTATION: 
    9921052        { 
     1053            pjmedia_orient orient = *(pjmedia_orient *)pval; 
     1054 
     1055            pj_assert(orient >= PJMEDIA_ORIENT_UNKNOWN && 
     1056                      orient <= PJMEDIA_ORIENT_ROTATE_270DEG); 
     1057 
     1058            if (orient == PJMEDIA_ORIENT_UNKNOWN) 
     1059                return PJ_EINVAL; 
     1060 
    9931061            pj_memcpy(&strm->param.orient, pval, 
    9941062                      sizeof(strm->param.orient)); 
    995             if (strm->param.orient == PJMEDIA_ORIENT_UNKNOWN) 
    996                 return PJ_SUCCESS; 
    997              
    998             dispatch_async(dispatch_get_main_queue(), ^{ 
    999                 strm->render_view.transform = 
    1000                     CGAffineTransformMakeRotation( 
    1001                         ((int)strm->param.orient-1) * -M_PI_2); 
    1002             }); 
     1063         
     1064            if (strm->param.dir == PJMEDIA_DIR_RENDER) { 
     1065                dispatch_async(dispatch_get_main_queue(), ^{ 
     1066                    strm->render_view.transform = 
     1067                        CGAffineTransformMakeRotation( 
     1068                            ((int)strm->param.orient-1) * -M_PI_2); 
     1069                }); 
     1070 
     1071                return PJ_SUCCESS; 
     1072            } 
     1073         
     1074            const AVCaptureVideoOrientation cap_ori[4] = 
     1075            { 
     1076                AVCaptureVideoOrientationLandscapeLeft,      /* NATURAL */ 
     1077                AVCaptureVideoOrientationPortrait,           /* 90DEG   */ 
     1078                AVCaptureVideoOrientationLandscapeRight,     /* 180DEG  */ 
     1079                AVCaptureVideoOrientationPortraitUpsideDown, /* 270DEG  */ 
     1080            }; 
     1081            AVCaptureConnection *vidcon; 
     1082            pj_bool_t support_ori = PJ_TRUE; 
     1083             
     1084            pj_assert(strm->param.dir == PJMEDIA_DIR_CAPTURE); 
     1085             
     1086            if (!strm->video_output) 
     1087                return PJMEDIA_EVID_NOTREADY; 
     1088 
     1089            vidcon = [strm->video_output  
     1090                      connectionWithMediaType:AVMediaTypeVideo]; 
     1091            if ([vidcon isVideoOrientationSupported]) { 
     1092                vidcon.videoOrientation = cap_ori[strm->param.orient-1]; 
     1093            } else { 
     1094                support_ori = PJ_FALSE; 
     1095            } 
     1096             
     1097            if (!strm->conv.conv) { 
     1098                pj_status_t status; 
     1099                pjmedia_rect_size orig_size; 
     1100 
     1101                /* Original native size of device is landscape */ 
     1102                orig_size.w = (strm->size.w > strm->size.h? strm->size.w : 
     1103                               strm->size.h); 
     1104                orig_size.h = (strm->size.w > strm->size.h? strm->size.h : 
     1105                               strm->size.w); 
     1106 
     1107                if (!support_ori) { 
     1108                    PJ_LOG(4, (THIS_FILE, "Native video capture orientation "  
     1109                                          "unsupported, will use converter's " 
     1110                                          "rotation.")); 
     1111                } 
     1112 
     1113                status = pjmedia_vid_dev_conv_create_converter( 
     1114                                                 &strm->conv, strm->pool, 
     1115                                                 &strm->param.fmt, 
     1116                                                 orig_size, strm->size, 
     1117                                                 (support_ori?PJ_FALSE:PJ_TRUE), 
     1118                                                 MAINTAIN_ASPECT_RATIO); 
     1119                 
     1120                if (status != PJ_SUCCESS) 
     1121                    return status; 
     1122            } 
     1123             
     1124            pjmedia_vid_dev_conv_set_rotation(&strm->conv, strm->param.orient); 
     1125             
     1126            PJ_LOG(5, (THIS_FILE, "Video capture orientation set to %d", 
     1127                                  strm->param.orient)); 
     1128 
    10031129            return PJ_SUCCESS; 
    10041130        } 
     
    11411267        stream->frame_lock = nil; 
    11421268    } 
     1269     
     1270    pjmedia_vid_dev_conv_destroy_converter(&stream->conv); 
    11431271 
    11441272    pj_pool_release(stream->pool); 
Note: See TracChangeset for help on using the changeset viewer.