Index: pjproject/trunk/pjmedia/include/pjmedia-videodev/videodev.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia-videodev/videodev.h	(revision 3754)
+++ pjproject/trunk/pjmedia/include/pjmedia-videodev/videodev.h	(revision 3756)
@@ -150,6 +150,12 @@
 
     /**
-     * The application can provide a window for the renderer to
-     * display the video.
+     * Support for returning the native window handle of the video window.
+     * For renderer, this means the window handle of the renderer window,
+     * while for capture, this means the window handle of the native preview,
+     * only if the device supports  PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW
+     * capability.
+     *
+     * The value of this capability is pointer to pjmedia_vid_dev_hwnd
+     * structure.
      */
     PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW = 4,
@@ -176,5 +182,18 @@
 
     /**
-     * End of capability
+     * Support for native preview capability in capture devices. Value is
+     * pj_bool_t. With native preview, capture device can be instructed to
+     * show or hide a preview window showing video directly from the camera
+     * by setting this capability to PJ_TRUE or PJ_FALSE. Once the preview
+     * is started, application may use PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW
+     * capability to query the vidow window.
+     *
+     * The value of this capability is a pj_bool_t containing boolean
+     * PJ_TRUE or PJ_FALSE.
+     */
+    PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW = 64,
+
+    /**
+     * End of standard capability
      */
     PJMEDIA_VID_DEV_CAP_MAX = 16384
@@ -338,4 +357,11 @@
     pj_bool_t window_hide;
 
+    /**
+     * Enable built-in preview. This setting is optional and is only used
+     * if PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW capability is supported and
+     * set in the flags.
+     */
+    pj_bool_t native_preview;
+
 } pjmedia_vid_dev_param;
 
Index: pjproject/trunk/pjmedia/src/pjmedia-videodev/videodev.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia-videodev/videodev.c	(revision 3754)
+++ pjproject/trunk/pjmedia/src/pjmedia-videodev/videodev.c	(revision 3756)
@@ -41,8 +41,9 @@
     DEFINE_CAP("format",        "Video format"),
     DEFINE_CAP("scale",         "Input dimension"),
-    DEFINE_CAP("window",        "Renderer window"),
+    DEFINE_CAP("window",        "Window handle"),
     DEFINE_CAP("resize",        "Renderer resize"),
     DEFINE_CAP("position",      "Renderer position"),
     DEFINE_CAP("hide",          "Renderer hide"),
+    DEFINE_CAP("preview",       "Input preview"),
 };
 
@@ -176,4 +177,7 @@
 	FIELD_INFO(window_hide);
 	break;
+    case PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW:
+	FIELD_INFO(native_preview);
+	break;
     default:
 	return PJMEDIA_EVID_INVCAP;
Index: pjproject/trunk/pjmedia/src/pjmedia/vid_tee.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/vid_tee.c	(revision 3754)
+++ pjproject/trunk/pjmedia/src/pjmedia/vid_tee.c	(revision 3756)
@@ -31,4 +31,5 @@
 #define TEE_PORT_SIGN	PJMEDIA_SIG_PORT_VID_TEE
 
+#define THIS_FILE	"vid_tee.c"
 
 typedef struct vid_tee_dst_port
@@ -317,6 +318,7 @@
                                                frame, &frame_);
             if (status != PJ_SUCCESS) {
-                PJ_LOG(3, ("", "Failed to convert frame for destination"
-                               "port %d (%.*s)", i,
+                PJ_LOG(3, (THIS_FILE,
+			       "Failed to convert frame for destination"
+                               " port %d (%.*s)", i,
                                tee->dst_ports[i].dst->info.name.slen,
                                tee->dst_ports[i].dst->info.name.ptr));
Index: pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 3754)
+++ pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 3756)
@@ -4692,4 +4692,16 @@
      */
     int			snd_auto_close_time;
+
+    /**
+     * Specify whether built-in/native preview should be used if available.
+     * In some systems, video input devices have built-in capability to show
+     * preview window of the device. Using this built-in preview is preferable
+     * as it consumes less CPU power. If built-in preview is not available,
+     * the library will perform software rendering of the input. If this
+     * field is set to PJ_FALSE, software preview will always be used.
+     *
+     * Default: PJ_TRUE
+     */
+    pj_bool_t vid_preview_enable_native;
 };
 
