Add optional stereo codec to SDP negotiation

- Defines stereo codec case, similar to RTX, that adds stereo codec to the SDP
negotiation. The underlying codec's payload type is similarly defined by "apt".
- If this negotiation is successful, codec name is included in sdp line via
"acn".
- Adds codec setting initializers for these specific stereo cases.
- Introduces new Stereo*Factory classes as optional convenience wrappers that
inserts stereo codec to the existing set of supported codecs on demand.

This CL is the step 5 for adding alpha channel support over the wire in webrtc.
Design Doc: https://goo.gl/sFeSUT

Bug: webrtc:7671
Change-Id: Ie12c56c8fcf7934e216135d73af33adec5248f76
Reviewed-on: https://webrtc-review.googlesource.com/22901
Commit-Queue: Niklas Enbom <niklas.enbom@webrtc.org>
Reviewed-by: Niklas Enbom <niklas.enbom@webrtc.org>
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#21210}
diff --git a/common_types.cc b/common_types.cc
index 0526d59..f1b2f1e 100644
--- a/common_types.cc
+++ b/common_types.cc
@@ -137,6 +137,7 @@
 static const char* kPayloadNameRED = "RED";
 static const char* kPayloadNameULPFEC = "ULPFEC";
 static const char* kPayloadNameGeneric = "Generic";
+static const char* kPayloadNameStereo = "Stereo";
 
 static bool CodecNamesEq(const char* name1, const char* name2) {
   return _stricmp(name1, name2) == 0;
@@ -156,10 +157,14 @@
       return kPayloadNameRED;
     case kVideoCodecULPFEC:
       return kPayloadNameULPFEC;
-    default:
-      // Unrecognized codecs default to generic.
+    // Other codecs default to generic.
+    case kVideoCodecStereo:
+    case kVideoCodecFlexfec:
+    case kVideoCodecGeneric:
+    case kVideoCodecUnknown:
       return kPayloadNameGeneric;
   }
+  return kPayloadNameGeneric;
 }
 
 VideoCodecType PayloadStringToCodecType(const std::string& name) {
@@ -175,6 +180,8 @@
     return kVideoCodecRED;
   if (CodecNamesEq(name.c_str(), kPayloadNameULPFEC))
     return kVideoCodecULPFEC;
+  if (CodecNamesEq(name.c_str(), kPayloadNameStereo))
+    return kVideoCodecStereo;
   return kVideoCodecGeneric;
 }
 
diff --git a/media/BUILD.gn b/media/BUILD.gn
index 754a89a..9911ce2 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -157,6 +157,8 @@
     "engine/simulcast.h",
     "engine/simulcast_encoder_adapter.cc",
     "engine/simulcast_encoder_adapter.h",
+    "engine/stereocodecfactory.cc",
+    "engine/stereocodecfactory.h",
     "engine/videodecodersoftwarefallbackwrapper.cc",
     "engine/videodecodersoftwarefallbackwrapper.h",
     "engine/videoencodersoftwarefallbackwrapper.cc",
@@ -243,6 +245,7 @@
     "../modules/video_capture:video_capture_module",
     "../modules/video_coding",
     "../modules/video_coding:webrtc_h264",
+    "../modules/video_coding:webrtc_stereo",
     "../modules/video_coding:webrtc_vp8",
     "../modules/video_coding:webrtc_vp9",
     "../p2p:rtc_p2p",
@@ -450,6 +453,7 @@
       "engine/payload_type_mapper_unittest.cc",
       "engine/simulcast_encoder_adapter_unittest.cc",
       "engine/simulcast_unittest.cc",
+      "engine/stereocodecfactory_unittest.cc",
       "engine/videodecodersoftwarefallbackwrapper_unittest.cc",
       "engine/videoencodersoftwarefallbackwrapper_unittest.cc",
       "engine/vp8_encoder_simulcast_proxy_unittest.cc",
