Index: pjproject/trunk/pjmedia/src/pjmedia-videodev/ios_dev.m
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia-videodev/ios_dev.m	(revision 5054)
+++ pjproject/trunk/pjmedia/src/pjmedia-videodev/ios_dev.m	(revision 5118)
@@ -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>
@@ -37,4 +38,9 @@
 #define DEFAULT_HEIGHT		288
 #define DEFAULT_FPS		15
+
+/* Define whether we should maintain the aspect ratio when rotating the image.
+ * For more details, please refer to vid_util.h.
+ */
+#define MAINTAIN_ASPECT_RATIO PJ_TRUE
 
 typedef struct ios_fmt_info
@@ -109,4 +115,8 @@
     NSLock 		   *frame_lock;
     void                   *capture_buf;
+    void		   *frame_buf;
+    
+    pjmedia_vid_dev_conv    conv;
+    pjmedia_rect_size	    vid_size;
     
     AVCaptureSession		*cap_session;
@@ -314,4 +324,5 @@
                                                        ios_sizes[m].preset_str])
                     {
+                        /* Landscape video */
                         fmt = &qdi->info.fmt[qdi->info.fmt_cnt++];
                         pjmedia_format_init_video(fmt,
@@ -319,4 +330,11 @@
                                                   ios_sizes[m].supported_size_w,
                                                   ios_sizes[m].supported_size_h,
+                                                  DEFAULT_FPS, 1);
+                        /* Portrait video */
+                        fmt = &qdi->info.fmt[qdi->info.fmt_cnt++];
+                        pjmedia_format_init_video(fmt,
+                                                  ios_fmts[l].pjmedia_format,
+                                                  ios_sizes[m].supported_size_h,
+                                                  ios_sizes[m].supported_size_w,
                                                   DEFAULT_FPS, 1);
                     }
