Index: pjproject/branches/projects/2.0-dev/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- pjproject/branches/projects/2.0-dev/pjsip/include/pjsua-lib/pjsua.h	(revision 3470)
+++ pjproject/branches/projects/2.0-dev/pjsip/include/pjsua-lib/pjsua.h	(revision 3471)
@@ -4935,4 +4935,96 @@
 
 /*****************************************************************************
+ * Video devices.
+ */
+
+/**
+ * Enum all video devices installed in the system.
+ *
+ * @param info		Array of info to be initialized.
+ * @param count		On input, specifies max elements in the array.
+ *			On return, it contains actual number of elements
+ *			that have been initialized.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsua_vid_enum_devs(pjmedia_vid_dev_info info[],
+					 unsigned *count);
+
+
+/**
+ * Get currently active video devices. If video devices has not been created
+ * (for example when pjsua_start() is not called), it is possible that
+ * the function returns PJ_SUCCESS with -1 as device IDs.
+ *
+ * @param capture_dev   On return it will be filled with device ID of the 
+ *			capture device.
+ * @param render_dev	On return it will be filled with device ID of the 
+ *			device ID of the render device.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsua_vid_get_dev(int *capture_dev, int *render_dev);
+
+
+/**
+ * Select video device for the next video sessions.
+ *
+ * @param capture_dev   Device ID of the capture device.
+ * @param render_dev	Device ID of the render device.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsua_vid_set_dev(int capture_dev, int render_dev);
+
+
+/**
+ * Configure video device setting to the video device being used. If video 
+ * device is currently active, the function will forward the setting to the
+ * video device instance to be applied immediately, if it supports it. 
+ *
+ * The setting will be saved for future opening of the video device, if the 
+ * "keep" argument is set to non-zero. If the video device is currently
+ * inactive, and the "keep" argument is false, this function will return
+ * error.
+ * 
+ * Note that in case the setting is kept for future use, it will be applied
+ * to any devices, even when application has changed the video device to be
+ * used.
+ *
+ * See also #pjmedia_vid_dev_stream_set_cap() for more information about
+ * setting an video device capability.
+ *
+ * @param cap		The video device setting to change.
+ * @param pval		Pointer to value. Please see #pjmedia_vid_dev_cap
+ *			documentation about the type of value to be 
+ *			supplied for each setting.
+ * @param keep		Specify whether the setting is to be kept for future
+ *			use.
+ *
+ * @return		PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsua_vid_set_setting(pjmedia_vid_dev_cap cap,
+					   const void *pval,
+					   pj_bool_t keep);
+
+/**
+ * Retrieve a video device setting. If video device is currently active,
+ * the function will forward the request to the video device. If video device
+ * is currently inactive, and if application had previously set the setting
+ * and mark the setting as kept, then that setting will be returned.
+ * Otherwise, this function will return error.
+ *
+ * @param cap		The video device setting to retrieve.
+ * @param pval		Pointer to receive the value. 
+ *			Please see #pjmedia_vid_dev_cap documentation about
+ *			the type of value to be supplied for each setting.
+ *
+ * @return		PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsua_vid_get_setting(pjmedia_vid_dev_cap cap,
+					   void *pval);
+
+
+/*****************************************************************************
  * Codecs.
  */
@@ -4990,4 +5082,64 @@
 PJ_DECL(pj_status_t) pjsua_codec_set_param( const pj_str_t *codec_id,
 					    const pjmedia_codec_param *param);