@@ -5437,5 +5449,6 @@
     /**
      * Device ID for the video renderer to be used for rendering the
-     * capture stream for preview.
+     * capture stream for preview. This parameter is ignored if native
+     * preview is being used.
      *
      * Default: PJMEDIA_VID_DEFAULT_RENDER_DEV
@@ -5459,4 +5472,16 @@
  */
 PJ_DECL(void) pjsua_vid_preview_param_default(pjsua_vid_preview_param *p);
+
+/**
+ * Determine if the specified video input device has built-in native
+ * preview capability. This is a convenience function that is equal to
+ * querying device's capability for PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW
+ * capability.
+ *
+ * @param id		The capture device ID.
+ *
+ * @return		PJ_TRUE if it has.
+ */
+PJ_DECL(pj_bool_t) pjsua_vid_preview_has_native(pjmedia_vid_dev_index id);
 
 /**
@@ -5504,12 +5529,20 @@
 {
     /**
+     * Flag to indicate whether this window is a native window,
+     * such as created by built-in preview device. If this field is
+     * PJ_TRUE, only the native window handle field of this
+     * structure is valid.
+     */
+    pj_bool_t is_native;
+
+    /**
+     * Native window handle.
+     */
+    pjmedia_vid_dev_hwnd hwnd;
+
+    /**
      * Renderer device ID.
      */
     pjmedia_vid_dev_index rdr_dev;
-
-    /**
-     * Native window handle.
-     */
-    pjmedia_vid_dev_hwnd hwnd;
 
     /**
@@ -5557,5 +5590,7 @@
 
 /**
- * Show or hide window.
+ * Show or hide window. This operation is not valid for native windows
+ * (pjsua_vid_win_info.is_native=PJ_TRUE), on which native windowing API
+ * must be used instead.
  *
  * @param wid		The video window ID.
@@ -5569,5 +5604,7 @@
 
 /**
- * Set video window position.
+ * Set video window position. This operation is not valid for native windows
+ * (pjsua_vid_win_info.is_native=PJ_TRUE), on which native windowing API
+ * must be used instead.
  *
  * @param wid		The video window ID.
@@ -5580,5 +5617,7 @@
 
 /**
- * Resize window.
+ * Resize window. This operation is not valid for native windows
+ * (pjsua_vid_win_info.is_native=PJ_TRUE), on which native windowing API
+ * must be used instead.
  *
  * @param wid		The video window ID.
Index: pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 3754)
+++ pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 3756)
@@ -308,4 +308,5 @@
 } pjsua_stun_resolve;
 
+/* See also pjsua_vid_win_type_name() */
 typedef enum pjsua_vid_win_type
 {
@@ -323,5 +324,6 @@
     pjmedia_vid_port		*vp_rend;	/**< Renderer vidport	*/
     pjmedia_port		*tee;		/**< Video tee		*/
-    pjmedia_vid_dev_index	 preview_cap_id;/* Capture dev id	*/
+    pjmedia_vid_dev_index	 preview_cap_id;/**< Capture dev id	*/
+    pj_bool_t			 is_native; 	/**< Preview is by dev  */
 } pjsua_vid_win;
 
@@ -676,19 +678,9 @@
 pj_status_t pjsua_vid_subsys_destroy(void);
 
-PJ_INLINE(void) pjsua_vid_win_reset(pjsua_vid_win_id wid)
-{
 #if PJSUA_HAS_VIDEO
-    pjsua_vid_win *w = &pjsua_var.win[wid];
-    pj_pool_t *pool = w->pool;
-
-    pj_bzero(w, sizeof(*w));
-    if (pool) pj_pool_reset(pool);
-    w->ref_cnt = 0;
-    w->pool = pool;
-    w->preview_cap_id = PJMEDIA_VID_INVALID_DEV;
+PJ_DECL(void) pjsua_vid_win_reset(pjsua_vid_win_id wid);
 #else
-    PJ_UNUSED_ARG(wid);
+#  define pjsua_vid_win_reset(wid)
 #endif
-}
 
 
Index: pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 3754)
+++ pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 3756)
@@ -229,4 +229,5 @@
 
     cfg->turn_conn_type = PJ_TURN_TP_UDP;
