Implement Base::ConstrainNewCodec2.

BUG=1788
R=wu@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk/talk@6743 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/media/webrtc/webrtcvideoengine2.cc b/media/webrtc/webrtcvideoengine2.cc
index 1ce1b99..21e51eb 100644
--- a/media/webrtc/webrtcvideoengine2.cc
+++ b/media/webrtc/webrtcvideoengine2.cc
@@ -73,28 +73,8 @@
 
 // The formats are sorted by the descending order of width. We use the order to
 // find the next format for CPU and bandwidth adaptation.
-const VideoFormatPod kDefaultVideoFormat = {
+const VideoFormatPod kDefaultMaxVideoFormat = {
     640, 400, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY};
-const VideoFormatPod kVideoFormats[] = {
-    {1280, 800, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
-    {1280, 720, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
-    {960, 600, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
-    {960, 540, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
-    kDefaultVideoFormat,
-    {640, 360, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
-    {640, 480, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
-    {480, 300, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
-    {480, 270, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
-    {480, 360, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
-    {320, 200, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
-    {320, 180, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
-    {320, 240, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
-    {240, 150, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
-    {240, 135, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
-    {240, 180, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
-    {160, 100, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
-    {160, 90, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY},
-    {160, 120, FPS_TO_INTERVAL(kDefaultFramerate), FOURCC_ANY}, };
 
 static bool FindFirstMatchingCodec(const std::vector<VideoCodec>& codecs,
                                    const VideoCodec& requested_codec,
@@ -107,49 +87,6 @@
   }
   return false;
 }
-static bool FindBestVideoFormat(int max_width,
-                                int max_height,
-                                int aspect_width,
-                                int aspect_height,
-                                VideoFormat* video_format) {
-  assert(max_width > 0);
-  assert(max_height > 0);
-  assert(aspect_width > 0);
-  assert(aspect_height > 0);
-  VideoFormat best_format;
-  for (int i = 0; i < ARRAY_SIZE(kVideoFormats); ++i) {
-    const VideoFormat format(kVideoFormats[i]);
-
-    // Skip any format that is larger than the local or remote maximums, or
-    // smaller than the current best match
-    if (format.width > max_width || format.height > max_height ||
-        (format.width < best_format.width &&
-         format.height < best_format.height)) {
-      continue;
-    }
-
-    // If we don't have any matches yet, this is the best so far.
-    if (best_format.width == 0) {
-      best_format = format;
-      continue;
-    }
-
-    // Prefer closer aspect ratios i.e:
-    // |format| aspect - requested aspect <
-    // |best_format| aspect - requested aspect
-    if (abs(format.width * aspect_height * best_format.height -
-            aspect_width * format.height * best_format.height) <
-        abs(best_format.width * aspect_height * format.height -
-            aspect_width * format.height * best_format.height)) {
-      best_format = format;
-    }
-  }
-  if (best_format.width != 0) {
-    *video_format = best_format;
-    return true;
-  }
-  return false;
-}
 
 static void AddDefaultFeedbackParams(VideoCodec* codec) {
   const FeedbackParam kFir(kRtcpFbParamCcm, kRtcpFbCcmParamFir);
@@ -170,8 +107,8 @@
 static VideoCodec DefaultVideoCodec() {
   VideoCodec default_codec(kDefaultVideoCodecPref.payload_type,
                            kDefaultVideoCodecPref.name,
-                           kDefaultVideoFormat.width,
-                           kDefaultVideoFormat.height,
+                           kDefaultMaxVideoFormat.width,
+                           kDefaultMaxVideoFormat.height,
                            kDefaultFramerate,
                            0);
   AddDefaultFeedbackParams(&default_codec);
@@ -267,7 +204,7 @@
   channel_factory_ = channel_factory;
 
   video_codecs_ = DefaultVideoCodecs();
-  default_codec_format_ = VideoFormat(kDefaultVideoFormat);
+  default_codec_format_ = VideoFormat(kDefaultMaxVideoFormat);
 
   rtp_header_extensions_.push_back(
       RtpHeaderExtension(kRtpTimestampOffsetHeaderExtension,
@@ -320,8 +257,21 @@
 
 bool WebRtcVideoEngine2::SetDefaultEncoderConfig(
     const VideoEncoderConfig& config) {
-  // TODO(pbos): Implement. Should be covered by corresponding unit tests.
-  LOG(LS_VERBOSE) << "SetDefaultEncoderConfig()";
+  const VideoCodec& codec = config.max_codec;
+  // TODO(pbos): Make use of external encoder factory.
+  if (!GetVideoEncoderFactory()->SupportsCodec(codec)) {
+    LOG(LS_ERROR) << "SetDefaultEncoderConfig, codec not supported:"
+                  << codec.ToString();
+    return false;
+  }
+
+  default_codec_format_ =
+      VideoFormat(codec.width,
+                  codec.height,
+                  VideoFormat::FpsToInterval(codec.framerate),
+                  FOURCC_ANY);
+  video_codecs_.clear();
+  video_codecs_.push_back(codec);
   return true;
 }
 
@@ -382,17 +332,10 @@
   // TODO(pbos): Probe encoder factory to figure out that the codec is supported
   // if supported by the encoder factory. Add a corresponding test that fails
   // with this code (that doesn't ask the factory).
-  for (int i = 0; i < ARRAY_SIZE(kVideoFormats); ++i) {
-    const VideoFormat fmt(kVideoFormats[i]);
-    if ((in.width != 0 || in.height != 0) &&
-        (fmt.width != in.width || fmt.height != in.height)) {
-      continue;
-    }
-    for (size_t j = 0; j < video_codecs_.size(); ++j) {
-      VideoCodec codec(video_codecs_[j].id, video_codecs_[j].name, 0, 0, 0, 0);
-      if (codec.Matches(in)) {
-        return true;
-      }
+  for (size_t j = 0; j < video_codecs_.size(); ++j) {
+    VideoCodec codec(video_codecs_[j].id, video_codecs_[j].name, 0, 0, 0, 0);
+    if (codec.Matches(in)) {
+      return true;
     }
   }
   return false;
@@ -406,7 +349,6 @@
                                       const VideoCodec& current,
                                       VideoCodec* out) {
   assert(out != NULL);
-  // TODO(pbos): Implement.
 
   if (requested.width != requested.height &&
       (requested.height == 0 || requested.width == 0)) {
@@ -420,37 +362,26 @@
     return false;
   }
 
-  // Pick the best quality that is within their and our bounds and has the
-  // correct aspect ratio.
-  VideoFormat format;
-  if (requested.width == 0 && requested.height == 0) {
-    // Special case with resolution 0. The channel should not send frames.
-  } else {
-    int max_width = talk_base::_min(requested.width, matching_codec.width);
-    int max_height = talk_base::_min(requested.height, matching_codec.height);
-    int aspect_width = max_width;
-    int aspect_height = max_height;
-    if (current.width > 0 && current.height > 0) {
-      aspect_width = current.width;
-      aspect_height = current.height;
-    }
-    if (!FindBestVideoFormat(
-            max_width, max_height, aspect_width, aspect_height, &format)) {
-      return false;
-    }
-  }
-
   out->id = requested.id;
   out->name = requested.name;
   out->preference = requested.preference;
   out->params = requested.params;
   out->framerate =
       talk_base::_min(requested.framerate, matching_codec.framerate);
-  out->width = format.width;
-  out->height = format.height;
   out->params = requested.params;
   out->feedback_params = requested.feedback_params;
-  return true;
+  out->width = requested.width;
+  out->height = requested.height;
+  if (requested.width == 0 && requested.height == 0) {
+    return true;
+  }
+
+  while (out->width > matching_codec.width) {
+    out->width /= 2;
+    out->height /= 2;
+  }
+
+  return out->width > 0 && out->height > 0;
 }
 
 bool WebRtcVideoEngine2::SetVoiceEngine(WebRtcVoiceEngine* voice_engine) {
diff --git a/media/webrtc/webrtcvideoengine2_unittest.cc b/media/webrtc/webrtcvideoengine2_unittest.cc
index 0954bcb..45ea161 100644
--- a/media/webrtc/webrtcvideoengine2_unittest.cc
+++ b/media/webrtc/webrtcvideoengine2_unittest.cc
@@ -350,8 +350,10 @@
   vp8_diff_id.id = 97;
   EXPECT_TRUE(engine_.FindCodec(vp8_diff_id));
 
+  // FindCodec ignores the codec size.
+  // Test that FindCodec can accept uncommon codec size.
   cricket::VideoCodec vp8_diff_res(104, "VP8", 320, 111, 30, 0);
-  EXPECT_FALSE(engine_.FindCodec(vp8_diff_res));
+  EXPECT_TRUE(engine_.FindCodec(vp8_diff_res));
 
   // PeerConnection doesn't negotiate the resolution at this point.
   // Test that FindCodec can handle the case when width/height is 0.
@@ -424,6 +426,17 @@
       << "Channel should be stoppable even without set codecs.";
 }
 
+class WebRtcVideoEngine2BaseTest
+    : public VideoEngineTest<cricket::WebRtcVideoEngine2> {
+ protected:
+  typedef VideoEngineTest<cricket::WebRtcVideoEngine2> Base;
+};
+
+#define WEBRTC_ENGINE_BASE_TEST(test) \
+  TEST_F(WebRtcVideoEngine2BaseTest, test) { Base::test##Body(); }
+
+WEBRTC_ENGINE_BASE_TEST(ConstrainNewCodec2);
+
 class WebRtcVideoChannel2BaseTest
     : public VideoMediaChannelTest<WebRtcVideoEngine2, WebRtcVideoChannel2> {
  protected:
@@ -431,118 +444,74 @@
   typedef VideoMediaChannelTest<WebRtcVideoEngine2, WebRtcVideoChannel2> Base;
 };
 
+#define WEBRTC_BASE_TEST(test) \
+  TEST_F(WebRtcVideoChannel2BaseTest, test) { Base::test(); }
+
+#define WEBRTC_DISABLED_BASE_TEST(test) \
+  TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_ ## test) { Base::test(); }
+
 // TODO(pbos): Fix WebRtcVideoEngine2BaseTest, where we want CheckCoInitialize.
 #if 0
 // TODO(juberti): Figure out why ViE is munging the COM refcount.
 #ifdef WIN32
-TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_CheckCoInitialize) {
+WEBRTC_DISABLED_BASE_TEST(CheckCoInitialize) {
   Base::CheckCoInitialize();
 }
 #endif
 #endif
 
-TEST_F(WebRtcVideoChannel2BaseTest, SetSend) { Base::SetSend(); }
+WEBRTC_BASE_TEST(SetSend);
+WEBRTC_BASE_TEST(SetSendWithoutCodecs);
+WEBRTC_BASE_TEST(SetSendSetsTransportBufferSizes);
 
-TEST_F(WebRtcVideoChannel2BaseTest, SetSendWithoutCodecs) {
-  Base::SetSendWithoutCodecs();
-}
+WEBRTC_BASE_TEST(GetStats);
+WEBRTC_BASE_TEST(GetStatsMultipleRecvStreams);
+WEBRTC_BASE_TEST(GetStatsMultipleSendStreams);
 
-TEST_F(WebRtcVideoChannel2BaseTest, SetSendSetsTransportBufferSizes) {
-  Base::SetSendSetsTransportBufferSizes();
-}
+WEBRTC_BASE_TEST(SetSendBandwidth);
 
-TEST_F(WebRtcVideoChannel2BaseTest, GetStats) { Base::GetStats(); }
+WEBRTC_BASE_TEST(SetSendSsrc);
+WEBRTC_BASE_TEST(SetSendSsrcAfterSetCodecs);
 
-TEST_F(WebRtcVideoChannel2BaseTest, GetStatsMultipleRecvStreams) {
-  Base::GetStatsMultipleRecvStreams();
-}
+WEBRTC_BASE_TEST(SetRenderer);
+WEBRTC_BASE_TEST(AddRemoveRecvStreams);
 
-TEST_F(WebRtcVideoChannel2BaseTest, GetStatsMultipleSendStreams) {
-  Base::GetStatsMultipleSendStreams();
-}
+WEBRTC_DISABLED_BASE_TEST(AddRemoveRecvStreamAndRender);
 
-TEST_F(WebRtcVideoChannel2BaseTest, SetSendBandwidth) {
-  Base::SetSendBandwidth();
-}
-TEST_F(WebRtcVideoChannel2BaseTest, SetSendSsrc) { Base::SetSendSsrc(); }
-TEST_F(WebRtcVideoChannel2BaseTest, SetSendSsrcAfterSetCodecs) {
-  Base::SetSendSsrcAfterSetCodecs();
-}
+WEBRTC_BASE_TEST(AddRemoveRecvStreamsNoConference);
 
-TEST_F(WebRtcVideoChannel2BaseTest, SetRenderer) { Base::SetRenderer(); }
+WEBRTC_BASE_TEST(AddRemoveSendStreams);
 
-TEST_F(WebRtcVideoChannel2BaseTest, AddRemoveRecvStreams) {
-  Base::AddRemoveRecvStreams();
-}
+WEBRTC_BASE_TEST(SimulateConference);
 
-TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_AddRemoveRecvStreamAndRender) {
-  Base::AddRemoveRecvStreamAndRender();
-}
+WEBRTC_BASE_TEST(AddRemoveCapturer);
 
-TEST_F(WebRtcVideoChannel2BaseTest, AddRemoveRecvStreamsNoConference) {
-  Base::AddRemoveRecvStreamsNoConference();
-}
+WEBRTC_BASE_TEST(RemoveCapturerWithoutAdd);
 
-TEST_F(WebRtcVideoChannel2BaseTest, AddRemoveSendStreams) {
-  Base::AddRemoveSendStreams();
-}
-
-TEST_F(WebRtcVideoChannel2BaseTest, SimulateConference) {
-  Base::SimulateConference();
-}
-
-TEST_F(WebRtcVideoChannel2BaseTest, AddRemoveCapturer) {
-  Base::AddRemoveCapturer();
-}
-
-TEST_F(WebRtcVideoChannel2BaseTest, RemoveCapturerWithoutAdd) {
-  Base::RemoveCapturerWithoutAdd();
-}
-
-TEST_F(WebRtcVideoChannel2BaseTest, AddRemoveCapturerMultipleSources) {
-  Base::AddRemoveCapturerMultipleSources();
-}
+WEBRTC_BASE_TEST(AddRemoveCapturerMultipleSources);
 
 // TODO(pbos): Figure out why this fails so often.
-TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_HighAspectHighHeightCapturer) {
-  Base::HighAspectHighHeightCapturer();
-}
+WEBRTC_DISABLED_BASE_TEST(HighAspectHighHeightCapturer);
 
-TEST_F(WebRtcVideoChannel2BaseTest, RejectEmptyStreamParams) {
-  Base::RejectEmptyStreamParams();
-}
+WEBRTC_BASE_TEST(RejectEmptyStreamParams);
 
-TEST_F(WebRtcVideoChannel2BaseTest, AdaptResolution16x10) {
-  Base::AdaptResolution16x10();
-}
+WEBRTC_BASE_TEST(AdaptResolution16x10);
 
-TEST_F(WebRtcVideoChannel2BaseTest, AdaptResolution4x3) {
-  Base::AdaptResolution4x3();
-}
+WEBRTC_BASE_TEST(AdaptResolution4x3);
 
-TEST_F(WebRtcVideoChannel2BaseTest, MuteStream) { Base::MuteStream(); }
+WEBRTC_BASE_TEST(MuteStream);
 
-TEST_F(WebRtcVideoChannel2BaseTest, MultipleSendStreams) {
-  Base::MultipleSendStreams();
-}
+WEBRTC_BASE_TEST(MultipleSendStreams);
 
 // TODO(juberti): Restore this test once we support sending 0 fps.
-TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_AdaptDropAllFrames) {
-  Base::AdaptDropAllFrames();
-}
+WEBRTC_DISABLED_BASE_TEST(AdaptDropAllFrames);
 // TODO(juberti): Understand why we get decode errors on this test.
-TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_AdaptFramerate) {
-  Base::AdaptFramerate();
-}
+WEBRTC_DISABLED_BASE_TEST(AdaptFramerate);
 
-TEST_F(WebRtcVideoChannel2BaseTest, SetSendStreamFormat0x0) {
-  Base::SetSendStreamFormat0x0();
-}
+WEBRTC_BASE_TEST(SetSendStreamFormat0x0);
 
 // TODO(zhurunz): Fix the flakey test.
-TEST_F(WebRtcVideoChannel2BaseTest, DISABLED_SetSendStreamFormat) {
-  Base::SetSendStreamFormat();
-}
+WEBRTC_DISABLED_BASE_TEST(SetSendStreamFormat);
 
 TEST_F(WebRtcVideoChannel2BaseTest, TwoStreamsSendAndReceive) {
   Base::TwoStreamsSendAndReceive(kVp8Codec);