+
+/*****************************************************************************
+ * Video codecs.
+ */
+
+/**
+ * Enum all supported video codecs in the system.
+ *
+ * @param id		Array of ID to be initialized.
+ * @param count		On input, specifies max elements in the array.
+ *			On return, it contains actual number of elements
+ *			that have been initialized.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsua_vid_enum_codecs( pjsua_codec_info id[],
+					    unsigned *count );
+
+
+/**
+ * Change video codec priority.
+ *
+ * @param codec_id	Codec ID, which is a string that uniquely identify
+ *			the codec (such as "H263/90000"). Please see pjsua
+ *			manual or pjmedia codec reference for details.
+ * @param priority	Codec priority, 0-255, where zero means to disable
+ *			the codec.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsua_vid_codec_set_priority( const pj_str_t *codec_id,
+						   pj_uint8_t priority );
+
+
+/**
+ * Get video codec parameters.
+ *
+ * @param codec_id	Codec ID.
+ * @param param		Structure to receive video codec parameters.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsua_vid_codec_get_param(
+					const pj_str_t *codec_id,
+					pjmedia_vid_codec_param *param);
+
+
+/**
+ * Set video codec parameters.
+ *
+ * @param codec_id	Codec ID.
+ * @param param		Codec parameter to set. Set to NULL to reset
+ *			codec parameter to library default settings.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsua_vid_codec_set_param( 
+					const pj_str_t *codec_id,
+					const pjmedia_vid_codec_param *param);
+
 
 #if DISABLED_FOR_TICKET_1185
Index: pjproject/branches/projects/2.0-dev/pjsip/include/pjsua-lib/pjsua_internal.h
===================================================================
--- pjproject/branches/projects/2.0-dev/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 3470)
+++ pjproject/branches/projects/2.0-dev/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 3471)
@@ -384,4 +384,8 @@
 
 
+    /* Video device */
+    pjmedia_vid_dev_index vcap_dev;  /**< Capture device ID.		*/
+    pjmedia_vid_dev_index vrdr_dev;  /**< Playback device ID.		*/
+
     /* File players: */
     unsigned		 player_cnt;/**< Number of file players.	*/
Index: pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_core.c	(revision 3470)
+++ pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_core.c	(revision 3471)
@@ -635,4 +635,8 @@
     pjsua_var.play_dev = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV;
 
+    /* Set default video device ID */
+    pjsua_var.vcap_dev = PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
+    pjsua_var.vrdr_dev = PJMEDIA_VID_DEFAULT_RENDER_DEV;
+
     /* Init caching pool. */
     pj_caching_pool_init(&pjsua_var.cp, NULL, 0);
Index: pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_media.c	(revision 3470)
+++ pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_media.c	(revision 3471)
@@ -59,4 +59,9 @@
 }
 
+
+PJ_DECL(pj_status_t)
+pjmedia_libswscale_converter_init(pjmedia_converter_mgr *mgr,
+				  pj_pool_t *pool);
+
 /**
  * Init media subsystems.
@@ -310,4 +315,13 @@
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Error initializing ffmpeg library",
+		     status);
+	return status;
+    }
+#endif
+
+#if PJMEDIA_HAS_VIDEO && PJMEDIA_HAS_LIBSWSCALE && PJMEDIA_HAS_LIBAVUTIL
+    status = pjmedia_libswscale_converter_init(NULL, pjsua_var.pool);
+    if (status != PJ_SUCCESS) {
+	pjsua_perror(THIS_FILE, "Error initializing libswscale converter",
 		     status);
 	return status;
@@ -1837,5 +1851,8 @@
 		call_med->strm.a.stream = NULL;
 	    }
-	} else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
+	}
+
+#if PJMEDIA_HAS_VIDEO
+	else if (call_med->type == PJMEDIA_TYPE_VIDEO) {
 	    pjmedia_vid_stream *strm = call_med->strm.v.stream;
 
@@ -1873,4 +1890,5 @@
 	    }
 	}
+#endif
 
 	PJ_LOG(4,(THIS_FILE, "Media session call%02d:%d is destroyed",
@@ -2134,4 +2152,7 @@
 }
 
+
+#if PJMEDIA_HAS_VIDEO
+
 static pj_status_t video_channel_update(pjsua_call_media *call_med,
                                         pj_pool_t *tmp_pool,
@@ -2212,4 +2233,32 @@
 #endif
 
+	/* Try to get shared format ID between the capture device and 
+	 * the encoder to avoid format conversion in the capture device.
+	 */
+	if (si->dir & PJMEDIA_DIR_ENCODING) {
+	    pjmedia_vid_dev_info dev_info;
+	    pjmedia_vid_codec_info *codec_info = &si->codec_info;
+	    unsigned i, j;
+
+	    status = pjmedia_vid_dev_get_info(pjsua_var.vcap_dev, &dev_info);
+	    if (status != PJ_SUCCESS)
+		return status;
+
+	    /* Find matched format ID */
+	    for (i = 0; i < codec_info->dec_fmt_id_cnt; ++i) {
+		for (j = 0; j < dev_info.fmt_cnt; ++j) {
+		    if (codec_info->dec_fmt_id[i] == 
+			(pjmedia_format_id)dev_info.fmt[j].id)
+		    {
+			/* Apply the matched format ID to the codec */
+			si->codec_param->dec_fmt.id = codec_info->dec_fmt_id[i];
+			/* Force outer loop to break */
+			i = codec_info->dec_fmt_id_cnt;
+			break;
+		    }
+		}
+	    }
+	}
+
 	/* Create session based on session info. */
 	status = pjmedia_vid_stream_create(pjsua_var.med_endpt, NULL, si,
@@ -2235,5 +2284,5 @@
 
 	    status = pjmedia_vid_dev_default_param(
-				tmp_pool, PJMEDIA_VID_DEFAULT_RENDER_DEV,
+				tmp_pool, pjsua_var.vrdr_dev,
 				&vport_param.vidparam);
 	    if (status != PJ_SUCCESS)
@@ -2275,5 +2324,5 @@
 
 	    status = pjmedia_vid_dev_default_param(
-				tmp_pool, PJMEDIA_VID_DEFAULT_CAPTURE_DEV,
+				tmp_pool, pjsua_var.vcap_dev,
 				&vport_param.vidparam);
 	    if (status != PJ_SUCCESS)
@@ -2282,5 +2331,4 @@
 	    pjmedia_format_copy(&vport_param.vidparam.fmt,
 				&media_port->info.fmt);
-
 	    vport_param.vidparam.dir = PJMEDIA_DIR_CAPTURE;
 	    vport_param.active = PJ_TRUE;
@@ -2353,4 +2401,6 @@
 }
 