+    cfg->vid_preview_enable_native = PJ_TRUE;
 }
 
Index: pjproject/trunk/pjsip/src/pjsua-lib/pjsua_vid.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua-lib/pjsua_vid.c	(revision 3754)
+++ pjproject/trunk/pjsip/src/pjsua-lib/pjsua_vid.c	(revision 3756)
@@ -24,6 +24,10 @@
 #if PJSUA_HAS_VIDEO
 
-#define ENABLE_EVENT	    0
-#define VID_TEE_MAX_PORT    (PJSUA_MAX_CALLS + 1)
+#define ENABLE_EVENT	    	0
+#define VID_TEE_MAX_PORT    	(PJSUA_MAX_CALLS + 1)
+
+#define PJSUA_SHOW_WINDOW	1
+#define PJSUA_HIDE_WINDOW	0
+
 
 static void free_vid_win(pjsua_vid_win_id wid);
@@ -125,4 +129,15 @@
 }
 
+PJ_DEF(const char*) pjsua_vid_win_type_name(pjsua_vid_win_type wt)
+{
+    const char *win_type_names[] = {
+         "none",
+         "preview",
+         "stream"
+    };
+
+    return (wt < PJ_ARRAY_SIZE(win_type_names)) ? win_type_names[wt] : "??";
+}
+
 PJ_DEF(void)
 pjsua_call_vid_strm_op_param_default(pjsua_call_vid_strm_op_param *param)
@@ -338,4 +353,15 @@
 }
 
+PJ_DEF(void) pjsua_vid_win_reset(pjsua_vid_win_id wid)
+{
+    pjsua_vid_win *w = &pjsua_var.win[wid];
+    pj_pool_t *pool = w->pool;
+
+    pj_bzero(w, sizeof(*w));
+    if (pool) pj_pool_reset(pool);
+    w->ref_cnt = 0;
+    w->pool = pool;
+    w->preview_cap_id = PJMEDIA_VID_INVALID_DEV;
+}
 
 /* Allocate and initialize pjsua video window:
@@ -351,4 +377,5 @@
 				  pjsua_vid_win_id *id)
 {
+    pj_bool_t enable_native_preview;
     pjsua_vid_win_id wid = PJSUA_INVALID_ID;
     pjsua_vid_win *w = NULL;
@@ -358,6 +385,9 @@
     unsigned i;
 
-    PJ_LOG(4,(THIS_FILE, "Creating window, type=%d, cap_dev=%d, rend_dev=%d",
-	      type, cap_id, rend_id));
+    enable_native_preview = pjsua_var.media_cfg.vid_preview_enable_native;
+
+    PJ_LOG(4,(THIS_FILE,
+	      "Creating video window: type=%s, cap_id=%d, rend_id=%d",
+	      pjsua_vid_win_type_name(type), cap_id, rend_id));
     pj_log_push_indent();
 
@@ -368,11 +398,23 @@
 	    /* Yes, it exists */
 	    /* Show/hide window */
-	    pjmedia_vid_dev_stream *rdr;
+	    pjmedia_vid_dev_stream *strm;
 	    pj_bool_t hide = !show;
 
-	    rdr = pjmedia_vid_port_get_stream(pjsua_var.win[wid].vp_rend);
-	    pj_assert(rdr);
+	    w = &pjsua_var.win[wid];
+
+	    PJ_LOG(4,(THIS_FILE,
+		      "Window already exists for cap_dev=%d, returning wid=%d",
+		      cap_id, wid));
+
+
+	    if (w->is_native) {
+		strm = pjmedia_vid_port_get_stream(w->vp_cap);
+	    } else {
+		strm = pjmedia_vid_port_get_stream(w->vp_rend);
+	    }
+
+	    pj_assert(strm);
 	    status = pjmedia_vid_dev_stream_set_cap(
-				    rdr, PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE,
+				    strm, PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE,
 				    &hide);
 
