Refactor webrtcvideoengines to have the default list of supported codecs being generated in runtime.
This will allow to plugin VP9 based on a field trial.

R=pbos@webrtc.org, pbos, pthatcher

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@7658 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/media/webrtc/constants.h b/talk/media/webrtc/constants.h
index 5390c0d..821a41f 100755
--- a/talk/media/webrtc/constants.h
+++ b/talk/media/webrtc/constants.h
@@ -35,7 +35,9 @@
 extern const char kVp8CodecName[];
 extern const char kH264CodecName[];
 
-extern const int kDefaultFramerate;
+extern const int kDefaultVideoMaxWidth;
+extern const int kDefaultVideoMaxHeight;
+extern const int kDefaultVideoMaxFramerate;
 extern const int kMinVideoBitrate;
 extern const int kStartVideoBitrate;
 extern const int kMaxVideoBitrate;
diff --git a/talk/media/webrtc/webrtcvideoengine.cc b/talk/media/webrtc/webrtcvideoengine.cc
index 6dacadd..46d316f 100644
--- a/talk/media/webrtc/webrtcvideoengine.cc
+++ b/talk/media/webrtc/webrtcvideoengine.cc
@@ -55,6 +55,7 @@
 #include "webrtc/base/basictypes.h"
 #include "webrtc/base/buffer.h"
 #include "webrtc/base/byteorder.h"
+#include "webrtc/base/checks.h"
 #include "webrtc/base/common.h"
 #include "webrtc/base/cpumonitor.h"
 #include "webrtc/base/logging.h"
@@ -106,7 +107,10 @@
 
 const char kVp8CodecName[] = "VP8";
 
-const int kDefaultFramerate = 30;
+// TODO(ronghuawu): Change to 640x360.
+const int kDefaultVideoMaxWidth = 640;
+const int kDefaultVideoMaxHeight = 400;
+const int kDefaultVideoMaxFramerate = 30;
 const int kMinVideoBitrate = 30;
 const int kStartVideoBitrate = 300;
 const int kMaxVideoBitrate = 2000;
@@ -176,15 +180,57 @@
 static const rtc::DiffServCodePoint kVideoDscpValue =
     rtc::DSCP_AF41;
 
-static bool IsNackEnabled(const VideoCodec& codec) {
-  return codec.HasFeedbackParam(FeedbackParam(kRtcpFbParamNack,
-                                              kParamValueEmpty));
+bool IsNackEnabled(const VideoCodec& codec) {
+  return codec.HasFeedbackParam(
+      FeedbackParam(kRtcpFbParamNack, kParamValueEmpty));
 }
 
-// Returns true if Receiver Estimated Max Bitrate is enabled.
-static bool IsRembEnabled(const VideoCodec& codec) {
-  return codec.HasFeedbackParam(FeedbackParam(kRtcpFbParamRemb,
-                                              kParamValueEmpty));
+bool IsRembEnabled(const VideoCodec& codec) {
+  return codec.HasFeedbackParam(
+      FeedbackParam(kRtcpFbParamRemb, kParamValueEmpty));
+}
+
+void AddDefaultFeedbackParams(VideoCodec* codec) {
+  codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamCcm, kRtcpFbCcmParamFir));
+  codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamNack, kParamValueEmpty));
+  codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamNack, kRtcpFbNackParamPli));
+  codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamRemb, kParamValueEmpty));
+}
+
+bool CodecNameMatches(const std::string& name1, const std::string& name2) {
+  return _stricmp(name1.c_str(), name2.c_str()) == 0;
+}
+
+static VideoCodec MakeVideoCodecWithDefaultFeedbackParams(int payload_type,
+                                                          const char* name) {
+  VideoCodec codec(payload_type, name, kDefaultVideoMaxWidth,
+                   kDefaultVideoMaxHeight, kDefaultVideoMaxFramerate, 0);
+  AddDefaultFeedbackParams(&codec);
+  return codec;
+}
+
+static VideoCodec MakeVideoCodec(int payload_type, const char* name) {
+  return VideoCodec(payload_type, name, 0, 0, 0, 0);
+}
+
+static VideoCodec MakeRtxCodec(int payload_type, int associated_payload_type) {
+  return VideoCodec::CreateRtxCodec(payload_type, associated_payload_type);
+}
+
+bool CodecIsInternallySupported(const std::string& codec_name) {
+  if (CodecNameMatches(codec_name, kVp8CodecName)) {
+    return true;
+  }
+  return false;
+}
+
+std::vector<VideoCodec> DefaultVideoCodecList() {
+  std::vector<VideoCodec> codecs;
+  codecs.push_back(MakeVideoCodecWithDefaultFeedbackParams(100, kVp8CodecName));
+  codecs.push_back(MakeRtxCodec(96, 100));
+  codecs.push_back(MakeVideoCodec(116, kRedCodecName));
+  codecs.push_back(MakeVideoCodec(117, kUlpfecCodecName));
+  return codecs;
 }
 
 struct FlushBlackFrameData : public rtc::MessageData {
@@ -923,18 +969,6 @@
   AdaptFormatType adapt_format_type_;
 };
 