diff --git a/media/base/mediaconstants.cc b/media/base/mediaconstants.cc
index 06c172c..9496d9f 100644
--- a/media/base/mediaconstants.cc
+++ b/media/base/mediaconstants.cc
@@ -25,6 +25,7 @@
 const char kRtxCodecName[] = "rtx";
 const char kRedCodecName[] = "red";
 const char kUlpfecCodecName[] = "ulpfec";
+const char kStereoCodecName[] = "stereo";
 
 // TODO(brandtr): Change this to 'flexfec' when we are confident that the
 // header format is not changing anymore.
@@ -34,6 +35,7 @@
 const char kFlexfecFmtpRepairWindow[] = "repair-window";
 
 const char kCodecParamAssociatedPayloadType[] = "apt";
+const char kCodecParamAssociatedCodecName[] = "acn";
 
 const char kOpusCodecName[] = "opus";
 const char kIsacCodecName[] = "ISAC";
diff --git a/media/base/mediaconstants.h b/media/base/mediaconstants.h
index 106fad0..58a66d9 100644
--- a/media/base/mediaconstants.h
+++ b/media/base/mediaconstants.h
@@ -30,11 +30,13 @@
 extern const char kRedCodecName[];
 extern const char kUlpfecCodecName[];
 extern const char kFlexfecCodecName[];
+extern const char kStereoCodecName[];
 
 extern const char kFlexfecFmtpRepairWindow[];
 
 // Codec parameters
 extern const char kCodecParamAssociatedPayloadType[];
+extern const char kCodecParamAssociatedCodecName[];
 
 extern const char kOpusCodecName[];
 extern const char kIsacCodecName[];