@@ -403,8 +445,29 @@
 
     if (w->type == PJSUA_WND_TYPE_PREVIEW) {
+	pjmedia_vid_dev_info vdi;
+
+	/*
+	 * Determine if the device supports native preview.
+	 */
+	status = pjmedia_vid_dev_get_info(cap_id, &vdi);
+	if (status != PJ_SUCCESS)
+	    goto on_error;
+
+	if (enable_native_preview &&
+	     (vdi.caps & PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW))
+	{
+	    /* Device supports native preview! */
+	    w->is_native = PJ_TRUE;
+	}
+
 	status = pjmedia_vid_dev_default_param(w->pool, cap_id,
 					       &vp_param.vidparam);
 	if (status != PJ_SUCCESS)
 	    goto on_error;
+
+	if (w->is_native) {
+	    vp_param.vidparam.flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE;
+	    vp_param.vidparam.window_hide = !show;
+	}
 
 	/* Normalize capture ID, in case it was set to
@@ -435,36 +498,65 @@
 	if (status != PJ_SUCCESS)
 	    goto on_error;
-    }
-
-    /* Create renderer video port */
-    status = pjmedia_vid_dev_default_param(w->pool, rend_id,
-					   &vp_param.vidparam);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-    vp_param.active = (w->type == PJSUA_WND_TYPE_STREAM);
-    vp_param.vidparam.dir = PJMEDIA_DIR_RENDER;
-    vp_param.vidparam.fmt = *fmt;
-    vp_param.vidparam.disp_size = fmt->det.vid.size;
-    vp_param.vidparam.flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE;
-    vp_param.vidparam.window_hide = !show;
-
-    status = pjmedia_vid_port_create(w->pool, &vp_param, &w->vp_rend);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-    /* For preview window, connect capturer & renderer (via tee) */
-    if (w->type == PJSUA_WND_TYPE_PREVIEW) {
-	pjmedia_port *rend_port;
-
-	status = pjmedia_vid_port_connect(w->vp_cap, w->tee, PJ_FALSE);
+
+	/* If device supports native preview, enable it */
+	if (w->is_native) {
+	    pjmedia_vid_dev_stream *cap_dev;
+	    pj_bool_t enabled = PJ_TRUE;
+
+	    cap_dev = pjmedia_vid_port_get_stream(w->vp_cap);
+	    status = pjmedia_vid_dev_stream_set_cap(
+			    cap_dev, PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW,
+			    &enabled);
+	    if (status != PJ_SUCCESS) {
+		PJ_PERROR(1,(THIS_FILE, status,
+			     "Error activating native preview, falling back "
+			     "to software preview.."));
+		w->is_native = PJ_FALSE;
+	    }
+	}
+    }
+
+    /* Create renderer video port, only if it's not a native preview */
+    if (!w->is_native) {
+	status = pjmedia_vid_dev_default_param(w->pool, rend_id,
+					       &vp_param.vidparam);
 	if (status != PJ_SUCCESS)
 	    goto on_error;
 
-	rend_port = pjmedia_vid_port_get_passive_port(w->vp_rend);
-	status = pjmedia_vid_tee_add_dst_port2(w->tee, 0, rend_port);
+	vp_param.active = (w->type == PJSUA_WND_TYPE_STREAM);
+	vp_param.vidparam.dir = PJMEDIA_DIR_RENDER;
+	vp_param.vidparam.fmt = *fmt;
+	vp_param.vidparam.disp_size = fmt->det.vid.size;
+	vp_param.vidparam.flags |= PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE;
+	vp_param.vidparam.window_hide = !show;
+
+	status = pjmedia_vid_port_create(w->pool, &vp_param, &w->vp_rend);
 	if (status != PJ_SUCCESS)
 	    goto on_error;
-    }
+
+	/* For preview window, connect capturer & renderer (via tee) */
+	if (w->type == PJSUA_WND_TYPE_PREVIEW) {
+	    pjmedia_port *rend_port;
+
+	    status = pjmedia_vid_port_connect(w->vp_cap, w->tee, PJ_FALSE);
+	    if (status != PJ_SUCCESS)
+		goto on_error;
+
+	    rend_port = pjmedia_vid_port_get_passive_port(w->vp_rend);
+	    status = pjmedia_vid_tee_add_dst_port2(w->tee, 0, rend_port);
+	    if (status != PJ_SUCCESS)
+		goto on_error;
+	}
+
+	PJ_LOG(4,(THIS_FILE,
+		  "%s window id %d created for cap_dev=%d rend_dev=%d",
+		  pjsua_vid_win_type_name(type), wid, cap_id, rend_id));
+    } else {
+	PJ_LOG(4,(THIS_FILE,
+		  "Preview window id %d created for cap_dev %d, "
+		  "using built-in preview!",
+		  wid, cap_id));
+    }
+
 
     /* Done */
