Set resolution based on incoming VideoFrames.

R=pthatcher@webrtc.org
BUG=1788

Review URL: https://webrtc-codereview.appspot.com/17269004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@7042 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/media/base/videoengine_unittest.h b/talk/media/base/videoengine_unittest.h
index 0f03c7b..aa5eff0 100644
--- a/talk/media/base/videoengine_unittest.h
+++ b/talk/media/base/videoengine_unittest.h
@@ -1593,6 +1593,24 @@
     frame_count += 2;
     EXPECT_EQ_WAIT(frame_count, renderer_.num_rendered_frames(), kTimeout);
   }
+  // Tests that adapted frames won't be upscaled to a higher resolution.
+  void SendsLowerResolutionOnSmallerFrames() {
+    cricket::VideoCodec codec = DefaultCodec();
+    codec.width = 320;
+    codec.height = 240;
+    EXPECT_TRUE(SetOneCodec(codec));
+    EXPECT_TRUE(SetSend(true));
+    EXPECT_TRUE(channel_->SetRender(true));
+    EXPECT_TRUE(channel_->SetRenderer(kDefaultReceiveSsrc, &renderer_));
+    EXPECT_EQ(0, renderer_.num_rendered_frames());
+    EXPECT_TRUE(SendFrame());
+    EXPECT_FRAME_WAIT(1, codec.width, codec.height, kTimeout);
+
+    // Check that we send smaller frames at the new resolution.
+    EXPECT_TRUE(video_capturer_->CaptureCustomFrame(
+        codec.width / 2, codec.height / 2, cricket::FOURCC_I420));
+    EXPECT_FRAME_WAIT(2, codec.width / 2, codec.height / 2, kTimeout);
+  }
   // Tests that we can set the send stream format properly.
   void SetSendStreamFormat() {
     cricket::VideoCodec codec(DefaultCodec());
diff --git a/talk/media/webrtc/webrtcvideoengine2.cc b/talk/media/webrtc/webrtcvideoengine2.cc
index efd3df4..97d274d 100644
--- a/talk/media/webrtc/webrtcvideoengine2.cc
+++ b/talk/media/webrtc/webrtcvideoengine2.cc
@@ -1364,15 +1364,15 @@
     const VideoFrame* frame) {
   LOG(LS_VERBOSE) << "InputFrame: " << frame->GetWidth() << "x"
                   << frame->GetHeight();
-  bool is_screencast = capturer->IsScreencast();
   // Lock before copying, can be called concurrently when swapping input source.
   rtc::CritScope frame_cs(&frame_lock_);
   if (!muted_) {
     ConvertToI420VideoFrame(*frame, &video_frame_);
   } else {
-    // Create a tiny black frame to transmit instead.
-    CreateBlackFrame(&video_frame_, 1, 1);
-    is_screencast = false;
+    // Create a black frame to transmit instead.
+    CreateBlackFrame(&video_frame_,
+                     static_cast<int>(frame->GetWidth()),
+                     static_cast<int>(frame->GetHeight()));
   }
   rtc::CritScope cs(&lock_);
   if (stream_ == NULL) {
@@ -1386,9 +1386,9 @@
     return;
   }
   // Reconfigure codec if necessary.
-  if (is_screencast) {
-    SetDimensions(video_frame_.width(), video_frame_.height());
-  }
+  SetDimensions(
+      video_frame_.width(), video_frame_.height(), capturer->IsScreencast());
+
   LOG(LS_VERBOSE) << "SwapFrame: " << video_frame_.width() << "x"
                   << video_frame_.height() << " -> (codec) "
                   << parameters_.video_streams.back().width << "x"
@@ -1416,7 +1416,7 @@
         black_frame.CreateEmptyFrame(
             width, height, width, half_width, half_width);
         SetWebRtcFrameToBlack(&black_frame);
-        SetDimensions(width, height);
+        SetDimensions(width, height, false);
         stream_->Input()->SwapFrame(&black_frame);
       }
 