+#endif
+
 
 pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
@@ -2395,8 +2445,10 @@
 	    }
 	    break;
+#if PJMEDIA_HAS_VIDEO
 	case PJMEDIA_TYPE_VIDEO:
 	    status = video_channel_update(call_med, tmp_pool,
 	                                  local_sdp, remote_sdp);
 	    break;
+#endif
 	default:
 	    break;
@@ -3772,5 +3824,5 @@
 
     if (count != 1)
-	return PJ_ENOTFOUND;
+	return (count > 1? PJ_ETOOMANY : PJ_ENOTFOUND);
 
     status = pjmedia_codec_mgr_get_default_param( codec_mgr, info, param);
@@ -3809,2 +3861,212 @@
     return status;
 }
+
+
+#if PJMEDIA_HAS_VIDEO
+
+/*****************************************************************************
+ * Video codecs.
+ */
+
+/*
+ * Enum all supported video codecs in the system.
+ */
+PJ_DEF(pj_status_t) pjsua_vid_enum_codecs( pjsua_codec_info id[],
+					   unsigned *p_count )
+{
+    pjmedia_vid_codec_info info[32];
+    unsigned i, j, count, prio[32];
+    pj_status_t status;
+
+    count = PJ_ARRAY_SIZE(info);
+    status = pjmedia_vid_codec_mgr_enum_codecs(NULL, &count, info, prio);
+    if (status != PJ_SUCCESS) {
+	*p_count = 0;
+	return status;
+    }
+
+    for (i=0, j=0; i<count && j<*p_count; ++i) {
+	if (info[i].has_rtp_pack) {
+	    pjmedia_vid_codec_info_to_id(&info[i], id[j].buf_, sizeof(id[j].buf_));
+	    id[j].codec_id = pj_str(id[j].buf_);
+	    id[j].priority = (pj_uint8_t) prio[i];
+	    ++j;
+	}
+    }
+
+    *p_count = j;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Change video codec priority.
+ */
+PJ_DEF(pj_status_t) pjsua_vid_codec_set_priority( const pj_str_t *codec_id,
+						  pj_uint8_t priority )
+{
+    const pj_str_t all = { NULL, 0 };
+
+    if (codec_id->slen==1 && *codec_id->ptr=='*')
+	codec_id = &all;
+
+    return pjmedia_vid_codec_mgr_set_codec_priority(NULL, codec_id,
+						    priority);
+}
+
+
+/*
+ * Get video codec parameters.
+ */
+PJ_DEF(pj_status_t) pjsua_vid_codec_get_param(
+					const pj_str_t *codec_id,
+					pjmedia_vid_codec_param *param)
+{
+    const pj_str_t all = { NULL, 0 };
+    const pjmedia_vid_codec_info *info;
+    unsigned count = 1;
+    pj_status_t status;
+
+    if (codec_id->slen==1 && *codec_id->ptr=='*')
+	codec_id = &all;
+
+    status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, codec_id,
+						     &count, &info, NULL);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    if (count != 1)
+	return (count > 1? PJ_ETOOMANY : PJ_ENOTFOUND);
+
+    status = pjmedia_vid_codec_mgr_get_default_param(NULL, info, param);
+    return status;
+}
+
+
+/*
+ * Set video codec parameters.
+ */
+PJ_DEF(pj_status_t) pjsua_vid_codec_set_param( 
+					const pj_str_t *codec_id,
+					const pjmedia_vid_codec_param *param)
+{
+    const pjmedia_vid_codec_info *info[2];
+    unsigned count = 2;
+    pj_status_t status;
+
+    status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL, codec_id,
+						     &count, info, NULL);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Codec ID should be specific */
+    if (count > 1) {
+	pj_assert(!"Codec ID is not specific");
+	return PJ_ETOOMANY;
+    }
+
+    status = pjmedia_vid_codec_mgr_set_default_param(NULL, pjsua_var.pool,
+						     info[0], param);
+    return status;
+}
+
+
+/*****************************************************************************
+ * Video devices.
+ */
+
+/*
+ * Enum all video devices installed in the system.
+ */
+PJ_DEF(pj_status_t) pjsua_vid_enum_devs(pjmedia_vid_dev_info info[],
+					unsigned *count)
+{
+    unsigned i, dev_count;
+
+    dev_count = pjmedia_vid_dev_count();
+    
+    if (dev_count > *count) dev_count = *count;
+
+    for (i=0; i<dev_count; ++i) {
+	pj_status_t status;
+
+	status = pjmedia_vid_dev_get_info(i, &info[i]);
+	if (status != PJ_SUCCESS)
+	    return status;
+    }
+
+    *count = dev_count;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Get currently active video devices.
+ */
+PJ_DEF(pj_status_t) pjsua_vid_get_dev(int *capture_dev, int *render_dev)
+{
+    if (capture_dev)
+	*capture_dev = pjsua_var.vcap_dev;
+    if (render_dev)
+	*render_dev = pjsua_var.vrdr_dev;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Select video device for the next video sessions.
+ */
+PJ_DEF(pj_status_t) pjsua_vid_set_dev(int capture_dev, int render_dev)
+{
+    pjmedia_vid_dev_info info;
+    pj_status_t status;
+
+    if (capture_dev < 0)
+	capture_dev = PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
+    if (render_dev < 0)
+	render_dev = PJMEDIA_VID_DEFAULT_RENDER_DEV;
+
+    status = pjmedia_vid_dev_get_info(capture_dev, &info);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    status = pjmedia_vid_dev_get_info(render_dev, &info);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    pjsua_var.vcap_dev = capture_dev;
+    pjsua_var.vrdr_dev = render_dev;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Configure video device setting to the video device being used.
+ */
+PJ_DECL(pj_status_t) pjsua_vid_set_setting(pjmedia_vid_dev_cap cap,
+					   const void *pval,
+					   pj_bool_t keep)
+{
+    PJ_UNUSED_ARG(cap);
+    PJ_UNUSED_ARG(pval);
+    PJ_UNUSED_ARG(keep);
+    return PJ_ENOTSUP;
+}
+
+
+/*
+ * Retrieve a video device setting.
+ */
+PJ_DECL(pj_status_t) pjsua_vid_get_setting(pjmedia_aud_dev_cap cap,
+					   void *pval)
+{
+    PJ_UNUSED_ARG(cap);
+    PJ_UNUSED_ARG(pval);
+    return PJ_ENOTSUP;
+}
+
+#endif /* PJMEDIA_HAS_VIDEO */