@@ -734,16 +826,19 @@
 	    }
 
-	    /* Create preview video window */
-	    status = create_vid_win(PJSUA_WND_TYPE_PREVIEW,
-				    &media_port->info.fmt,
-				    call_med->strm.v.rdr_dev,
-				    call_med->strm.v.cap_dev,
-				    //acc->cfg.vid_rend_dev,
-				    //acc->cfg.vid_cap_dev,
-				    PJ_FALSE,
-				    &wid);
-	    if (status != PJ_SUCCESS) {
+	    wid = pjsua_vid_preview_get_win(call_med->strm.v.cap_dev);
+	    if (wid == PJSUA_INVALID_ID) {
+		/* Create preview video window */
+		status = create_vid_win(PJSUA_WND_TYPE_PREVIEW,
+					&media_port->info.fmt,
+					call_med->strm.v.rdr_dev,
+					call_med->strm.v.cap_dev,
+					//acc->cfg.vid_rend_dev,
+					//acc->cfg.vid_cap_dev,
+					PJSUA_HIDE_WINDOW,
+					&wid);
+		if (status != PJ_SUCCESS) {
 		pj_log_pop_indent();
-		goto on_error;
+		    return status;
+		}
 	    }
 
@@ -903,4 +998,14 @@
 }
 
+/*
+ * Does it have built-in preview support.
+ */
+PJ_DEF(pj_bool_t) pjsua_vid_preview_has_native(pjmedia_vid_dev_index id)
+{
+    pjmedia_vid_dev_info vdi;
+
+    return (pjmedia_vid_dev_get_info(id, &vdi)==PJ_SUCCESS) ?
+	    ((vdi.caps & PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW)!=0) : PJ_FALSE;
+}
 
 /*
@@ -939,13 +1044,15 @@
     w = &pjsua_var.win[wid];
 
+    /* Start renderer, unless it's native preview */
+    if (!w->is_native) {
+	status = pjmedia_vid_port_start(w->vp_rend);
+	if (status != PJ_SUCCESS) {
+	    PJSUA_UNLOCK();
+	    pj_log_pop_indent();
+	    return status;
+	}
+    }
+
     /* Start capturer */