-const WebRtcVideoEngine::VideoCodecPref
-    WebRtcVideoEngine::kVideoCodecPrefs[] = {
-    {kVp8CodecName, 100, -1, 0},
-    {kRedCodecName, 116, -1, 1},
-    {kUlpfecCodecName, 117, -1, 2},
-    {kRtxCodecName, 96, 100, 3},
-};
-
-const VideoFormatPod WebRtcVideoEngine::kDefaultMaxVideoFormat =
-  {640, 400, FPS_TO_INTERVAL(30), FOURCC_ANY};
-// TODO(ronghuawu): Change to 640x360.
-
 static bool GetCpuOveruseOptions(const VideoOptions& options,
                                  webrtc::CpuOveruseOptions* overuse_options) {
   int underuse_threshold = 0;
@@ -1018,20 +1052,14 @@
     LOG_RTCERR1(SetTraceCallback, this);
   }
 
+  default_video_codec_list_ = DefaultVideoCodecList();
+
   // Set default quality levels for our supported codecs. We override them here
   // if we know your cpu performance is low, and they can be updated explicitly
   // by calling SetDefaultCodec.  For example by a flute preference setting, or
   // by the server with a jec in response to our reported system info.
-  VideoCodec max_codec(kVideoCodecPrefs[0].payload_type,
-                       kVideoCodecPrefs[0].name,
-                       kDefaultMaxVideoFormat.width,
-                       kDefaultMaxVideoFormat.height,
-                       VideoFormat::IntervalToFps(
-                           kDefaultMaxVideoFormat.interval),
-                       0);
-  if (!SetDefaultCodec(max_codec)) {
-    LOG(LS_ERROR) << "Failed to initialize list of supported codec types";
-  }
+  CHECK(SetDefaultCodec(default_video_codec_list_.front()))
+      << "Failed to initialize list of supported codec types.";
 
   // Consider jitter, packet loss, etc when rendering.  This will
   // theoretically make rendering more smooth.
@@ -1214,13 +1242,12 @@
         return true;
     }
   }
-  for (size_t j = 0; j < ARRAY_SIZE(kVideoCodecPrefs); ++j) {
-    VideoCodec codec(kVideoCodecPrefs[j].payload_type,
-                     kVideoCodecPrefs[j].name, 0, 0, 0, 0);
-    if (codec.Matches(in)) {
+  for (size_t j = 0; j != default_video_codec_list_.size(); ++j) {
+    if (default_video_codec_list_[j].Matches(in)) {
       return true;
     }
   }
+
   return false;
 }
 
@@ -1428,17 +1455,6 @@
   }
 }
 
-static void AddDefaultFeedbackParams(VideoCodec* codec) {
-  const FeedbackParam kFir(kRtcpFbParamCcm, kRtcpFbCcmParamFir);
-  codec->AddFeedbackParam(kFir);
-  const FeedbackParam kNack(kRtcpFbParamNack, kParamValueEmpty);
-  codec->AddFeedbackParam(kNack);
-  const FeedbackParam kPli(kRtcpFbParamNack, kRtcpFbNackParamPli);
-  codec->AddFeedbackParam(kPli);
-  const FeedbackParam kRemb(kRtcpFbParamRemb, kParamValueEmpty);
-  codec->AddFeedbackParam(kRemb);
-}
-
 // Rebuilds the codec list to be only those that are less intensive
 // than the specified codec. Prefers internal codec over external with
 // higher preference field.
@@ -1448,27 +1464,17 @@
 
   video_codecs_.clear();
 
-  bool found = false;
   std::set<std::string> internal_codec_names;
