Index: pjproject/trunk/pjlib/include/pj/config_site_sample.h
===================================================================
--- pjproject/trunk/pjlib/include/pj/config_site_sample.h	(revision 5137)
+++ pjproject/trunk/pjlib/include/pj/config_site_sample.h	(revision 5138)
@@ -392,4 +392,7 @@
     /* Fine tune Speex's default settings for best performance/quality */
     #define PJMEDIA_CODEC_SPEEX_DEFAULT_QUALITY	5
+    
+    /* Increase number of video device's supported formats */
+    #define PJMEDIA_VID_DEV_INFO_FMT_CNT	128
 
     /*
Index: pjproject/trunk/pjmedia/src/pjmedia-videodev/android_dev.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia-videodev/android_dev.c	(revision 5137)
+++ pjproject/trunk/pjmedia/src/pjmedia-videodev/android_dev.c	(revision 5138)
@@ -17,4 +17,5 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+#include "util.h"
 #include <pjmedia-videodev/videodev_imp.h>
 #include <pj/assert.h>
@@ -39,4 +40,8 @@
 #define ALIGN16(x)		((((x)+15) >> 4) << 4)
 
+/* Define whether we should maintain the aspect ratio when rotating the image.
+ * For more details, please refer to util.h.
+ */
+#define MAINTAIN_ASPECT_RATIO 	PJ_TRUE
 
 /* Format map info */
@@ -119,4 +124,8 @@
     /** NV21/YV12 -> I420 Conversion buffer  */
     pj_uint8_t		   *convert_buf;
+    pjmedia_rect_size	    cam_size;
+    
+    /** Converter to rotate frame  */
+    pjmedia_vid_dev_conv    conv;
     
     /** Frame format param for NV21/YV12 -> I420 conversion */
@@ -512,5 +521,6 @@
 	vdi->dir = PJMEDIA_DIR_CAPTURE;
 	vdi->has_callback = PJ_TRUE;
-	vdi->caps = PJMEDIA_VID_DEV_CAP_SWITCH;
+	vdi->caps = PJMEDIA_VID_DEV_CAP_SWITCH |
+		    PJMEDIA_VID_DEV_CAP_ORIENTATION;
 
 	/* Set driver & name info */
@@ -579,10 +589,17 @@
 
 		for (k = 0; k < adi->sup_size_cnt &&
-			    vdi->fmt_cnt < max_fmt_cnt; k++)
+			    vdi->fmt_cnt < max_fmt_cnt-1; k++)
 		{
+		    /* Landscape video */
 		    pjmedia_format_init_video(&vdi->fmt[vdi->fmt_cnt++],
 					      fmt,
 					      adi->sup_size[k].w,
 					      adi->sup_size[k].h,
+					      DEFAULT_FPS, 1);
+		    /* Portrait video */
+		    pjmedia_format_init_video(&vdi->fmt[vdi->fmt_cnt++],
+					      fmt,
+					      adi->sup_size[k].h,
+					      adi->sup_size[k].w,
 					      DEFAULT_FPS, 1);
 		}
@@ -599,5 +616,5 @@
 		adi->forced_i420 = PJ_TRUE;
 		for (k = 0; k < adi->sup_size_cnt &&
-			    vdi->fmt_cnt < max_fmt_cnt; k++)
+			    vdi->fmt_cnt < max_fmt_cnt-1; k++)
 		{
 		    pjmedia_format_init_video(&vdi->fmt[vdi->fmt_cnt++],
@@ -605,4 +622,9 @@
 					      adi->sup_size[k].w,
 					      adi->sup_size[k].h,
+					      DEFAULT_FPS, 1);
+		    pjmedia_format_init_video(&vdi->fmt[vdi->fmt_cnt++],
+					      PJMEDIA_FORMAT_I420,
+					      adi->sup_size[k].h,
+					      adi->sup_size[k].w,
 					      DEFAULT_FPS, 1);
 		}