-    status = pjmedia_vid_port_start(w->vp_rend);
-    if (status != PJ_SUCCESS) {
-	PJSUA_UNLOCK();
-	pj_log_pop_indent();
-	return status;
-    }
-
-    /* Start renderer */
     status = pjmedia_vid_port_start(w->vp_cap);
     if (status != PJ_SUCCESS) {
@@ -1029,6 +1136,26 @@
     PJ_ASSERT_RETURN(wid >= 0 && wid < PJSUA_MAX_VID_WINS && wi, PJ_EINVAL);
 
+    pj_bzero(wi, sizeof(*wi));
+
     PJSUA_LOCK();
     w = &pjsua_var.win[wid];
+
+    wi->is_native = w->is_native;
+
+    if (w->is_native) {
+	pjmedia_vid_dev_stream *cap_strm;
+	pjmedia_vid_dev_cap cap = PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW;
+
+	cap_strm = pjmedia_vid_port_get_stream(w->vp_cap);
+	if (!cap_strm) {
+	    status = PJ_EINVAL;
+	} else {
+	    status = pjmedia_vid_dev_stream_get_cap(cap_strm, cap, &wi->hwnd);
+	}
+
+	PJSUA_UNLOCK();
+	return status;
+    }
+
     if (w->vp_rend == NULL) {
 	PJSUA_UNLOCK();
@@ -1075,4 +1202,5 @@
     w = &pjsua_var.win[wid];
     if (w->vp_rend == NULL) {
+	/* Native window */
 	PJSUA_UNLOCK();
 	return PJ_EINVAL;
@@ -1109,4 +1237,5 @@
     w = &pjsua_var.win[wid];
     if (w->vp_rend == NULL) {
+	/* Native window */
 	PJSUA_UNLOCK();
 	return PJ_EINVAL;
@@ -1142,4 +1271,5 @@
     w = &pjsua_var.win[wid];
     if (w->vp_rend == NULL) {
+	/* Native window */
 	PJSUA_UNLOCK();
 	return PJ_EINVAL;
@@ -1247,4 +1377,5 @@
     pjsua_acc_config *acc_cfg = &pjsua_var.acc[call->acc_id].cfg;
     pjsua_call_media *call_med;
+    const pjmedia_sdp_session *current_sdp;
     pjmedia_sdp_session *sdp;
     pjmedia_sdp_media *sdp_m;
@@ -1261,8 +1392,10 @@
 	return PJ_ETOOMANY;
 
-    /* Get active local SDP */
-    status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &sdp);
+    /* Get active local SDP and clone it */
+    status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &current_sdp);
     if (status != PJ_SUCCESS)
 	return status;
+
+    sdp = pjmedia_sdp_session_clone(call->inv->pool_prov, current_sdp);
 
     /* Initialize call media */
@@ -1346,4 +1479,5 @@
 {
     pjsua_call_media *call_med;
+    const pjmedia_sdp_session *current_sdp;
     pjmedia_sdp_session *sdp;
     pj_status_t status;
@@ -1374,8 +1508,10 @@
     }
 
-    /* Get active local SDP */
-    status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &sdp);
+    /* Get active local SDP and clone it */
+    status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &current_sdp);
     if (status != PJ_SUCCESS)
 	return status;
+
+    sdp = pjmedia_sdp_session_clone(call->inv->pool_prov, current_sdp);
 
     pj_assert(med_idx < (int)sdp->media_count);
@@ -1538,13 +1674,16 @@
     /* = Attach stream port to the new capture device = */
 
-    /* Create preview video window */
-    status = create_vid_win(PJSUA_WND_TYPE_PREVIEW,
-			    &media_port->info.fmt,
-			    call_med->strm.v.rdr_dev,
-			    cap_dev,
-			    PJ_FALSE,
-			    &new_wid);
-    if (status != PJ_SUCCESS)
-	goto on_error;
+    new_wid = pjsua_vid_preview_get_win(cap_dev);
+    if (new_wid == PJSUA_INVALID_ID) {
+	/* Create preview video window */
+	status = create_vid_win(PJSUA_WND_TYPE_PREVIEW,
+				&media_port->info.fmt,
+				call_med->strm.v.rdr_dev,
+				cap_dev,
+				PJSUA_HIDE_WINDOW,
+				&new_wid);
+	if (status != PJ_SUCCESS)
+	    goto on_error;
+    }
 
     inc_vid_win(new_wid);
@@ -1561,14 +1700,16 @@
 	return status;
 
+    if (w->vp_rend) {
 #if ENABLE_EVENT
-    pjmedia_event_subscribe(
-	    pjmedia_vid_port_get_event_publisher(w->vp_rend),
-	    &call_med->esub_cap);
+	pjmedia_event_subscribe(
+		pjmedia_vid_port_get_event_publisher(w->vp_rend),
+		&call_med->esub_cap);
 #endif
 
-    /* Start renderer */
-    status = pjmedia_vid_port_start(new_w->vp_rend);
-    if (status != PJ_SUCCESS)
-	goto on_error;
+	/* Start renderer */
+	status = pjmedia_vid_port_start(new_w->vp_rend);
+	if (status != PJ_SUCCESS)
+	    goto on_error;
+    }
 
     /* Start capturer */