-  for (size_t i = 0; i < ARRAY_SIZE(kVideoCodecPrefs); ++i) {
-    const VideoCodecPref& pref(kVideoCodecPrefs[i]);
-    if (!found)
-      found = (in_codec.name == pref.name);
-    if (found) {
-      VideoCodec codec(pref.payload_type, pref.name,
-                       in_codec.width, in_codec.height, in_codec.framerate,
-                       static_cast<int>(ARRAY_SIZE(kVideoCodecPrefs) - i));
-      if (_stricmp(kVp8CodecName, codec.name.c_str()) == 0) {
-        AddDefaultFeedbackParams(&codec);
-      }
-      if (pref.associated_payload_type != -1) {
-        codec.SetParam(kCodecParamAssociatedPayloadType,
-                       pref.associated_payload_type);
-      }
-      video_codecs_.push_back(codec);
-      internal_codec_names.insert(codec.name);
-    }
+  for (size_t i = 0; i != default_video_codec_list_.size(); ++i) {
+    VideoCodec codec = default_video_codec_list_[i];
+    codec.width = in_codec.width;
+    codec.height = in_codec.height;
+    codec.framerate = in_codec.framerate;
+    video_codecs_.push_back(codec);
+
+    internal_codec_names.insert(codec.name);
   }
+
   if (encoder_factory_) {
     const std::vector<WebRtcVideoEncoderFactory::VideoCodec>& codecs =
         encoder_factory_->codecs();
@@ -1476,8 +1482,6 @@
       bool is_internal_codec = internal_codec_names.find(codecs[i].name) !=
           internal_codec_names.end();
       if (!is_internal_codec) {
-        if (!found)
-          found = (in_codec.name == codecs[i].name);
         VideoCodec codec(
             GetExternalVideoPayloadType(static_cast<int>(i)),
             codecs[i].name,
@@ -1492,7 +1496,6 @@
       }
     }
   }
-  ASSERT(found);
   return true;
 }
 
@@ -1598,12 +1601,10 @@
   encoder_factory_ = encoder_factory;
 
   // Rebuild codec list while reapplying the current default codec format.
-  VideoCodec max_codec(kVideoCodecPrefs[0].payload_type,
-                       kVideoCodecPrefs[0].name,
-                       video_codecs_[0].width,
-                       video_codecs_[0].height,
-                       video_codecs_[0].framerate,
-                       0);
+  VideoCodec max_codec = default_video_codec_list_[0];
+  max_codec.width = video_codecs_[0].width;
+  max_codec.height = video_codecs_[0].height;
+  max_codec.framerate = video_codecs_[0].framerate;
   if (!RebuildCodecList(max_codec)) {
     LOG(LS_ERROR) << "Failed to initialize list of supported codec types";
   }
diff --git a/talk/media/webrtc/webrtcvideoengine.h b/talk/media/webrtc/webrtcvideoengine.h
index d577b4b..db091af 100644
--- a/talk/media/webrtc/webrtcvideoengine.h
+++ b/talk/media/webrtc/webrtcvideoengine.h
@@ -85,6 +85,15 @@
 struct CapturedFrame;
 struct Device;
 