@@ -637,5 +659,5 @@
     for (i = 0; i < f->dev_count; i++) {
 	and_dev_info *adi = &f->dev_info[i];
-	char tmp_str[1024], *p;
+	char tmp_str[2048], *p;
 	int j, plen, slen;
 	PJ_LOG(4, (THIS_FILE, "%2d: %s", i, f->dev_info[i].info.name));
@@ -793,8 +815,10 @@
 
     /* Instantiate PjCamera */
+    strm->cam_size.w = (vfd->size.w > vfd->size.h? vfd->size.w: vfd->size.h);
+    strm->cam_size.h = (vfd->size.w > vfd->size.h? vfd->size.h: vfd->size.w);
     jcam = (*jni_env)->NewObject(jni_env, jobjs.cam.cls, jobjs.cam.m_init,
 				 adi->dev_idx,		/* idx */
-				 vfd->size.w,		/* w */
-				 vfd->size.h,		/* h */
+				 strm->cam_size.w,	/* w */
+				 strm->cam_size.h,	/* h */
 				 and_fmt,		/* fmt */
 				 vfd->fps.num*1000/
@@ -814,4 +838,17 @@
         status = PJMEDIA_EVID_SYSERR;
 	goto on_return;
+    }
+    
+    /* Video orientation.
+     * If we send in portrait, we need to set up orientation converter
+     * as well.
+     */
+    if ((param->flags & PJMEDIA_VID_DEV_CAP_ORIENTATION) ||
+        (vfd->size.h > vfd->size.w))
+    {
+        if (param->orient == PJMEDIA_ORIENT_UNKNOWN)
+    	    param->orient = PJMEDIA_ORIENT_NATURAL;
+        and_stream_set_cap(&strm->base, PJMEDIA_VID_DEV_CAP_ORIENTATION,
+    		           &param->orient);
     }
 
@@ -922,4 +959,38 @@
 	}
 
+        case PJMEDIA_VID_DEV_CAP_ORIENTATION:
+        {
+            pjmedia_orient orient = *(pjmedia_orient *)pval;
+
+	    pj_assert(orient >= PJMEDIA_ORIENT_UNKNOWN &&
+	              orient <= PJMEDIA_ORIENT_ROTATE_270DEG);
+
+            if (orient == PJMEDIA_ORIENT_UNKNOWN)
+                return PJ_EINVAL;
+
+            pj_memcpy(&strm->param.orient, pval,
+                      sizeof(strm->param.orient));
+
+	    if (!strm->conv.conv) {
+	        status = pjmedia_vid_dev_conv_create_converter(
+	        				 &strm->conv, strm->pool,
+	        		        	 &strm->param.fmt,
+	        		        	 strm->cam_size,
+	        		        	 strm->param.fmt.det.vid.size,
+	        		        	 PJ_TRUE,
+	        		        	 MAINTAIN_ASPECT_RATIO);
+	    	
+	    	if (status != PJ_SUCCESS)
+	    	    return status;
+	    }
+	    
+	    pjmedia_vid_dev_conv_set_rotation(&strm->conv, strm->param.orient);
+	    
+	    PJ_LOG(4, (THIS_FILE, "Video capture orientation set to %d",
+	    			  strm->param.orient));
+
+            break;
+        }
+
 	default:
 	    status = PJMEDIA_EVID_INVCAP;
@@ -1006,4 +1077,6 @@
     jni_detach_env(with_attach);
     
+    pjmedia_vid_dev_conv_destroy_converter(&strm->conv);
+    
     if (strm->pool)
 	pj_pool_release(strm->pool);
@@ -1021,4 +1094,6 @@
     pjmedia_frame f;
     pj_uint8_t *Y, *U, *V;
+    pj_status_t status; 
+    void *frame_buf, *data_buf;     
 
     strm->frame_ts.u64 += strm->ts_inc;
@@ -1040,5 +1115,5 @@
     f.size = length;
     f.timestamp.u64 = strm->frame_ts.u64;
-    f.buf = (*env)->GetByteArrayElements(env, data, 0);
+    f.buf = data_buf = (*env)->GetByteArrayElements(env, data, 0);
 
     Y = (pj_uint8_t*)f.buf;
@@ -1116,7 +1191,14 @@
 	}
     }
+    
+    status = pjmedia_vid_dev_conv_resize_and_rotate(&strm->conv, 
+    						    f.buf,
+    				       		    &frame_buf);
+    if (status == PJ_SUCCESS) {
+        f.buf = frame_buf;
+    }
 
     (*strm->vid_cb.capture_cb)(&strm->base, strm->user_data, &f);
-    (*env)->ReleaseByteArrayElements(env, data, f.buf, JNI_ABORT);
+    (*env)->ReleaseByteArrayElements(env, data, data_buf, JNI_ABORT);
 }
 
Index: pjproject/trunk/pjmedia/src/pjmedia-videodev/ios_dev.m
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia-videodev/ios_dev.m	(revision 5137)
+++ pjproject/trunk/pjmedia/src/pjmedia-videodev/ios_dev.m	(revision 5138)
@@ -40,7 +40,7 @@
 
 /* Define whether we should maintain the aspect ratio when rotating the image.
- * For more details, please refer to vid_util.h.
+ * For more details, please refer to util.h.
  */
