Ignore:
Timestamp:
Sep 19, 2011 8:26:35 AM (13 years ago)
Author:
bennylp
Message:

Implemented native video preview support. This closes #1340

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/src/pjsua-lib/pjsua_vid.c

    r3753 r3756  
    2424#if PJSUA_HAS_VIDEO 
    2525 
    26 #define ENABLE_EVENT        0 
    27 #define VID_TEE_MAX_PORT    (PJSUA_MAX_CALLS + 1) 
     26#define ENABLE_EVENT            0 
     27#define VID_TEE_MAX_PORT        (PJSUA_MAX_CALLS + 1) 
     28 
     29#define PJSUA_SHOW_WINDOW       1 
     30#define PJSUA_HIDE_WINDOW       0 
     31 
    2832 
    2933static void free_vid_win(pjsua_vid_win_id wid); 
     
    125129} 
    126130 
     131PJ_DEF(const char*) pjsua_vid_win_type_name(pjsua_vid_win_type wt) 
     132{ 
     133    const char *win_type_names[] = { 
     134         "none", 
     135         "preview", 
     136         "stream" 
     137    }; 
     138 
     139    return (wt < PJ_ARRAY_SIZE(win_type_names)) ? win_type_names[wt] : "??"; 
     140} 
     141 
    127142PJ_DEF(void) 
    128143pjsua_call_vid_strm_op_param_default(pjsua_call_vid_strm_op_param *param) 
     
    338353} 
    339354 
     355PJ_DEF(void) pjsua_vid_win_reset(pjsua_vid_win_id wid) 
     356{ 
     357    pjsua_vid_win *w = &pjsua_var.win[wid]; 
     358    pj_pool_t *pool = w->pool; 
     359 
     360    pj_bzero(w, sizeof(*w)); 
     361    if (pool) pj_pool_reset(pool); 
     362    w->ref_cnt = 0; 
     363    w->pool = pool; 
     364    w->preview_cap_id = PJMEDIA_VID_INVALID_DEV; 
     365} 
    340366 
    341367/* Allocate and initialize pjsua video window: 
     
    351377                                  pjsua_vid_win_id *id) 
    352378{ 
     379    pj_bool_t enable_native_preview; 
    353380    pjsua_vid_win_id wid = PJSUA_INVALID_ID; 
    354381    pjsua_vid_win *w = NULL; 
     
    358385    unsigned i; 
    359386 
    360     PJ_LOG(4,(THIS_FILE, "Creating window, type=%d, cap_dev=%d, rend_dev=%d", 
    361               type, cap_id, rend_id)); 
     387    enable_native_preview = pjsua_var.media_cfg.vid_preview_enable_native; 
     388 
     389    PJ_LOG(4,(THIS_FILE, 
     390              "Creating video window: type=%s, cap_id=%d, rend_id=%d", 
     391              pjsua_vid_win_type_name(type), cap_id, rend_id)); 
    362392    pj_log_push_indent(); 
    363393 
     
    368398            /* Yes, it exists */ 
    369399            /* Show/hide window */ 
    370             pjmedia_vid_dev_stream *rdr; 
     400            pjmedia_vid_dev_stream *strm; 
    371401            pj_bool_t hide = !show; 
    372402 
    373             rdr = pjmedia_vid_port_get_stream(pjsua_var.win[wid].vp_rend); 
    374             pj_assert(rdr); 
     403            w = &pjsua_var.win[wid]; 
     404 
     405            PJ_LOG(4,(THIS_FILE, 
     406                      "Window already exists for cap_dev=%d, returning wid=%d", 
     407                      cap_id, wid)); 
     408 
     409 
     410            if (w->is_native) { 
     411                strm = pjmedia_vid_port_get_stream(w->vp_cap); 
     412            } else { 
     413                strm = pjmedia_vid_port_get_stream(w->vp_rend); 
     414            } 
     415 
     416            pj_assert(strm); 
    375417            status = pjmedia_vid_dev_stream_set_cap( 
    376                                     rdr, PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE, 
     418                                    strm, PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE, 
    377419                                    &hide); 
    378420 
     
    403445 
    404446    if (w->type == PJSUA_WND_TYPE_PREVIEW) { 
     447        pjmedia_vid_dev_info vdi; 
     448 
     449        /* 
     450         * Determine if the device supports native preview. 
     451         */ 
     452        status = pjmedia_vid_dev_get_info(cap_id, &vdi); 
     453        if (status != PJ_SUCCESS) 
     454            goto on_error; 
     455 
     456        if (enable_native_preview && 
     457             (vdi.caps & PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW)) 
     458        { 
     459            /* Device supports native preview! */ 
     460            w->is_native = PJ_TRUE; 
     461        } 
     462 
    405463        status = pjmedia_vid_dev_default_param(w->pool, cap_id, 
    406464                                               &vp_param.vidparam); 
    407465        if (status != PJ_SUCCESS) 
    408466            goto on_error; 
     467 
     468        if (w->is_native) { 
     469            vp_param.vidparam.flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE; 
     470            vp_param.vidparam.window_hide = !show; 
     471        } 
    409472 
    410473        /* Normalize capture ID, in case it was set to 
     
    435498        if (status != PJ_SUCCESS) 
    436499            goto on_error; 
    437     } 
    438  
    439     /* Create renderer video port */ 
    440     status = pjmedia_vid_dev_default_param(w->pool, rend_id, 
    441                                            &vp_param.vidparam); 
    442     if (status != PJ_SUCCESS) 
    443         goto on_error; 
    444  
    445     vp_param.active = (w->type == PJSUA_WND_TYPE_STREAM); 
    446     vp_param.vidparam.dir = PJMEDIA_DIR_RENDER; 
    447     vp_param.vidparam.fmt = *fmt; 
    448     vp_param.vidparam.disp_size = fmt->det.vid.size; 
    449     vp_param.vidparam.flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE; 
    450     vp_param.vidparam.window_hide = !show; 
    451  
    452     status = pjmedia_vid_port_create(w->pool, &vp_param, &w->vp_rend); 
    453     if (status != PJ_SUCCESS) 
    454         goto on_error; 
    455  
    456     /* For preview window, connect capturer & renderer (via tee) */ 
    457     if (w->type == PJSUA_WND_TYPE_PREVIEW) { 
    458         pjmedia_port *rend_port; 
    459  
    460         status = pjmedia_vid_port_connect(w->vp_cap, w->tee, PJ_FALSE); 
     500 
     501        /* If device supports native preview, enable it */ 
     502        if (w->is_native) { 
     503            pjmedia_vid_dev_stream *cap_dev; 
     504            pj_bool_t enabled = PJ_TRUE; 
     505 
     506            cap_dev = pjmedia_vid_port_get_stream(w->vp_cap); 
     507            status = pjmedia_vid_dev_stream_set_cap( 
     508                            cap_dev, PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW, 
     509                            &enabled); 
     510            if (status != PJ_SUCCESS) { 
     511                PJ_PERROR(1,(THIS_FILE, status, 
     512                             "Error activating native preview, falling back " 
     513                             "to software preview..")); 
     514                w->is_native = PJ_FALSE; 
     515            } 
     516        } 
     517    } 
     518 
     519    /* Create renderer video port, only if it's not a native preview */ 
     520    if (!w->is_native) { 
     521        status = pjmedia_vid_dev_default_param(w->pool, rend_id, 
     522                                               &vp_param.vidparam); 
    461523        if (status != PJ_SUCCESS) 
    462524            goto on_error; 
    463525 
    464         rend_port = pjmedia_vid_port_get_passive_port(w->vp_rend); 
    465         status = pjmedia_vid_tee_add_dst_port2(w->tee, 0, rend_port); 
     526        vp_param.active = (w->type == PJSUA_WND_TYPE_STREAM); 
     527        vp_param.vidparam.dir = PJMEDIA_DIR_RENDER; 
     528        vp_param.vidparam.fmt = *fmt; 
     529        vp_param.vidparam.disp_size = fmt->det.vid.size; 
     530        vp_param.vidparam.flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE; 
     531        vp_param.vidparam.window_hide = !show; 
     532 
     533        status = pjmedia_vid_port_create(w->pool, &vp_param, &w->vp_rend); 
    466534        if (status != PJ_SUCCESS) 
    467535            goto on_error; 
    468     } 
     536 
     537        /* For preview window, connect capturer & renderer (via tee) */ 
     538        if (w->type == PJSUA_WND_TYPE_PREVIEW) { 
     539            pjmedia_port *rend_port; 
     540 
     541            status = pjmedia_vid_port_connect(w->vp_cap, w->tee, PJ_FALSE); 
     542            if (status != PJ_SUCCESS) 
     543                goto on_error; 
     544 
     545            rend_port = pjmedia_vid_port_get_passive_port(w->vp_rend); 
     546            status = pjmedia_vid_tee_add_dst_port2(w->tee, 0, rend_port); 
     547            if (status != PJ_SUCCESS) 
     548                goto on_error; 
     549        } 
     550 
     551        PJ_LOG(4,(THIS_FILE, 
     552                  "%s window id %d created for cap_dev=%d rend_dev=%d", 
     553                  pjsua_vid_win_type_name(type), wid, cap_id, rend_id)); 
     554    } else { 
     555        PJ_LOG(4,(THIS_FILE, 
     556                  "Preview window id %d created for cap_dev %d, " 
     557                  "using built-in preview!", 
     558                  wid, cap_id)); 
     559    } 
     560 
    469561 
    470562    /* Done */ 
     
    734826            } 
    735827 
    736             /* Create preview video window */ 
    737             status = create_vid_win(PJSUA_WND_TYPE_PREVIEW, 
    738                                     &media_port->info.fmt, 
    739                                     call_med->strm.v.rdr_dev, 
    740                                     call_med->strm.v.cap_dev, 
    741                                     //acc->cfg.vid_rend_dev, 
    742                                     //acc->cfg.vid_cap_dev, 
    743                                     PJ_FALSE, 
    744                                     &wid); 
    745             if (status != PJ_SUCCESS) { 
     828            wid = pjsua_vid_preview_get_win(call_med->strm.v.cap_dev); 
     829            if (wid == PJSUA_INVALID_ID) { 
     830                /* Create preview video window */ 
     831                status = create_vid_win(PJSUA_WND_TYPE_PREVIEW, 
     832                                        &media_port->info.fmt, 
     833                                        call_med->strm.v.rdr_dev, 
     834                                        call_med->strm.v.cap_dev, 
     835                                        //acc->cfg.vid_rend_dev, 
     836                                        //acc->cfg.vid_cap_dev, 
     837                                        PJSUA_HIDE_WINDOW, 
     838                                        &wid); 
     839                if (status != PJ_SUCCESS) { 
    746840                pj_log_pop_indent(); 
    747                 goto on_error; 
     841                    return status; 
     842                } 
    748843            } 
    749844 
     
    903998} 
    904999 
     1000/* 
     1001 * Does it have built-in preview support. 
     1002 */ 
     1003PJ_DEF(pj_bool_t) pjsua_vid_preview_has_native(pjmedia_vid_dev_index id) 
     1004{ 
     1005    pjmedia_vid_dev_info vdi; 
     1006 
     1007    return (pjmedia_vid_dev_get_info(id, &vdi)==PJ_SUCCESS) ? 
     1008            ((vdi.caps & PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW)!=0) : PJ_FALSE; 
     1009} 
    9051010 
    9061011/* 
     
    9391044    w = &pjsua_var.win[wid]; 
    9401045 
     1046    /* Start renderer, unless it's native preview */ 
     1047    if (!w->is_native) { 
     1048        status = pjmedia_vid_port_start(w->vp_rend); 
     1049        if (status != PJ_SUCCESS) { 
     1050            PJSUA_UNLOCK(); 
     1051            pj_log_pop_indent(); 
     1052            return status; 
     1053        } 
     1054    } 
     1055 
    9411056    /* Start capturer */ 
    942     status = pjmedia_vid_port_start(w->vp_rend); 
    943     if (status != PJ_SUCCESS) { 
    944         PJSUA_UNLOCK(); 
    945         pj_log_pop_indent(); 
    946         return status; 
    947     } 
    948  
    949     /* Start renderer */ 
    9501057    status = pjmedia_vid_port_start(w->vp_cap); 
    9511058    if (status != PJ_SUCCESS) { 
     
    10291136    PJ_ASSERT_RETURN(wid >= 0 && wid < PJSUA_MAX_VID_WINS && wi, PJ_EINVAL); 
    10301137 
     1138    pj_bzero(wi, sizeof(*wi)); 
     1139 
    10311140    PJSUA_LOCK(); 
    10321141    w = &pjsua_var.win[wid]; 
     1142 
     1143    wi->is_native = w->is_native; 
     1144 
     1145    if (w->is_native) { 
     1146        pjmedia_vid_dev_stream *cap_strm; 
     1147        pjmedia_vid_dev_cap cap = PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW; 
     1148 
     1149        cap_strm = pjmedia_vid_port_get_stream(w->vp_cap); 
     1150        if (!cap_strm) { 
     1151            status = PJ_EINVAL; 
     1152        } else { 
     1153            status = pjmedia_vid_dev_stream_get_cap(cap_strm, cap, &wi->hwnd); 
     1154        } 
     1155 
     1156        PJSUA_UNLOCK(); 
     1157        return status; 
     1158    } 
     1159 
    10331160    if (w->vp_rend == NULL) { 
    10341161        PJSUA_UNLOCK(); 
     
    10751202    w = &pjsua_var.win[wid]; 
    10761203    if (w->vp_rend == NULL) { 
     1204        /* Native window */ 
    10771205        PJSUA_UNLOCK(); 
    10781206        return PJ_EINVAL; 
     
    11091237    w = &pjsua_var.win[wid]; 
    11101238    if (w->vp_rend == NULL) { 
     1239        /* Native window */ 
    11111240        PJSUA_UNLOCK(); 
    11121241        return PJ_EINVAL; 
     
    11421271    w = &pjsua_var.win[wid]; 
    11431272    if (w->vp_rend == NULL) { 
     1273        /* Native window */ 
    11441274        PJSUA_UNLOCK(); 
    11451275        return PJ_EINVAL; 
     
    12471377    pjsua_acc_config *acc_cfg = &pjsua_var.acc[call->acc_id].cfg; 
    12481378    pjsua_call_media *call_med; 
     1379    const pjmedia_sdp_session *current_sdp; 
    12491380    pjmedia_sdp_session *sdp; 
    12501381    pjmedia_sdp_media *sdp_m; 
     
    12611392        return PJ_ETOOMANY; 
    12621393 
    1263     /* Get active local SDP */ 
    1264     status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &sdp); 
     1394    /* Get active local SDP and clone it */ 
     1395    status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &current_sdp); 
    12651396    if (status != PJ_SUCCESS) 
    12661397        return status; 
     1398 
     1399    sdp = pjmedia_sdp_session_clone(call->inv->pool_prov, current_sdp); 
    12671400 
    12681401    /* Initialize call media */ 
     
    13461479{ 
    13471480    pjsua_call_media *call_med; 
     1481    const pjmedia_sdp_session *current_sdp; 
    13481482    pjmedia_sdp_session *sdp; 
    13491483    pj_status_t status; 
     
    13741508    } 
    13751509 
    1376     /* Get active local SDP */ 
    1377     status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &sdp); 
     1510    /* Get active local SDP and clone it */ 
     1511    status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &current_sdp); 
    13781512    if (status != PJ_SUCCESS) 
    13791513        return status; 
     1514 
     1515    sdp = pjmedia_sdp_session_clone(call->inv->pool_prov, current_sdp); 
    13801516 
    13811517    pj_assert(med_idx < (int)sdp->media_count); 
     
    15381674    /* = Attach stream port to the new capture device = */ 
    15391675 
    1540     /* Create preview video window */ 
    1541     status = create_vid_win(PJSUA_WND_TYPE_PREVIEW, 
    1542                             &media_port->info.fmt, 
    1543                             call_med->strm.v.rdr_dev, 
    1544                             cap_dev, 
    1545                             PJ_FALSE, 
    1546                             &new_wid); 
    1547     if (status != PJ_SUCCESS) 
    1548         goto on_error; 
     1676    new_wid = pjsua_vid_preview_get_win(cap_dev); 
     1677    if (new_wid == PJSUA_INVALID_ID) { 
     1678        /* Create preview video window */ 
     1679        status = create_vid_win(PJSUA_WND_TYPE_PREVIEW, 
     1680                                &media_port->info.fmt, 
     1681                                call_med->strm.v.rdr_dev, 
     1682                                cap_dev, 
     1683                                PJSUA_HIDE_WINDOW, 
     1684                                &new_wid); 
     1685        if (status != PJ_SUCCESS) 
     1686            goto on_error; 
     1687    } 
    15491688 
    15501689    inc_vid_win(new_wid); 
     
    15611700        return status; 
    15621701 
     1702    if (w->vp_rend) { 
    15631703#if ENABLE_EVENT 
    1564     pjmedia_event_subscribe( 
    1565             pjmedia_vid_port_get_event_publisher(w->vp_rend), 
    1566             &call_med->esub_cap); 
     1704        pjmedia_event_subscribe( 
     1705                pjmedia_vid_port_get_event_publisher(w->vp_rend), 
     1706                &call_med->esub_cap); 
    15671707#endif 
    15681708 
    1569     /* Start renderer */ 
    1570     status = pjmedia_vid_port_start(new_w->vp_rend); 
    1571     if (status != PJ_SUCCESS) 
    1572         goto on_error; 
     1709        /* Start renderer */ 
     1710        status = pjmedia_vid_port_start(new_w->vp_rend); 
     1711        if (status != PJ_SUCCESS) 
     1712            goto on_error; 
     1713    } 
    15731714 
    15741715    /* Start capturer */ 
Note: See TracChangeset for help on using the changeset viewer.