@@ -436,4 +454,6 @@
 {
     CVImageBufferRef img;
+    pj_status_t status;
+    void *frame_buf;
 
     /* Refrain from calling pjlib functions which require thread registration
@@ -452,5 +472,4 @@
     /* Lock the base address of the pixel buffer */
     CVPixelBufferLockBaseAddress(img, kCVPixelBufferLock_ReadOnly);
-    
 
     [stream->frame_lock lock];
@@ -464,8 +483,17 @@
              */
             pj_size_t stride = CVPixelBufferGetBytesPerRowOfPlane(img, 0);
-            pj_bool_t need_clip = (stride != stream->size.w);
+            pj_size_t height = CVPixelBufferGetHeight(img);
+            pj_bool_t need_clip;
+            
+            /* Auto detect rotation */
+            if (height != stream->vid_size.h) {
+                stream->vid_size.w = stream->vid_size.h;
+                stream->vid_size.h = height;
+            }
+            
+            need_clip = (stride != stream->vid_size.w);
             
             p = (pj_uint8_t*)CVPixelBufferGetBaseAddressOfPlane(img, 0);
-            p_len = stream->size.w * stream->size.h;
+            p_len = stream->vid_size.w * stream->vid_size.h;
             Y = (pj_uint8_t*)stream->capture_buf;
             U = Y + p_len;
@@ -476,7 +504,8 @@
             } else {
                 int i = 0;
-                for (;i<stream->size.h;++i) {
-                    pj_memcpy(Y+(i*stream->size.w), p+(i*stride),
-                              stream->size.w);
+                for (; i < stream->vid_size.h; ++i) {
+                    pj_memcpy(Y, p, stream->vid_size.w);
+                    Y += stream->vid_size.w;
+                    p += stride;
                 }
             }
@@ -493,11 +522,11 @@
             } else {
                 int i = 0;
-                for (;i<(stream->size.h)/2;++i) {
+                for (;i<(stream->vid_size.h)/2;++i) {
                     int y=0;
-                    for (;y<(stream->size.w)/2;++y) {
+                    for (;y<(stream->vid_size.w)/2;++y) {
                         *U++ = *p++;
                         *V++ = *p++;
                     }
-                    p += (stride - stream->size.w);
+                    p += (stride - stream->vid_size.w);
                 }
             }
@@ -506,4 +535,11 @@
         pj_memcpy(stream->capture_buf, CVPixelBufferGetBaseAddress(img),
                   stream->frame_size);
+    }
+    
+    status = pjmedia_vid_dev_conv_resize_and_rotate(&stream->conv, 
+    						    stream->capture_buf,
+    				       		    &frame_buf);
+    if (status == PJ_SUCCESS) {
+        stream->frame_buf = frame_buf;
     }
 
@@ -528,5 +564,5 @@
     
     [stream->frame_lock lock];
-    pj_memcpy(frame->buf, stream->capture_buf, stream->frame_size);
+    pj_memcpy(frame->buf, stream->frame_buf, stream->frame_size);
     [stream->frame_lock unlock];
     
@@ -646,6 +682,8 @@
  
         for (i = PJ_ARRAY_SIZE(ios_sizes)-1; i > 0; --i) {
-            if ((vfd->size.w == ios_sizes[i].supported_size_w) &&
-                (vfd->size.h == ios_sizes[i].supported_size_h))
+            if (((vfd->size.w == ios_sizes[i].supported_size_w) &&
+                 (vfd->size.h == ios_sizes[i].supported_size_h)) ||
+                ((vfd->size.w == ios_sizes[i].supported_size_h) &&
+                 (vfd->size.h == ios_sizes[i].supported_size_w)))
             {
                 break;
@@ -655,7 +693,16 @@
         strm->cap_session.sessionPreset = ios_sizes[i].preset_str;
         
-        vfd->size.w = ios_sizes[i].supported_size_w;
-        vfd->size.h = ios_sizes[i].supported_size_h;
+        /* If the requested size is portrait (or landscape), we make
+         * our natural orientation portrait (or landscape) as well.
+         */
+        if (vfd->size.w > vfd->size.h) {
+            vfd->size.w = ios_sizes[i].supported_size_w;
+            vfd->size.h = ios_sizes[i].supported_size_h;
+        } else {
+            vfd->size.h = ios_sizes[i].supported_size_w;
+            vfd->size.w = ios_sizes[i].supported_size_h;
+        }
         strm->size = vfd->size;
+        strm->vid_size = vfd->size;
         strm->bytes_per_row = strm->size.w * vfi->bpp / 8;
         strm->frame_size = strm->bytes_per_row * strm->size.h;
@@ -724,4 +771,5 @@
 	
 	strm->capture_buf = pj_pool_alloc(strm->pool, strm->frame_size);
+	strm->frame_buf = strm->capture_buf;
 	strm->frame_lock = [[NSLock alloc]init];
 	
@@ -730,4 +778,17 @@
             ios_stream_set_cap(&strm->base, PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW,
                                &param->native_preview);
+        }
+
+        /* 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;
+            ios_stream_set_cap(&strm->base, PJMEDIA_VID_DEV_CAP_ORIENTATION,
+                               &param->orient);
         }
         
@@ -988,17 +1049,82 @@
         }
             
-        /* TODO: orientation for capture device */
         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->param.orient == PJMEDIA_ORIENT_UNKNOWN)
-                return PJ_SUCCESS;
-            
-            dispatch_async(dispatch_get_main_queue(), ^{
-                strm->render_view.transform =
-                    CGAffineTransformMakeRotation(
-                        ((int)strm->param.orient-1) * -M_PI_2);
-            });
+        
+            if (strm->param.dir == PJMEDIA_DIR_RENDER) {
+            	dispatch_async(dispatch_get_main_queue(), ^{
+                    strm->render_view.transform =
+                        CGAffineTransformMakeRotation(
+                            ((int)strm->param.orient-1) * -M_PI_2);
+                });
+
+		return PJ_SUCCESS;
+            }
+        
+            const AVCaptureVideoOrientation cap_ori[4] =
+            {
+   		AVCaptureVideoOrientationLandscapeLeft,      /* NATURAL */
+        	AVCaptureVideoOrientationPortrait,           /* 90DEG   */
+   		AVCaptureVideoOrientationLandscapeRight,     /* 180DEG  */
+   		AVCaptureVideoOrientationPortraitUpsideDown, /* 270DEG  */
+            };
+	    AVCaptureConnection *vidcon;
+	    pj_bool_t support_ori = PJ_TRUE;
+	    
+	    pj_assert(strm->param.dir == PJMEDIA_DIR_CAPTURE);
+	    
+	    if (!strm->video_output)
+	        return PJMEDIA_EVID_NOTREADY;
+
+	    vidcon = [strm->video_output 
+	              connectionWithMediaType:AVMediaTypeVideo];
+	    if ([vidcon isVideoOrientationSupported]) {
+	        vidcon.videoOrientation = cap_ori[strm->param.orient-1];
+	    } else {
+	        support_ori = PJ_FALSE;
+	    }
+	    
+	    if (!strm->conv.conv) {
+	        pj_status_t status;
+	        pjmedia_rect_size orig_size;
+
+	        /* Original native size of device is landscape */
+	        orig_size.w = (strm->size.w > strm->size.h? strm->size.w :
+	        	       strm->size.h);
+	        orig_size.h = (strm->size.w > strm->size.h? strm->size.h :
+	        	       strm->size.w);
+
+		if (!support_ori) {
+	            PJ_LOG(4, (THIS_FILE, "Native video capture orientation " 
+	        		          "unsupported, will use converter's "
+	        		          "rotation."));
+	        }
+
+	        status = pjmedia_vid_dev_conv_create_converter(
+	        				 &strm->conv, strm->pool,
+	        		        	 &strm->param.fmt,
+	        		        	 orig_size, strm->size,
+	        		        	 (support_ori?PJ_FALSE:PJ_TRUE),
+	        		        	 MAINTAIN_ASPECT_RATIO);
+	    	
+	    	if (status != PJ_SUCCESS)
+	    	    return status;
+	    }
+	    
+	    pjmedia_vid_dev_conv_set_rotation(&strm->conv, strm->param.orient);
+	    
+	    PJ_LOG(5, (THIS_FILE, "Video capture orientation set to %d",
+	    			  strm->param.orient));
+
             return PJ_SUCCESS;
         }
@@ -1141,4 +1267,6 @@
         stream->frame_lock = nil;
     }
+    
+    pjmedia_vid_dev_conv_destroy_converter(&stream->conv);
 
     pj_pool_release(stream->pool);