-#define MAINTAIN_ASPECT_RATIO PJ_TRUE
+#define MAINTAIN_ASPECT_RATIO 	PJ_TRUE
 
 typedef struct ios_fmt_info
Index: pjproject/trunk/pjmedia/src/pjmedia-videodev/util.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia-videodev/util.c	(revision 5137)
+++ pjproject/trunk/pjmedia/src/pjmedia-videodev/util.c	(revision 5138)
@@ -169,9 +169,11 @@
     pjmedia_vid_dev_conv_set_rotation(conv, PJMEDIA_ORIENT_NATURAL);
 
-    PJ_LOG(4, (THIS_FILE, "Orientation converter created: %dx%d to %dx%d",
+    PJ_LOG(4, (THIS_FILE, "Orientation converter created: %dx%d to %dx%d, "
+    			  "maintain aspect ratio=%s",
 			  conv_param.src.det.vid.size.w,
 			  conv_param.src.det.vid.size.h,
 			  conv_param.dst.det.vid.size.w,
-			  conv_param.dst.det.vid.size.h));
+			  conv_param.dst.det.vid.size.h,
+			  maintain_aspect_ratio? "yes": "no"));
 			  
     return PJ_SUCCESS;
Index: pjproject/trunk/pjsip-apps/src/swig/java/android/AndroidManifest.xml
===================================================================
--- pjproject/trunk/pjsip-apps/src/swig/java/android/AndroidManifest.xml	(revision 5137)
+++ pjproject/trunk/pjsip-apps/src/swig/java/android/AndroidManifest.xml	(revision 5138)
@@ -41,4 +41,5 @@
         <activity
             android:name="org.pjsip.pjsua2.app.CallActivity"
+            android:configChanges="orientation|keyboardHidden|screenSize"
             android:label="@string/title_activity_call" >
         </activity>
Index: pjproject/trunk/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/CallActivity.java
===================================================================
--- pjproject/trunk/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/CallActivity.java	(revision 5137)
+++ pjproject/trunk/pjsip-apps/src/swig/java/android/src/org/pjsip/pjsua2/app/CallActivity.java	(revision 5138)
@@ -22,10 +22,15 @@
 import android.os.Handler;
 import android.os.Message;
+import android.view.Display;
+import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.View;
+import android.view.WindowManager;
 import android.widget.Button;
 import android.widget.TextView;
 import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
 
 import org.pjsip.pjsua2.*;
@@ -132,4 +137,47 @@
 
     @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        