diff --git a/media/engine/stereocodecfactory.cc b/media/engine/stereocodecfactory.cc
new file mode 100644
index 0000000..5ffb0c4
--- /dev/null
+++ b/media/engine/stereocodecfactory.cc
@@ -0,0 +1,111 @@
+/*
+ *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "media/engine/stereocodecfactory.h"
+
+#include <utility>
+
+#include "api/video_codecs/sdp_video_format.h"
+#include "media/base/codec.h"
+#include "media/base/mediaconstants.h"
+#include "modules/video_coding/codecs/stereo/include/stereo_decoder_adapter.h"
+#include "modules/video_coding/codecs/stereo/include/stereo_encoder_adapter.h"
+#include "rtc_base/logging.h"
+
+namespace {
+
+bool IsStereoCodec(const cricket::VideoCodec& codec) {
+  return cricket::CodecNamesEq(codec.name.c_str(), cricket::kStereoCodecName);
+}
+
+}  // anonymous namespace
+
+namespace webrtc {
+
+constexpr const char* kStereoAssociatedCodecName = cricket::kVp9CodecName;
+
+StereoEncoderFactory::StereoEncoderFactory(
+    std::unique_ptr<VideoEncoderFactory> factory)
+    : factory_(std::move(factory)) {}
+
+std::vector<SdpVideoFormat> StereoEncoderFactory::GetSupportedFormats() const {
+  std::vector<SdpVideoFormat> formats = factory_->GetSupportedFormats();
+  for (const auto& format : formats) {
+    if (cricket::CodecNamesEq(format.name, kStereoAssociatedCodecName)) {
+      SdpVideoFormat stereo_format = format;
+      stereo_format.parameters[cricket::kCodecParamAssociatedCodecName] =
+          format.name;
+      stereo_format.name = cricket::kStereoCodecName;
+      formats.push_back(stereo_format);
+      break;
+    }
+  }
+  return formats;
+}
+
+VideoEncoderFactory::CodecInfo StereoEncoderFactory::QueryVideoEncoder(
+    const SdpVideoFormat& format) const {
+  if (!IsStereoCodec(cricket::VideoCodec(format)))
+    return factory_->QueryVideoEncoder(format);
+  return factory_->QueryVideoEncoder(
+      SdpVideoFormat(kStereoAssociatedCodecName));
+}
+
+std::unique_ptr<VideoEncoder> StereoEncoderFactory::CreateVideoEncoder(
+    const SdpVideoFormat& format) {
+  if (!IsStereoCodec(cricket::VideoCodec(format)))
+    return factory_->CreateVideoEncoder(format);
+  const auto& it =
+      format.parameters.find(cricket::kCodecParamAssociatedCodecName);
+  if (it == format.parameters.end()) {
+    RTC_LOG(LS_ERROR) << "No assicated codec for stereo.";
+    return nullptr;
+  }
+  SdpVideoFormat associated_format = format;
+  associated_format.name = it->second;
+  return std::unique_ptr<VideoEncoder>(
+      new StereoEncoderAdapter(factory_.get(), associated_format));
+}
+
+StereoDecoderFactory::StereoDecoderFactory(
+    std::unique_ptr<VideoDecoderFactory> factory)
+    : factory_(std::move(factory)) {}
+
+std::vector<SdpVideoFormat> StereoDecoderFactory::GetSupportedFormats() const {
+  std::vector<SdpVideoFormat> formats = factory_->GetSupportedFormats();
+  for (const auto& format : formats) {
+    if (cricket::CodecNamesEq(format.name, kStereoAssociatedCodecName)) {
+      SdpVideoFormat stereo_format = format;
+      stereo_format.parameters[cricket::kCodecParamAssociatedCodecName] =
+          format.name;
+      stereo_format.name = cricket::kStereoCodecName;
+      formats.push_back(stereo_format);
+    }
+  }
+  return formats;
+}
+
+std::unique_ptr<VideoDecoder> StereoDecoderFactory::CreateVideoDecoder(
+    const SdpVideoFormat& format) {
+  if (!IsStereoCodec(cricket::VideoCodec(format)))
+    return factory_->CreateVideoDecoder(format);
+  const auto& it =
+      format.parameters.find(cricket::kCodecParamAssociatedCodecName);
+  if (it == format.parameters.end()) {
+    RTC_LOG(LS_ERROR) << "No assicated codec for stereo.";
+    return nullptr;
+  }
+  SdpVideoFormat associated_format = format;
+  associated_format.name = it->second;
+  return std::unique_ptr<VideoDecoder>(
+      new StereoDecoderAdapter(factory_.get(), associated_format));
+}
+
+}  // namespace webrtc
diff --git a/media/engine/stereocodecfactory.h b/media/engine/stereocodecfactory.h
new file mode 100644
index 0000000..468d2fa
--- /dev/null
+++ b/media/engine/stereocodecfactory.h
@@ -0,0 +1,49 @@
+/*
+ *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef MEDIA_ENGINE_STEREOCODECFACTORY_H_
+#define MEDIA_ENGINE_STEREOCODECFACTORY_H_
+
+#include <memory>
+#include <vector>
+
+#include "api/video_codecs/video_decoder_factory.h"
+#include "api/video_codecs/video_encoder_factory.h"
+
+namespace webrtc {
+
+class StereoEncoderFactory : public VideoEncoderFactory {
+ public:
+  explicit StereoEncoderFactory(std::unique_ptr<VideoEncoderFactory> factory);
+
+  std::vector<SdpVideoFormat> GetSupportedFormats() const override;
+  CodecInfo QueryVideoEncoder(const SdpVideoFormat& format) const override;
+  std::unique_ptr<VideoEncoder> CreateVideoEncoder(
+      const SdpVideoFormat& format) override;
+
+ private:
+  std::unique_ptr<VideoEncoderFactory> factory_;
+};
+
+class StereoDecoderFactory : public VideoDecoderFactory {
+ public:
+  explicit StereoDecoderFactory(std::unique_ptr<VideoDecoderFactory> factory);
+
+  std::vector<SdpVideoFormat> GetSupportedFormats() const override;
+  std::unique_ptr<VideoDecoder> CreateVideoDecoder(
+      const SdpVideoFormat& format) override;
+
+ private:
+  std::unique_ptr<VideoDecoderFactory> factory_;
+};
+
+}  // namespace webrtc
+
+#endif  // MEDIA_ENGINE_STEREOCODECFACTORY_H_
diff --git a/media/engine/stereocodecfactory_unittest.cc b/media/engine/stereocodecfactory_unittest.cc
new file mode 100644
index 0000000..a86eff0
--- /dev/null
+++ b/media/engine/stereocodecfactory_unittest.cc
@@ -0,0 +1,47 @@
+/*
+ *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "media/engine/stereocodecfactory.h"
+
+#include <utility>
+
+#include "api/video_codecs/sdp_video_format.h"
+#include "api/video_codecs/video_decoder.h"
+#include "api/video_codecs/video_encoder.h"
+#include "media/base/mediaconstants.h"
+#include "media/engine/internaldecoderfactory.h"
+#include "media/engine/internalencoderfactory.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+TEST(StereoDecoderFactory, CreateVideoDecoder) {
+  std::unique_ptr<VideoDecoderFactory> internal_factory(
+      new InternalDecoderFactory());
+  StereoDecoderFactory factory(std::move(internal_factory));
+  std::unique_ptr<VideoDecoder> decoder =
+      factory.CreateVideoDecoder(SdpVideoFormat(
+          cricket::kStereoCodecName,
+          {{cricket::kCodecParamAssociatedCodecName, cricket::kVp9CodecName}}));
+  EXPECT_TRUE(decoder);
+}
+
+TEST(StereoEncoderFactory, CreateVideoEncoder) {
+  std::unique_ptr<VideoEncoderFactory> internal_factory(
+      new InternalEncoderFactory());
+  StereoEncoderFactory factory(std::move(internal_factory));
+  std::unique_ptr<VideoEncoder> encoder =
+      factory.CreateVideoEncoder(SdpVideoFormat(
+          cricket::kStereoCodecName,
+          {{cricket::kCodecParamAssociatedCodecName, cricket::kVp9CodecName}}));
+  EXPECT_TRUE(encoder);
+}
+
+}  // namespace webrtc
diff --git a/modules/video_coding/codecs/stereo/include/stereo_decoder_adapter.h b/modules/video_coding/codecs/stereo/include/stereo_decoder_adapter.h
index 729517f..c6237ee 100644
--- a/modules/video_coding/codecs/stereo/include/stereo_decoder_adapter.h
+++ b/modules/video_coding/codecs/stereo/include/stereo_decoder_adapter.h
@@ -15,6 +15,7 @@
 #include <memory>
 #include <vector>
 
+#include "api/video_codecs/sdp_video_format.h"
 #include "api/video_codecs/video_decoder.h"
 #include "api/video_codecs/video_decoder_factory.h"
 #include "modules/video_coding/codecs/stereo/include/stereo_encoder_adapter.h"
@@ -24,7 +25,8 @@
 class StereoDecoderAdapter : public VideoDecoder {
  public:
   // |factory| is not owned and expected to outlive this class' lifetime.
-  explicit StereoDecoderAdapter(VideoDecoderFactory* factory);
+  explicit StereoDecoderAdapter(VideoDecoderFactory* factory,
+                                const SdpVideoFormat& associated_format);
   virtual ~StereoDecoderAdapter();
 
   // Implements VideoDecoder
@@ -59,6 +61,7 @@
                         const rtc::Optional<uint8_t>& stereo_qp);
 
   VideoDecoderFactory* const factory_;
+  const SdpVideoFormat associated_format_;
   std::vector<std::unique_ptr<VideoDecoder>> decoders_;
   std::vector<std::unique_ptr<AdapterDecodedImageCallback>> adapter_callbacks_;
   DecodedImageCallback* decoded_complete_callback_;
diff --git a/modules/video_coding/codecs/stereo/include/stereo_encoder_adapter.h b/modules/video_coding/codecs/stereo/include/stereo_encoder_adapter.h
index 74ed1a2..95283f1 100644
--- a/modules/video_coding/codecs/stereo/include/stereo_encoder_adapter.h
+++ b/modules/video_coding/codecs/stereo/include/stereo_encoder_adapter.h
@@ -15,6 +15,7 @@
 #include <memory>
 #include <vector>
 
+#include "api/video_codecs/sdp_video_format.h"
 #include "api/video_codecs/video_encoder.h"
 #include "api/video_codecs/video_encoder_factory.h"
 #include "modules/video_coding/include/video_codec_interface.h"
@@ -30,7 +31,8 @@
 class StereoEncoderAdapter : public VideoEncoder {
  public:
   // |factory| is not owned and expected to outlive this class' lifetime.
-  explicit StereoEncoderAdapter(VideoEncoderFactory* factory);
+  explicit StereoEncoderAdapter(VideoEncoderFactory* factory,
+                                const SdpVideoFormat& associated_format);
   virtual ~StereoEncoderAdapter();
 
   // Implements VideoEncoder
@@ -58,6 +60,7 @@
   class AdapterEncodedImageCallback;
 
   VideoEncoderFactory* const factory_;
+  const SdpVideoFormat associated_format_;
   std::vector<std::unique_ptr<VideoEncoder>> encoders_;
   std::vector<std::unique_ptr<AdapterEncodedImageCallback>> adapter_callbacks_;
   EncodedImageCallback* encoded_complete_callback_;
diff --git a/modules/video_coding/codecs/stereo/stereo_decoder_adapter.cc b/modules/video_coding/codecs/stereo/stereo_decoder_adapter.cc
index caf3299..96d5552 100644
--- a/modules/video_coding/codecs/stereo/stereo_decoder_adapter.cc
+++ b/modules/video_coding/codecs/stereo/stereo_decoder_adapter.cc
@@ -12,7 +12,6 @@
 
 #include "api/video/i420_buffer.h"
 #include "api/video/video_frame_buffer.h"
-#include "api/video_codecs/sdp_video_format.h"
 #include "common_video/include/video_frame.h"
 #include "common_video/include/video_frame_buffer.h"
 #include "common_video/libyuv/include/webrtc_libyuv.h"
@@ -80,8 +79,10 @@
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(DecodedImageData);
 };
 
-StereoDecoderAdapter::StereoDecoderAdapter(VideoDecoderFactory* factory)
-    : factory_(factory) {}
+StereoDecoderAdapter::StereoDecoderAdapter(
+    VideoDecoderFactory* factory,
+    const SdpVideoFormat& associated_format)
+    : factory_(factory), associated_format_(associated_format) {}
 
 StereoDecoderAdapter::~StereoDecoderAdapter() {
   Release();
@@ -89,12 +90,12 @@
 
 int32_t StereoDecoderAdapter::InitDecode(const VideoCodec* codec_settings,
                                          int32_t number_of_cores) {
+  RTC_DCHECK_EQ(kVideoCodecStereo, codec_settings->codecType);
   VideoCodec settings = *codec_settings;
-  settings.codecType = kVideoCodecVP9;
+  settings.codecType = PayloadStringToCodecType(associated_format_.name);
   for (size_t i = 0; i < kAlphaCodecStreams; ++i) {
-    const SdpVideoFormat format("VP9");
     std::unique_ptr<VideoDecoder> decoder =
-        factory_->CreateVideoDecoder(format);
+        factory_->CreateVideoDecoder(associated_format_);
     const int32_t rv = decoder->InitDecode(&settings, number_of_cores);
     if (rv)
       return rv;
diff --git a/modules/video_coding/codecs/stereo/stereo_encoder_adapter.cc b/modules/video_coding/codecs/stereo/stereo_encoder_adapter.cc
index ed7a486..60e3ea8 100644
--- a/modules/video_coding/codecs/stereo/stereo_encoder_adapter.cc
+++ b/modules/video_coding/codecs/stereo/stereo_encoder_adapter.cc
@@ -10,7 +10,6 @@
 
 #include "modules/video_coding/codecs/stereo/include/stereo_encoder_adapter.h"
 
-#include "api/video_codecs/sdp_video_format.h"
 #include "common_video/include/video_frame.h"
 #include "common_video/include/video_frame_buffer.h"
 #include "common_video/libyuv/include/webrtc_libyuv.h"
@@ -58,8 +57,12 @@
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ImageStereoInfo);
 };
 
-StereoEncoderAdapter::StereoEncoderAdapter(VideoEncoderFactory* factory)
-    : factory_(factory), encoded_complete_callback_(nullptr) {}
+StereoEncoderAdapter::StereoEncoderAdapter(
+    VideoEncoderFactory* factory,
+    const SdpVideoFormat& associated_format)
+    : factory_(factory),
+      associated_format_(associated_format),
+      encoded_complete_callback_(nullptr) {}
 
 StereoEncoderAdapter::~StereoEncoderAdapter() {
   Release();
@@ -74,13 +77,16 @@
   // It is more expensive to encode 0x00, so use 0x80 instead.
   std::fill(stereo_dummy_planes_.begin(), stereo_dummy_planes_.end(), 0x80);
 
+  RTC_DCHECK_EQ(kVideoCodecStereo, inst->codecType);
+  VideoCodec settings = *inst;
+  settings.codecType = PayloadStringToCodecType(associated_format_.name);
   for (size_t i = 0; i < kAlphaCodecStreams; ++i) {
-    const SdpVideoFormat format("VP9");
     std::unique_ptr<VideoEncoder> encoder =
-        factory_->CreateVideoEncoder(format);
-    const int rv = encoder->InitEncode(inst, number_of_cores, max_payload_size);
+        factory_->CreateVideoEncoder(associated_format_);
+    const int rv =
+        encoder->InitEncode(&settings, number_of_cores, max_payload_size);
     if (rv) {
-      RTC_LOG(LS_ERROR) << "Failed to create stere codec index " << i;
+      RTC_LOG(LS_ERROR) << "Failed to create stereo codec index " << i;
       return rv;
     }
     adapter_callbacks_.emplace_back(new AdapterEncodedImageCallback(
@@ -180,7 +186,7 @@
     const EncodedImage& encodedImage,
     const CodecSpecificInfo* codecSpecificInfo,
     const RTPFragmentationHeader* fragmentation) {
-  const VideoCodecType associated_coded_type = codecSpecificInfo->codecType;
+  const VideoCodecType associated_codec_type = codecSpecificInfo->codecType;
   const auto& image_stereo_info_itr =
       image_stereo_info_.find(encodedImage._timeStamp);
   RTC_DCHECK(image_stereo_info_itr != image_stereo_info_.end());
@@ -193,7 +199,7 @@
   CodecSpecificInfo codec_info = *codecSpecificInfo;
   codec_info.codecType = kVideoCodecStereo;
   codec_info.codec_name = "stereo";
-  codec_info.codecSpecific.stereo.associated_codec_type = associated_coded_type;
+  codec_info.codecSpecific.stereo.associated_codec_type = associated_codec_type;
   codec_info.codecSpecific.stereo.indices.frame_index = stream_idx;
   codec_info.codecSpecific.stereo.indices.frame_count = frame_count;
   codec_info.codecSpecific.stereo.indices.picture_index = picture_index;
diff --git a/modules/video_coding/codecs/stereo/test/stereo_adapter_unittest.cc b/modules/video_coding/codecs/stereo/test/stereo_adapter_unittest.cc
index 34723c5..976a5bb 100644
--- a/modules/video_coding/codecs/stereo/test/stereo_adapter_unittest.cc
+++ b/modules/video_coding/codecs/stereo/test/stereo_adapter_unittest.cc
@@ -10,8 +10,10 @@
 
 #include "api/test/mock_video_decoder_factory.h"
 #include "api/test/mock_video_encoder_factory.h"
+#include "api/video_codecs/sdp_video_format.h"
 #include "common_video/include/video_frame_buffer.h"
 #include "common_video/libyuv/include/webrtc_libyuv.h"
+#include "media/base/mediaconstants.h"
 #include "modules/video_coding/codecs/stereo/include/stereo_decoder_adapter.h"
 #include "modules/video_coding/codecs/stereo/include/stereo_encoder_adapter.h"
 #include "modules/video_coding/codecs/test/video_codec_test.h"
@@ -24,6 +26,10 @@
 
 namespace webrtc {
 
+constexpr const char* kStereoAssociatedCodecName = cricket::kVp9CodecName;
+const VideoCodecType kStereoAssociatedCodecType =
+    PayloadStringToCodecType(kStereoAssociatedCodecName);
+
 class TestStereoAdapter : public VideoCodecTest {
  public:
   TestStereoAdapter()
@@ -32,18 +38,21 @@
 
  protected:
   std::unique_ptr<VideoDecoder> CreateDecoder() override {
-    return rtc::MakeUnique<StereoDecoderAdapter>(decoder_factory_.get());
+    return rtc::MakeUnique<StereoDecoderAdapter>(
+        decoder_factory_.get(), SdpVideoFormat(kStereoAssociatedCodecName));
   }
 
   std::unique_ptr<VideoEncoder> CreateEncoder() override {
-    return rtc::MakeUnique<StereoEncoderAdapter>(encoder_factory_.get());
+    return rtc::MakeUnique<StereoEncoderAdapter>(
+        encoder_factory_.get(), SdpVideoFormat(kStereoAssociatedCodecName));
   }
 
   VideoCodec codec_settings() override {
     VideoCodec codec_settings;
-    codec_settings.codecType = webrtc::kVideoCodecVP9;
+    codec_settings.codecType = kStereoAssociatedCodecType;
     codec_settings.VP9()->numberOfTemporalLayers = 1;
     codec_settings.VP9()->numberOfSpatialLayers = 1;
+    codec_settings.codecType = webrtc::kVideoCodecStereo;
     return codec_settings;
   }
 
@@ -103,7 +112,7 @@
   ASSERT_TRUE(WaitForEncodedFrame(&encoded_frame, &codec_specific_info));
 
   EXPECT_EQ(kVideoCodecStereo, codec_specific_info.codecType);
-  EXPECT_EQ(kVideoCodecVP9,
+  EXPECT_EQ(kStereoAssociatedCodecType,
             codec_specific_info.codecSpecific.stereo.associated_codec_type);
   EXPECT_EQ(0, codec_specific_info.codecSpecific.stereo.indices.frame_index);
   EXPECT_EQ(1, codec_specific_info.codecSpecific.stereo.indices.frame_count);
@@ -134,7 +143,7 @@
 
   const CodecSpecificInfo& yuv_info = codec_specific_infos[kYUVStream];
   EXPECT_EQ(kVideoCodecStereo, yuv_info.codecType);
-  EXPECT_EQ(kVideoCodecVP9,
+  EXPECT_EQ(kStereoAssociatedCodecType,
             yuv_info.codecSpecific.stereo.associated_codec_type);
   EXPECT_EQ(kYUVStream, yuv_info.codecSpecific.stereo.indices.frame_index);
   EXPECT_EQ(kAlphaCodecStreams,
@@ -143,7 +152,7 @@
 
   const CodecSpecificInfo& axx_info = codec_specific_infos[kAXXStream];
   EXPECT_EQ(kVideoCodecStereo, axx_info.codecType);
-  EXPECT_EQ(kVideoCodecVP9,
+  EXPECT_EQ(kStereoAssociatedCodecType,
             axx_info.codecSpecific.stereo.associated_codec_type);
   EXPECT_EQ(kAXXStream, axx_info.codecSpecific.stereo.indices.frame_index);
   EXPECT_EQ(kAlphaCodecStreams,
diff --git a/modules/video_coding/video_codec_initializer.cc b/modules/video_coding/video_codec_initializer.cc
index 3e1b0e1..c5cd452 100644
--- a/modules/video_coding/video_codec_initializer.cc
+++ b/modules/video_coding/video_codec_initializer.cc
@@ -39,6 +39,20 @@
     bool nack_enabled,
     VideoCodec* codec,
     std::unique_ptr<VideoBitrateAllocator>* bitrate_allocator) {
+  if (PayloadStringToCodecType(settings.payload_name) == kVideoCodecStereo) {
+    VideoSendStream::Config::EncoderSettings associated_codec_settings =
+        settings;
+    associated_codec_settings.payload_name =
+        CodecTypeToPayloadString(kVideoCodecVP9);
+    if (!SetupCodec(config, associated_codec_settings, streams, nack_enabled,
+                    codec, bitrate_allocator)) {
+      RTC_LOG(LS_ERROR) << "Failed to create stereo encoder configuration.";
+      return false;
+    }
+    codec->codecType = kVideoCodecStereo;
+    return true;
+  }
+
   *codec =
       VideoEncoderConfigToVideoCodec(config, streams, settings.payload_name,
                                      settings.payload_type, nack_enabled);
diff --git a/modules/video_coding/video_codec_initializer_unittest.cc b/modules/video_coding/video_codec_initializer_unittest.cc
index 48bf466..0862b72 100644
--- a/modules/video_coding/video_codec_initializer_unittest.cc
+++ b/modules/video_coding/video_codec_initializer_unittest.cc
@@ -79,6 +79,7 @@
           webrtc::VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
       settings_.payload_name = kVp8PayloadName;
       settings_.payload_type = kVp8PayloadType;
+    } else if (type == VideoCodecType::kVideoCodecStereo) {
     } else {
       ADD_FAILURE() << "Unexpected codec type: " << type;
     }
@@ -93,7 +94,8 @@
                                            &bitrate_allocator_out_)) {
       return false;
     }
-
+    if (codec_out_.codecType == VideoCodecType::kVideoCodecStereo)
+      return true;
     // Make sure temporal layers instances have been created.
     if (codec_out_.codecType == VideoCodecType::kVideoCodecVP8) {
       if (!codec_out_.VP8()->tl_factory)
@@ -215,4 +217,10 @@
             bitrate_allocation.GetBitrate(1, 1));
 }
 
+TEST_F(VideoCodecInitializerTest, SingleStreamStereoCodec) {
+  SetUpFor(VideoCodecType::kVideoCodecStereo, 1, 1, true);
+  streams_.push_back(DefaultStream());
+  EXPECT_TRUE(InitializeCodec());
+}
+
 }  // namespace webrtc
diff --git a/video/video_receive_stream.cc b/video/video_receive_stream.cc
index 5f6b5cf..62a4dd2 100644
--- a/video/video_receive_stream.cc
+++ b/video/video_receive_stream.cc
@@ -59,6 +59,12 @@
     *(codec.H264()) = VideoEncoder::GetDefaultH264Settings();
     codec.H264()->profile =
         H264::ParseSdpProfileLevelId(decoder.codec_params)->profile;
+  } else if (codec.codecType == kVideoCodecStereo) {
+    VideoReceiveStream::Decoder associated_decoder = decoder;
+    associated_decoder.payload_name = CodecTypeToPayloadString(kVideoCodecVP9);
+    VideoCodec associated_codec = CreateDecoderVideoCodec(associated_decoder);
+    associated_codec.codecType = kVideoCodecStereo;
+    return associated_codec;
   }
 
   codec.width = 320;