+// This set of methods is declared here for the sole purpose of sharing code
+// between webrtc video engine v1 and v2.
+std::vector<VideoCodec> DefaultVideoCodecList();
+bool CodecNameMatches(const std::string& name1, const std::string& name2);
+bool CodecIsInternallySupported(const std::string& codec_name);
+bool IsNackEnabled(const VideoCodec& codec);
+bool IsRembEnabled(const VideoCodec& codec);
+void AddDefaultFeedbackParams(VideoCodec* codec);
+
 class WebRtcVideoEngine : public sigslot::has_slots<>,
                           public webrtc::TraceCallback {
  public:
@@ -187,18 +196,6 @@
 
  private:
   typedef std::vector<WebRtcVideoMediaChannel*> VideoChannels;
-  struct VideoCodecPref {
-    const char* name;
-    int payload_type;
-    // For RTX, this field is the payload-type that RTX applies to.
-    // For other codecs, it should be set to -1.
-    int associated_payload_type;
-    int pref;
-  };
-
-  static const VideoCodecPref kVideoCodecPrefs[];
-  static const VideoFormatPod kVideoFormats[];
-  static const VideoFormatPod kDefaultMaxVideoFormat;
 
   void Construct(ViEWrapper* vie_wrapper,
                  ViETraceWrapper* tracing,
@@ -225,6 +222,7 @@
   WebRtcVideoEncoderFactory* encoder_factory_;
   WebRtcVideoDecoderFactory* decoder_factory_;
   std::vector<VideoCodec> video_codecs_;
+  std::vector<VideoCodec> default_video_codec_list_;
   std::vector<RtpHeaderExtension> rtp_header_extensions_;
   VideoFormat default_codec_format_;
 
diff --git a/talk/media/webrtc/webrtcvideoengine2.cc b/talk/media/webrtc/webrtcvideoengine2.cc
index a641a58..8d53f17 100644
--- a/talk/media/webrtc/webrtcvideoengine2.cc
+++ b/talk/media/webrtc/webrtcvideoengine2.cc
@@ -36,6 +36,7 @@
 #include "talk/media/base/videorenderer.h"
 #include "talk/media/webrtc/constants.h"
 #include "talk/media/webrtc/webrtcvideocapturer.h"
+#include "talk/media/webrtc/webrtcvideoengine.h"
 #include "talk/media/webrtc/webrtcvideoframe.h"
 #include "talk/media/webrtc/webrtcvoiceengine.h"
 #include "webrtc/base/buffer.h"
@@ -51,26 +52,6 @@
 
 namespace cricket {
 namespace {
-
-static bool CodecNameMatches(const std::string& name1,
-                             const std::string& name2) {
-  return _stricmp(name1.c_str(), name2.c_str()) == 0;
-}
-
-const char* kInternallySupportedCodecs[] = {
-    kVp8CodecName,
-};
-
-// True if codec is supported by a software implementation that's always
-// available.
-static bool CodecIsInternallySupported(const std::string& codec_name) {
-  for (size_t i = 0; i < ARRAY_SIZE(kInternallySupportedCodecs); ++i) {
-    if (CodecNameMatches(codec_name, kInternallySupportedCodecs[i]))
-      return true;
-  }
-  return false;
-}
-
 static std::string CodecVectorToString(const std::vector<VideoCodec>& codecs) {
   std::stringstream out;
   out << '{';
@@ -116,6 +97,29 @@
   return out.str();
 }
 
+// Merges two fec configs and logs an error if a conflict arises
+// such that merging in diferent order would trigger a diferent output.
+static void MergeFecConfig(const webrtc::FecConfig& other,
+                           webrtc::FecConfig* output) {
+  if (other.ulpfec_payload_type != -1) {
+    if (output->ulpfec_payload_type != -1 &&
+        output->ulpfec_payload_type != other.ulpfec_payload_type) {
+      LOG(LS_WARNING) << "Conflict merging ulpfec_payload_type configs: "
+                      << output->ulpfec_payload_type << " and "
+                      << other.ulpfec_payload_type;
+    }
+    output->ulpfec_payload_type = other.ulpfec_payload_type;
+  }
+  if (other.red_payload_type != -1) {
+    if (output->red_payload_type != -1 &&
+        output->red_payload_type != other.red_payload_type) {
+      LOG(LS_WARNING) << "Conflict merging red_payload_type configs: "
+                      << output->red_payload_type << " and "
+                      << other.red_payload_type;
+    }
+    output->red_payload_type = other.red_payload_type;
+  }
+}
 }  // namespace
 
 // This constant is really an on/off, lower-level configurable NACK history
@@ -135,19 +139,8 @@
 static const size_t kMaxExternalVideoCodecs = 8;
 #endif
 
-struct VideoCodecPref {
-  int payload_type;
-  int width;
-  int height;
-  const char* name;
-  int rtx_payload_type;
-} kDefaultVideoCodecPref = {100, 640, 400, kVp8CodecName, 96};
-
 const char kH264CodecName[] = "H264";
 
-VideoCodecPref kRedPref = {116, -1, -1, kRedCodecName, -1};
-VideoCodecPref kUlpfecPref = {117, -1, -1, kUlpfecCodecName, -1};
-
 static bool FindFirstMatchingCodec(const std::vector<VideoCodec>& codecs,
                                    const VideoCodec& requested_codec,
                                    VideoCodec* matching_codec) {
@@ -160,59 +153,6 @@
   return false;
 }
 
-static void AddDefaultFeedbackParams(VideoCodec* codec) {
-  const FeedbackParam kFir(kRtcpFbParamCcm, kRtcpFbCcmParamFir);
-  codec->AddFeedbackParam(kFir);
-  const FeedbackParam kNack(kRtcpFbParamNack, kParamValueEmpty);
-  codec->AddFeedbackParam(kNack);
-  const FeedbackParam kPli(kRtcpFbParamNack, kRtcpFbNackParamPli);
-  codec->AddFeedbackParam(kPli);
-  const FeedbackParam kRemb(kRtcpFbParamRemb, kParamValueEmpty);
-  codec->AddFeedbackParam(kRemb);
-}
-
-static bool IsNackEnabled(const VideoCodec& codec) {
-  return codec.HasFeedbackParam(
-      FeedbackParam(kRtcpFbParamNack, kParamValueEmpty));
-}
-
-static bool IsRembEnabled(const VideoCodec& codec) {
-  return codec.HasFeedbackParam(
-      FeedbackParam(kRtcpFbParamRemb, kParamValueEmpty));
-}
-
-static VideoCodec DefaultVideoCodec() {
-  VideoCodec default_codec(kDefaultVideoCodecPref.payload_type,
-                           kDefaultVideoCodecPref.name,
-                           kDefaultVideoCodecPref.width,
-                           kDefaultVideoCodecPref.height,
-                           kDefaultFramerate,
-                           0);
-  AddDefaultFeedbackParams(&default_codec);
-  return default_codec;
-}
-
-static VideoCodec DefaultRedCodec() {
-  return VideoCodec(kRedPref.payload_type, kRedPref.name, 0, 0, 0, 0);
-}
-
-static VideoCodec DefaultUlpfecCodec() {
-  return VideoCodec(kUlpfecPref.payload_type, kUlpfecPref.name, 0, 0, 0, 0);
-}
-
-static std::vector<VideoCodec> DefaultVideoCodecs() {
-  std::vector<VideoCodec> codecs;
-  codecs.push_back(DefaultVideoCodec());
-  codecs.push_back(DefaultRedCodec());
-  codecs.push_back(DefaultUlpfecCodec());
-  if (kDefaultVideoCodecPref.rtx_payload_type != -1) {
-    codecs.push_back(
-        VideoCodec::CreateRtxCodec(kDefaultVideoCodecPref.rtx_payload_type,
-                                   kDefaultVideoCodecPref.payload_type));
-  }
-  return codecs;
-}
-
 static bool ValidateRtpHeaderExtensionIds(
     const std::vector<RtpHeaderExtension>& extensions) {
   std::set<int> extensions_used;
@@ -258,7 +198,7 @@
   stream.width = codec.width;
   stream.height = codec.height;
   stream.max_framerate =
-      codec.framerate != 0 ? codec.framerate : kDefaultFramerate;
+      codec.framerate != 0 ? codec.framerate : kDefaultVideoMaxFramerate;
 
   int min_bitrate = kMinVideoBitrate;
   codec.GetParam(kCodecParamMinBitrate, &min_bitrate);
@@ -350,9 +290,9 @@
 WebRtcVideoEngine2::WebRtcVideoEngine2()
     : worker_thread_(NULL),
       voice_engine_(NULL),
-      default_codec_format_(kDefaultVideoCodecPref.width,
-                            kDefaultVideoCodecPref.height,
-                            FPS_TO_INTERVAL(kDefaultFramerate),
+      default_codec_format_(kDefaultVideoMaxWidth,
+                            kDefaultVideoMaxHeight,
+                            FPS_TO_INTERVAL(kDefaultVideoMaxFramerate),
                             FOURCC_ANY),
       initialized_(false),
       cpu_monitor_(new rtc::CpuMonitor(NULL)),
@@ -571,7 +511,7 @@
 }
 
 std::vector<VideoCodec> WebRtcVideoEngine2::GetSupportedCodecs() const {
-  std::vector<VideoCodec> supported_codecs = DefaultVideoCodecs();
+  std::vector<VideoCodec> supported_codecs = DefaultVideoCodecList();
 
   if (external_encoder_factory_ == NULL) {
     return supported_codecs;
@@ -1097,19 +1037,19 @@
   }
 
   for (size_t i = 0; i < recv_codecs_.size(); ++i) {
-    if (recv_codecs_[i].codec.id == kDefaultVideoCodecPref.payload_type) {
-      config->rtp.fec = recv_codecs_[i].fec;
-      uint32 rtx_ssrc;
-      if (recv_codecs_[i].rtx_payload_type != -1 &&
-          sp.GetFidSsrc(ssrc, &rtx_ssrc)) {
-        config->rtp.rtx[kDefaultVideoCodecPref.payload_type].ssrc = rtx_ssrc;
-        config->rtp.rtx[kDefaultVideoCodecPref.payload_type].payload_type =
-            recv_codecs_[i].rtx_payload_type;
-      }
-      break;
-    }
+    MergeFecConfig(recv_codecs_[i].fec, &config->rtp.fec);
   }
 
+  for (size_t i = 0; i < recv_codecs_.size(); ++i) {
+    uint32 rtx_ssrc;
+    if (recv_codecs_[i].rtx_payload_type != -1 &&
+        sp.GetFidSsrc(ssrc, &rtx_ssrc)) {
+      webrtc::VideoReceiveStream::Config::Rtp::Rtx& rtx =
+          config->rtp.rtx[recv_codecs_[i].codec.id];
+      rtx.ssrc = rtx_ssrc;
+      rtx.payload_type = recv_codecs_[i].rtx_payload_type;
+    }
+  }
 }
 
 bool WebRtcVideoChannel2::RemoveRecvStream(uint32 ssrc) {