@@ -1450,7 +1450,7 @@
     // TODO(pbos): Fix me, this only affects the last stream!
     parameters_.video_streams.back().max_framerate =
         VideoFormat::IntervalToFps(format.interval);
-    SetDimensions(format.width, format.height);
+    SetDimensions(format.width, format.height, false);
   }
 
   format_ = format;
@@ -1539,10 +1539,23 @@
   RecreateWebRtcStream();
 }
 
-void WebRtcVideoChannel2::WebRtcVideoSendStream::SetDimensions(int width,
-                                                               int height) {
+void WebRtcVideoChannel2::WebRtcVideoSendStream::SetDimensions(
+    int width,
+    int height,
+    bool override_max) {
   assert(!parameters_.video_streams.empty());
   LOG(LS_VERBOSE) << "SetDimensions: " << width << "x" << height;
+
+  VideoCodecSettings codec_settings;
+  parameters_.codec_settings.Get(&codec_settings);
+  // Restrict dimensions according to codec max.
+  if (!override_max) {
+    if (codec_settings.codec.width < width)
+      width = codec_settings.codec.width;
+    if (codec_settings.codec.height < height)
+      height = codec_settings.codec.height;
+  }
+
   if (parameters_.video_streams.back().width == width &&
       parameters_.video_streams.back().height == height) {
     return;
@@ -1552,8 +1565,6 @@
   parameters_.video_streams.back().width = width;
   parameters_.video_streams.back().height = height;
 
-  VideoCodecSettings codec_settings;
-  parameters_.codec_settings.Get(&codec_settings);
   void* encoder_settings = encoder_factory_->CreateVideoEncoderSettings(
       codec_settings.codec, parameters_.options);
 
diff --git a/talk/media/webrtc/webrtcvideoengine2.h b/talk/media/webrtc/webrtcvideoengine2.h
index dbd3990..d77afb9 100644
--- a/talk/media/webrtc/webrtcvideoengine2.h
+++ b/talk/media/webrtc/webrtcvideoengine2.h
@@ -322,7 +322,8 @@
     void SetCodecAndOptions(const VideoCodecSettings& codec,
                             const VideoOptions& options);
     void RecreateWebRtcStream();
-    void SetDimensions(int width, int height);
+    // When |override_max| is false constrain width/height to codec dimensions.
+    void SetDimensions(int width, int height, bool override_max);
 
     webrtc::Call* const call_;
     WebRtcVideoEncoderFactory2* const encoder_factory_;
diff --git a/talk/media/webrtc/webrtcvideoengine2_unittest.cc b/talk/media/webrtc/webrtcvideoengine2_unittest.cc
index 6aaa7bd..4f69f6d 100644
--- a/talk/media/webrtc/webrtcvideoengine2_unittest.cc
+++ b/talk/media/webrtc/webrtcvideoengine2_unittest.cc
@@ -536,15 +536,17 @@
 
 WEBRTC_BASE_TEST(AdaptResolution4x3);
 
-WEBRTC_BASE_TEST(MuteStream);
-
-WEBRTC_BASE_TEST(MultipleSendStreams);
-
 // TODO(juberti): Restore this test once we support sending 0 fps.
 WEBRTC_DISABLED_BASE_TEST(AdaptDropAllFrames);
 // TODO(juberti): Understand why we get decode errors on this test.
 WEBRTC_DISABLED_BASE_TEST(AdaptFramerate);
 
+WEBRTC_BASE_TEST(SendsLowerResolutionOnSmallerFrames);
+
+WEBRTC_BASE_TEST(MuteStream);
+
+WEBRTC_BASE_TEST(MultipleSendStreams);
+
 WEBRTC_BASE_TEST(SetSendStreamFormat0x0);
 
 // TODO(zhurunz): Fix the flakey test.