+        WindowManager wm;
+        Display display;
+        int rotation;
+        pjmedia_orient orient;
+
+        wm = (WindowManager)this.getSystemService(Context.WINDOW_SERVICE);
+        display = wm.getDefaultDisplay();
+        rotation = display.getRotation();
+        System.out.println("Device orientation changed: " + rotation);
+        
+        switch (rotation) {
+        case Surface.ROTATION_0:   // Portrait
+            orient = pjmedia_orient.PJMEDIA_ORIENT_ROTATE_270DEG;
+            break;
+        case Surface.ROTATION_90:  // Landscape, home button on the right
+            orient = pjmedia_orient.PJMEDIA_ORIENT_NATURAL;
+            break;
+        case Surface.ROTATION_180:
+            orient = pjmedia_orient.PJMEDIA_ORIENT_ROTATE_90DEG;
+            break;
+        case Surface.ROTATION_270: // Landscape, home button on the left
+            orient = pjmedia_orient.PJMEDIA_ORIENT_ROTATE_180DEG;
+            break;
+        default:
+            orient = pjmedia_orient.PJMEDIA_ORIENT_UNKNOWN;
+        }
+
+        if (MyApp.ep != null && MainActivity.account != null) {
+            try {
+        	AccountConfig cfg = MainActivity.account.cfg;
+        	int cap_dev = cfg.getVideoConfig().getDefaultCaptureDevice();
+        	MyApp.ep.vidDevManager().setCaptureOrient(cap_dev, orient,
+        						  true);
+            } catch (Exception e) {
+        	System.out.println(e);
+            }
+        }
+    }    
+
+    @Override
     protected void onDestroy()
     {
@@ -256,4 +304,8 @@
 
 	    if (MainActivity.currentCall.vidWin != null) {
+		/* Set capture orientation according to current
+		 * device orientation.
+		 */
+		onConfigurationChanged(getResources().getConfiguration());
 		/* If there's incoming video, display it. */
 		setupVideoSurface();
Index: pjproject/trunk/pjsip-apps/src/swig/symbols.i
===================================================================
--- pjproject/trunk/pjsip-apps/src/swig/symbols.i	(revision 5137)
+++ pjproject/trunk/pjsip-apps/src/swig/symbols.i	(revision 5138)
@@ -94,4 +94,6 @@
 typedef enum pjmedia_tp_proto {PJMEDIA_TP_PROTO_NONE = 0, PJMEDIA_TP_PROTO_RTP_AVP, PJMEDIA_TP_PROTO_RTP_SAVP, PJMEDIA_TP_PROTO_UNKNOWN} pjmedia_tp_proto;
 
+typedef enum pjmedia_orient {PJMEDIA_ORIENT_UNKNOWN, PJMEDIA_ORIENT_NATURAL, PJMEDIA_ORIENT_ROTATE_90DEG, PJMEDIA_ORIENT_ROTATE_180DEG, PJMEDIA_ORIENT_ROTATE_270DEG} pjmedia_orient;
+
 typedef enum pjmedia_format_id {PJMEDIA_FORMAT_L16 = 0, PJMEDIA_FORMAT_PCM = PJMEDIA_FORMAT_L16, PJMEDIA_FORMAT_PCMA = ((('W' << 24) | ('A' << 16)) | ('L' << 8)) | 'A', PJMEDIA_FORMAT_ALAW = PJMEDIA_FORMAT_PCMA, PJMEDIA_FORMAT_PCMU = ((('W' << 24) | ('A' << 16)) | ('L' << 8)) | 'u', PJMEDIA_FORMAT_ULAW = PJMEDIA_FORMAT_PCMU, PJMEDIA_FORMAT_AMR = ((('R' << 24) | ('M' << 16)) | ('A' << 8)) | ' ', PJMEDIA_FORMAT_G729 = ((('9' << 24) | ('2' << 16)) | ('7' << 8)) | 'G', PJMEDIA_FORMAT_ILBC = ((('C' << 24) | ('B' << 16)) | ('L' << 8)) | 'I', PJMEDIA_FORMAT_RGB24 = ((('3' << 24) | ('B' << 16)) | ('G' << 8)) | 'R', PJMEDIA_FORMAT_RGBA = ((('A' << 24) | ('B' << 16)) | ('G' << 8)) | 'R', PJMEDIA_FORMAT_BGRA = ((('A' << 24) | ('R' << 16)) | ('G' << 8)) | 'B', PJMEDIA_FORMAT_RGB32 = PJMEDIA_FORMAT_RGBA, PJMEDIA_FORMAT_DIB = (((' ' << 24) | ('B' << 16)) | ('I' << 8)) | 'D', PJMEDIA_FORMAT_GBRP = ((('P' << 24) | ('R' << 16)) | ('B' << 8)) | 'G', PJMEDIA_FORMAT_AYUV = ((('V' << 24) | ('U' << 16)) | ('Y' << 8)) | 'A', PJMEDIA_FORMAT_YUY2 = ((('2' << 24) | ('Y' << 16)) | ('U' << 8)) | 'Y', PJMEDIA_FORMAT_UYVY = ((('Y' << 24) | ('V' << 16)) | ('Y' << 8)) | 'U', PJMEDIA_FORMAT_YVYU = ((('U' << 24) | ('Y' << 16)) | ('V' << 8)) | 'Y', PJMEDIA_FORMAT_I420 = ((('0' << 24) | ('2' << 16)) | ('4' << 8)) | 'I', PJMEDIA_FORMAT_IYUV = PJMEDIA_FORMAT_I420, PJMEDIA_FORMAT_YV12 = ((('2' << 24) | ('1' << 16)) | ('V' << 8)) | 'Y', PJMEDIA_FORMAT_NV21 = ((('1' << 24) | ('2' << 16)) | ('V' << 8)) | 'N', PJMEDIA_FORMAT_I422 = ((('2' << 24) | ('2' << 16)) | ('4' << 8)) | 'I', PJMEDIA_FORMAT_I420JPEG = ((('0' << 24) | ('2' << 16)) | ('4' << 8)) | 'J', PJMEDIA_FORMAT_I422JPEG = ((('2' << 24) | ('2' << 16)) | ('4' << 8)) | 'J', PJMEDIA_FORMAT_H261 = ((('1' << 24) | ('6' << 16)) | ('2' << 8)) | 'H', PJMEDIA_FORMAT_H263 = ((('3' << 24) | ('6' << 16)) | ('2' << 8)) | 'H', PJMEDIA_FORMAT_H263P = ((('3' << 24) | ('6' << 16)) | ('2' << 8)) | 'P', PJMEDIA_FORMAT_H264 = ((('4' << 24) | ('6' << 16)) | ('2' << 8)) | 'H', PJMEDIA_FORMAT_MJPEG = ((('G' << 24) | ('P' << 16)) | ('J' << 8)) | 'M', PJMEDIA_FORMAT_MPEG1VIDEO = ((('V' << 24) | ('1' << 16)) | ('P' << 8)) | 'M', PJMEDIA_FORMAT_MPEG2VIDEO = ((('V' << 24) | ('2' << 16)) | ('P' << 8)) | 'M', PJMEDIA_FORMAT_MPEG4 = ((('4' << 24) | ('G' << 16)) | ('P' << 8)) | 'M'} pjmedia_format_id;
 
Index: pjproject/trunk/pjsip-apps/src/swig/symbols.lst
===================================================================
--- pjproject/trunk/pjsip-apps/src/swig/symbols.lst	(revision 5137)
+++ pjproject/trunk/pjsip-apps/src/swig/symbols.lst	(revision 5138)
@@ -15,5 +15,5 @@
 pjmedia/wav_port.h              pjmedia_file_writer_option pjmedia_file_player_option
 pjmedia/tonegen.h		pjmedia_tone_digit pjmedia_tone_digit_map pjmedia_tone_desc
-pjmedia/types.h                 pjmedia_type pjmedia_dir pjmedia_tp_proto
+pjmedia/types.h                 pjmedia_type pjmedia_dir pjmedia_tp_proto pjmedia_orient
 pjmedia/format.h		pjmedia_format_id
 
Index: pjproject/trunk/pjsip/include/pjsua2/media.hpp
===================================================================
--- pjproject/trunk/pjsip/include/pjsua2/media.hpp	(revision 5137)
+++ pjproject/trunk/pjsip/include/pjsua2/media.hpp	(revision 5138)
@@ -1674,4 +1674,37 @@
     const VideoDevInfoVector &enumDev() throw(Error);
 
+    /**
+     * Check whether the video capture device is currently active, i.e. if
+     * a video preview has been started or there is a video call using
+     * the device.    
+     *
+     * @param dev_id	The video device id
+     * 
+     * @return		True if it's active.
+     */
+    bool isCaptureActive(int dev_id) const;
+
+    /**
+     * This will configure video orientation of the video capture device.
+     * If the device is currently active (i.e. if there is a video call
+     * using the device or a video preview has been started), the method
+     * 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 true. If the video device is
+     * currently inactive, and the "keep" argument is false, this method
+     * will throw Error.
+     *
+     * @param dev_id	The video device id
+     * @param orient	The video orientation.
+     * @param keep	Specify whether the setting is to be kept for
+     * 			future use.
+     *
+     */
+    void setCaptureOrient(pjmedia_vid_dev_index dev_id,
+    			  pjmedia_orient orient,
+    			  bool keep=true) throw(Error);
+
 private:
     VideoDevInfoVector videoDevList;
Index: pjproject/trunk/pjsip/src/pjsua2/media.cpp
===================================================================
--- pjproject/trunk/pjsip/src/pjsua2/media.cpp	(revision 5137)
+++ pjproject/trunk/pjsip/src/pjsua2/media.cpp	(revision 5138)
@@ -1307,4 +1307,26 @@
 }
 
+bool VidDevManager::isCaptureActive(int dev_id) const
+{
+#if PJSUA_HAS_VIDEO
+    return (pjsua_vid_dev_is_active(dev_id) == PJ_TRUE? true: false);
+#else
+    PJ_UNUSED_ARG(dev_id);
+    
+    return false;
+#endif
+}
+    
+void VidDevManager::setCaptureOrient(pjmedia_vid_dev_index dev_id,
+    			  	     pjmedia_orient orient,
+    			  	     bool keep) throw(Error)
+{
+#if PJSUA_HAS_VIDEO
+    PJSUA2_CHECK_EXPR(pjsua_vid_dev_set_setting(dev_id,
+    			  PJMEDIA_VID_DEV_CAP_ORIENTATION, &orient, keep));
+#endif
+}
+
+
 VidDevManager::VidDevManager()
 {
