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}
This commit is contained in:

committed by
Commit Bot

parent
654320666d
commit
0a37547033
@ -137,6 +137,7 @@ static const char* kPayloadNameI420 = "I420";
|
|||||||
static const char* kPayloadNameRED = "RED";
|
static const char* kPayloadNameRED = "RED";
|
||||||
static const char* kPayloadNameULPFEC = "ULPFEC";
|
static const char* kPayloadNameULPFEC = "ULPFEC";
|
||||||
static const char* kPayloadNameGeneric = "Generic";
|
static const char* kPayloadNameGeneric = "Generic";
|
||||||
|
static const char* kPayloadNameStereo = "Stereo";
|
||||||
|
|
||||||
static bool CodecNamesEq(const char* name1, const char* name2) {
|
static bool CodecNamesEq(const char* name1, const char* name2) {
|
||||||
return _stricmp(name1, name2) == 0;
|
return _stricmp(name1, name2) == 0;
|
||||||
@ -156,10 +157,14 @@ const char* CodecTypeToPayloadString(VideoCodecType type) {
|
|||||||
return kPayloadNameRED;
|
return kPayloadNameRED;
|
||||||
case kVideoCodecULPFEC:
|
case kVideoCodecULPFEC:
|
||||||
return kPayloadNameULPFEC;
|
return kPayloadNameULPFEC;
|
||||||
default:
|
// Other codecs default to generic.
|
||||||
// Unrecognized codecs default to generic.
|
case kVideoCodecStereo:
|
||||||
|
case kVideoCodecFlexfec:
|
||||||
|
case kVideoCodecGeneric:
|
||||||
|
case kVideoCodecUnknown:
|
||||||
return kPayloadNameGeneric;
|
return kPayloadNameGeneric;
|
||||||
}
|
}
|
||||||
|
return kPayloadNameGeneric;
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoCodecType PayloadStringToCodecType(const std::string& name) {
|
VideoCodecType PayloadStringToCodecType(const std::string& name) {
|
||||||
@ -175,6 +180,8 @@ VideoCodecType PayloadStringToCodecType(const std::string& name) {
|
|||||||
return kVideoCodecRED;
|
return kVideoCodecRED;
|
||||||
if (CodecNamesEq(name.c_str(), kPayloadNameULPFEC))
|
if (CodecNamesEq(name.c_str(), kPayloadNameULPFEC))
|
||||||
return kVideoCodecULPFEC;
|
return kVideoCodecULPFEC;
|
||||||
|
if (CodecNamesEq(name.c_str(), kPayloadNameStereo))
|
||||||
|
return kVideoCodecStereo;
|
||||||
return kVideoCodecGeneric;
|
return kVideoCodecGeneric;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,6 +157,8 @@ rtc_static_library("rtc_audio_video") {
|
|||||||
"engine/simulcast.h",
|
"engine/simulcast.h",
|
||||||
"engine/simulcast_encoder_adapter.cc",
|
"engine/simulcast_encoder_adapter.cc",
|
||||||
"engine/simulcast_encoder_adapter.h",
|
"engine/simulcast_encoder_adapter.h",
|
||||||
|
"engine/stereocodecfactory.cc",
|
||||||
|
"engine/stereocodecfactory.h",
|
||||||
"engine/videodecodersoftwarefallbackwrapper.cc",
|
"engine/videodecodersoftwarefallbackwrapper.cc",
|
||||||
"engine/videodecodersoftwarefallbackwrapper.h",
|
"engine/videodecodersoftwarefallbackwrapper.h",
|
||||||
"engine/videoencodersoftwarefallbackwrapper.cc",
|
"engine/videoencodersoftwarefallbackwrapper.cc",
|
||||||
@ -243,6 +245,7 @@ rtc_static_library("rtc_audio_video") {
|
|||||||
"../modules/video_capture:video_capture_module",
|
"../modules/video_capture:video_capture_module",
|
||||||
"../modules/video_coding",
|
"../modules/video_coding",
|
||||||
"../modules/video_coding:webrtc_h264",
|
"../modules/video_coding:webrtc_h264",
|
||||||
|
"../modules/video_coding:webrtc_stereo",
|
||||||
"../modules/video_coding:webrtc_vp8",
|
"../modules/video_coding:webrtc_vp8",
|
||||||
"../modules/video_coding:webrtc_vp9",
|
"../modules/video_coding:webrtc_vp9",
|
||||||
"../p2p:rtc_p2p",
|
"../p2p:rtc_p2p",
|
||||||
@ -450,6 +453,7 @@ if (rtc_include_tests) {
|
|||||||
"engine/payload_type_mapper_unittest.cc",
|
"engine/payload_type_mapper_unittest.cc",
|
||||||
"engine/simulcast_encoder_adapter_unittest.cc",
|
"engine/simulcast_encoder_adapter_unittest.cc",
|
||||||
"engine/simulcast_unittest.cc",
|
"engine/simulcast_unittest.cc",
|
||||||
|
"engine/stereocodecfactory_unittest.cc",
|
||||||
"engine/videodecodersoftwarefallbackwrapper_unittest.cc",
|
"engine/videodecodersoftwarefallbackwrapper_unittest.cc",
|
||||||
"engine/videoencodersoftwarefallbackwrapper_unittest.cc",
|
"engine/videoencodersoftwarefallbackwrapper_unittest.cc",
|
||||||
"engine/vp8_encoder_simulcast_proxy_unittest.cc",
|
"engine/vp8_encoder_simulcast_proxy_unittest.cc",
|
||||||
|
@ -25,6 +25,7 @@ const float kProcessCpuThreshold = 0.10f;
|
|||||||
const char kRtxCodecName[] = "rtx";
|
const char kRtxCodecName[] = "rtx";
|
||||||
const char kRedCodecName[] = "red";
|
const char kRedCodecName[] = "red";
|
||||||
const char kUlpfecCodecName[] = "ulpfec";
|
const char kUlpfecCodecName[] = "ulpfec";
|
||||||
|
const char kStereoCodecName[] = "stereo";
|
||||||
|
|
||||||
// TODO(brandtr): Change this to 'flexfec' when we are confident that the
|
// TODO(brandtr): Change this to 'flexfec' when we are confident that the
|
||||||
// header format is not changing anymore.
|
// header format is not changing anymore.
|
||||||
@ -34,6 +35,7 @@ const char kFlexfecCodecName[] = "flexfec-03";
|
|||||||
const char kFlexfecFmtpRepairWindow[] = "repair-window";
|
const char kFlexfecFmtpRepairWindow[] = "repair-window";
|
||||||
|
|
||||||
const char kCodecParamAssociatedPayloadType[] = "apt";
|
const char kCodecParamAssociatedPayloadType[] = "apt";
|
||||||
|
const char kCodecParamAssociatedCodecName[] = "acn";
|
||||||
|
|
||||||
const char kOpusCodecName[] = "opus";
|
const char kOpusCodecName[] = "opus";
|
||||||
const char kIsacCodecName[] = "ISAC";
|
const char kIsacCodecName[] = "ISAC";
|
||||||
|
@ -30,11 +30,13 @@ extern const char kRtxCodecName[];
|
|||||||
extern const char kRedCodecName[];
|
extern const char kRedCodecName[];
|
||||||
extern const char kUlpfecCodecName[];
|
extern const char kUlpfecCodecName[];
|
||||||
extern const char kFlexfecCodecName[];
|
extern const char kFlexfecCodecName[];
|
||||||
|
extern const char kStereoCodecName[];
|
||||||
|
|
||||||
extern const char kFlexfecFmtpRepairWindow[];
|
extern const char kFlexfecFmtpRepairWindow[];
|
||||||
|
|
||||||
// Codec parameters
|
// Codec parameters
|
||||||
extern const char kCodecParamAssociatedPayloadType[];
|
extern const char kCodecParamAssociatedPayloadType[];
|
||||||
|
extern const char kCodecParamAssociatedCodecName[];
|
||||||
|
|
||||||
extern const char kOpusCodecName[];
|
extern const char kOpusCodecName[];
|
||||||
extern const char kIsacCodecName[];
|
extern const char kIsacCodecName[];
|
||||||
|
111
media/engine/stereocodecfactory.cc
Normal file
111
media/engine/stereocodecfactory.cc
Normal file
@ -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
|
49
media/engine/stereocodecfactory.h
Normal file
49
media/engine/stereocodecfactory.h
Normal file
@ -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_
|
47
media/engine/stereocodecfactory_unittest.cc
Normal file
47
media/engine/stereocodecfactory_unittest.cc
Normal file
@ -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
|
@ -15,6 +15,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "api/video_codecs/sdp_video_format.h"
|
||||||
#include "api/video_codecs/video_decoder.h"
|
#include "api/video_codecs/video_decoder.h"
|
||||||
#include "api/video_codecs/video_decoder_factory.h"
|
#include "api/video_codecs/video_decoder_factory.h"
|
||||||
#include "modules/video_coding/codecs/stereo/include/stereo_encoder_adapter.h"
|
#include "modules/video_coding/codecs/stereo/include/stereo_encoder_adapter.h"
|
||||||
@ -24,7 +25,8 @@ namespace webrtc {
|
|||||||
class StereoDecoderAdapter : public VideoDecoder {
|
class StereoDecoderAdapter : public VideoDecoder {
|
||||||
public:
|
public:
|
||||||
// |factory| is not owned and expected to outlive this class' lifetime.
|
// |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();
|
virtual ~StereoDecoderAdapter();
|
||||||
|
|
||||||
// Implements VideoDecoder
|
// Implements VideoDecoder
|
||||||
@ -59,6 +61,7 @@ class StereoDecoderAdapter : public VideoDecoder {
|
|||||||
const rtc::Optional<uint8_t>& stereo_qp);
|
const rtc::Optional<uint8_t>& stereo_qp);
|
||||||
|
|
||||||
VideoDecoderFactory* const factory_;
|
VideoDecoderFactory* const factory_;
|
||||||
|
const SdpVideoFormat associated_format_;
|
||||||
std::vector<std::unique_ptr<VideoDecoder>> decoders_;
|
std::vector<std::unique_ptr<VideoDecoder>> decoders_;
|
||||||
std::vector<std::unique_ptr<AdapterDecodedImageCallback>> adapter_callbacks_;
|
std::vector<std::unique_ptr<AdapterDecodedImageCallback>> adapter_callbacks_;
|
||||||
DecodedImageCallback* decoded_complete_callback_;
|
DecodedImageCallback* decoded_complete_callback_;
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "api/video_codecs/sdp_video_format.h"
|
||||||
#include "api/video_codecs/video_encoder.h"
|
#include "api/video_codecs/video_encoder.h"
|
||||||
#include "api/video_codecs/video_encoder_factory.h"
|
#include "api/video_codecs/video_encoder_factory.h"
|
||||||
#include "modules/video_coding/include/video_codec_interface.h"
|
#include "modules/video_coding/include/video_codec_interface.h"
|
||||||
@ -30,7 +31,8 @@ enum AlphaCodecStream {
|
|||||||
class StereoEncoderAdapter : public VideoEncoder {
|
class StereoEncoderAdapter : public VideoEncoder {
|
||||||
public:
|
public:
|
||||||
// |factory| is not owned and expected to outlive this class' lifetime.
|
// |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();
|
virtual ~StereoEncoderAdapter();
|
||||||
|
|
||||||
// Implements VideoEncoder
|
// Implements VideoEncoder
|
||||||
@ -58,6 +60,7 @@ class StereoEncoderAdapter : public VideoEncoder {
|
|||||||
class AdapterEncodedImageCallback;
|
class AdapterEncodedImageCallback;
|
||||||
|
|
||||||
VideoEncoderFactory* const factory_;
|
VideoEncoderFactory* const factory_;
|
||||||
|
const SdpVideoFormat associated_format_;
|
||||||
std::vector<std::unique_ptr<VideoEncoder>> encoders_;
|
std::vector<std::unique_ptr<VideoEncoder>> encoders_;
|
||||||
std::vector<std::unique_ptr<AdapterEncodedImageCallback>> adapter_callbacks_;
|
std::vector<std::unique_ptr<AdapterEncodedImageCallback>> adapter_callbacks_;
|
||||||
EncodedImageCallback* encoded_complete_callback_;
|
EncodedImageCallback* encoded_complete_callback_;
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
#include "api/video/i420_buffer.h"
|
#include "api/video/i420_buffer.h"
|
||||||
#include "api/video/video_frame_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.h"
|
||||||
#include "common_video/include/video_frame_buffer.h"
|
#include "common_video/include/video_frame_buffer.h"
|
||||||
#include "common_video/libyuv/include/webrtc_libyuv.h"
|
#include "common_video/libyuv/include/webrtc_libyuv.h"
|
||||||
@ -80,8 +79,10 @@ struct StereoDecoderAdapter::DecodedImageData {
|
|||||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(DecodedImageData);
|
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(DecodedImageData);
|
||||||
};
|
};
|
||||||
|
|
||||||
StereoDecoderAdapter::StereoDecoderAdapter(VideoDecoderFactory* factory)
|
StereoDecoderAdapter::StereoDecoderAdapter(
|
||||||
: factory_(factory) {}
|
VideoDecoderFactory* factory,
|
||||||
|
const SdpVideoFormat& associated_format)
|
||||||
|
: factory_(factory), associated_format_(associated_format) {}
|
||||||
|
|
||||||
StereoDecoderAdapter::~StereoDecoderAdapter() {
|
StereoDecoderAdapter::~StereoDecoderAdapter() {
|
||||||
Release();
|
Release();
|
||||||
@ -89,12 +90,12 @@ StereoDecoderAdapter::~StereoDecoderAdapter() {
|
|||||||
|
|
||||||
int32_t StereoDecoderAdapter::InitDecode(const VideoCodec* codec_settings,
|
int32_t StereoDecoderAdapter::InitDecode(const VideoCodec* codec_settings,
|
||||||
int32_t number_of_cores) {
|
int32_t number_of_cores) {
|
||||||
|
RTC_DCHECK_EQ(kVideoCodecStereo, codec_settings->codecType);
|
||||||
VideoCodec settings = *codec_settings;
|
VideoCodec settings = *codec_settings;
|
||||||
settings.codecType = kVideoCodecVP9;
|
settings.codecType = PayloadStringToCodecType(associated_format_.name);
|
||||||
for (size_t i = 0; i < kAlphaCodecStreams; ++i) {
|
for (size_t i = 0; i < kAlphaCodecStreams; ++i) {
|
||||||
const SdpVideoFormat format("VP9");
|
|
||||||
std::unique_ptr<VideoDecoder> decoder =
|
std::unique_ptr<VideoDecoder> decoder =
|
||||||
factory_->CreateVideoDecoder(format);
|
factory_->CreateVideoDecoder(associated_format_);
|
||||||
const int32_t rv = decoder->InitDecode(&settings, number_of_cores);
|
const int32_t rv = decoder->InitDecode(&settings, number_of_cores);
|
||||||
if (rv)
|
if (rv)
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#include "modules/video_coding/codecs/stereo/include/stereo_encoder_adapter.h"
|
#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.h"
|
||||||
#include "common_video/include/video_frame_buffer.h"
|
#include "common_video/include/video_frame_buffer.h"
|
||||||
#include "common_video/libyuv/include/webrtc_libyuv.h"
|
#include "common_video/libyuv/include/webrtc_libyuv.h"
|
||||||
@ -58,8 +57,12 @@ struct StereoEncoderAdapter::ImageStereoInfo {
|
|||||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ImageStereoInfo);
|
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ImageStereoInfo);
|
||||||
};
|
};
|
||||||
|
|
||||||
StereoEncoderAdapter::StereoEncoderAdapter(VideoEncoderFactory* factory)
|
StereoEncoderAdapter::StereoEncoderAdapter(
|
||||||
: factory_(factory), encoded_complete_callback_(nullptr) {}
|
VideoEncoderFactory* factory,
|
||||||
|
const SdpVideoFormat& associated_format)
|
||||||
|
: factory_(factory),
|
||||||
|
associated_format_(associated_format),
|
||||||
|
encoded_complete_callback_(nullptr) {}
|
||||||
|
|
||||||
StereoEncoderAdapter::~StereoEncoderAdapter() {
|
StereoEncoderAdapter::~StereoEncoderAdapter() {
|
||||||
Release();
|
Release();
|
||||||
@ -74,13 +77,16 @@ int StereoEncoderAdapter::InitEncode(const VideoCodec* inst,
|
|||||||
// It is more expensive to encode 0x00, so use 0x80 instead.
|
// It is more expensive to encode 0x00, so use 0x80 instead.
|
||||||
std::fill(stereo_dummy_planes_.begin(), stereo_dummy_planes_.end(), 0x80);
|
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) {
|
for (size_t i = 0; i < kAlphaCodecStreams; ++i) {
|
||||||
const SdpVideoFormat format("VP9");
|
|
||||||
std::unique_ptr<VideoEncoder> encoder =
|
std::unique_ptr<VideoEncoder> encoder =
|
||||||
factory_->CreateVideoEncoder(format);
|
factory_->CreateVideoEncoder(associated_format_);
|
||||||
const int rv = encoder->InitEncode(inst, number_of_cores, max_payload_size);
|
const int rv =
|
||||||
|
encoder->InitEncode(&settings, number_of_cores, max_payload_size);
|
||||||
if (rv) {
|
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;
|
return rv;
|
||||||
}
|
}
|
||||||
adapter_callbacks_.emplace_back(new AdapterEncodedImageCallback(
|
adapter_callbacks_.emplace_back(new AdapterEncodedImageCallback(
|
||||||
@ -180,7 +186,7 @@ EncodedImageCallback::Result StereoEncoderAdapter::OnEncodedImage(
|
|||||||
const EncodedImage& encodedImage,
|
const EncodedImage& encodedImage,
|
||||||
const CodecSpecificInfo* codecSpecificInfo,
|
const CodecSpecificInfo* codecSpecificInfo,
|
||||||
const RTPFragmentationHeader* fragmentation) {
|
const RTPFragmentationHeader* fragmentation) {
|
||||||
const VideoCodecType associated_coded_type = codecSpecificInfo->codecType;
|
const VideoCodecType associated_codec_type = codecSpecificInfo->codecType;
|
||||||
const auto& image_stereo_info_itr =
|
const auto& image_stereo_info_itr =
|
||||||
image_stereo_info_.find(encodedImage._timeStamp);
|
image_stereo_info_.find(encodedImage._timeStamp);
|
||||||
RTC_DCHECK(image_stereo_info_itr != image_stereo_info_.end());
|
RTC_DCHECK(image_stereo_info_itr != image_stereo_info_.end());
|
||||||
@ -193,7 +199,7 @@ EncodedImageCallback::Result StereoEncoderAdapter::OnEncodedImage(
|
|||||||
CodecSpecificInfo codec_info = *codecSpecificInfo;
|
CodecSpecificInfo codec_info = *codecSpecificInfo;
|
||||||
codec_info.codecType = kVideoCodecStereo;
|
codec_info.codecType = kVideoCodecStereo;
|
||||||
codec_info.codec_name = "stereo";
|
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_index = stream_idx;
|
||||||
codec_info.codecSpecific.stereo.indices.frame_count = frame_count;
|
codec_info.codecSpecific.stereo.indices.frame_count = frame_count;
|
||||||
codec_info.codecSpecific.stereo.indices.picture_index = picture_index;
|
codec_info.codecSpecific.stereo.indices.picture_index = picture_index;
|
||||||
|
@ -10,8 +10,10 @@
|
|||||||
|
|
||||||
#include "api/test/mock_video_decoder_factory.h"
|
#include "api/test/mock_video_decoder_factory.h"
|
||||||
#include "api/test/mock_video_encoder_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/include/video_frame_buffer.h"
|
||||||
#include "common_video/libyuv/include/webrtc_libyuv.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_decoder_adapter.h"
|
||||||
#include "modules/video_coding/codecs/stereo/include/stereo_encoder_adapter.h"
|
#include "modules/video_coding/codecs/stereo/include/stereo_encoder_adapter.h"
|
||||||
#include "modules/video_coding/codecs/test/video_codec_test.h"
|
#include "modules/video_coding/codecs/test/video_codec_test.h"
|
||||||
@ -24,6 +26,10 @@ using testing::Return;
|
|||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
|
constexpr const char* kStereoAssociatedCodecName = cricket::kVp9CodecName;
|
||||||
|
const VideoCodecType kStereoAssociatedCodecType =
|
||||||
|
PayloadStringToCodecType(kStereoAssociatedCodecName);
|
||||||
|
|
||||||
class TestStereoAdapter : public VideoCodecTest {
|
class TestStereoAdapter : public VideoCodecTest {
|
||||||
public:
|
public:
|
||||||
TestStereoAdapter()
|
TestStereoAdapter()
|
||||||
@ -32,18 +38,21 @@ class TestStereoAdapter : public VideoCodecTest {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<VideoDecoder> CreateDecoder() override {
|
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 {
|
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() override {
|
||||||
VideoCodec codec_settings;
|
VideoCodec codec_settings;
|
||||||
codec_settings.codecType = webrtc::kVideoCodecVP9;
|
codec_settings.codecType = kStereoAssociatedCodecType;
|
||||||
codec_settings.VP9()->numberOfTemporalLayers = 1;
|
codec_settings.VP9()->numberOfTemporalLayers = 1;
|
||||||
codec_settings.VP9()->numberOfSpatialLayers = 1;
|
codec_settings.VP9()->numberOfSpatialLayers = 1;
|
||||||
|
codec_settings.codecType = webrtc::kVideoCodecStereo;
|
||||||
return codec_settings;
|
return codec_settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +112,7 @@ TEST_F(TestStereoAdapter, EncodeDecodeI420Frame) {
|
|||||||
ASSERT_TRUE(WaitForEncodedFrame(&encoded_frame, &codec_specific_info));
|
ASSERT_TRUE(WaitForEncodedFrame(&encoded_frame, &codec_specific_info));
|
||||||
|
|
||||||
EXPECT_EQ(kVideoCodecStereo, codec_specific_info.codecType);
|
EXPECT_EQ(kVideoCodecStereo, codec_specific_info.codecType);
|
||||||
EXPECT_EQ(kVideoCodecVP9,
|
EXPECT_EQ(kStereoAssociatedCodecType,
|
||||||
codec_specific_info.codecSpecific.stereo.associated_codec_type);
|
codec_specific_info.codecSpecific.stereo.associated_codec_type);
|
||||||
EXPECT_EQ(0, codec_specific_info.codecSpecific.stereo.indices.frame_index);
|
EXPECT_EQ(0, codec_specific_info.codecSpecific.stereo.indices.frame_index);
|
||||||
EXPECT_EQ(1, codec_specific_info.codecSpecific.stereo.indices.frame_count);
|
EXPECT_EQ(1, codec_specific_info.codecSpecific.stereo.indices.frame_count);
|
||||||
@ -134,7 +143,7 @@ TEST_F(TestStereoAdapter, EncodeDecodeI420AFrame) {
|
|||||||
|
|
||||||
const CodecSpecificInfo& yuv_info = codec_specific_infos[kYUVStream];
|
const CodecSpecificInfo& yuv_info = codec_specific_infos[kYUVStream];
|
||||||
EXPECT_EQ(kVideoCodecStereo, yuv_info.codecType);
|
EXPECT_EQ(kVideoCodecStereo, yuv_info.codecType);
|
||||||
EXPECT_EQ(kVideoCodecVP9,
|
EXPECT_EQ(kStereoAssociatedCodecType,
|
||||||
yuv_info.codecSpecific.stereo.associated_codec_type);
|
yuv_info.codecSpecific.stereo.associated_codec_type);
|
||||||
EXPECT_EQ(kYUVStream, yuv_info.codecSpecific.stereo.indices.frame_index);
|
EXPECT_EQ(kYUVStream, yuv_info.codecSpecific.stereo.indices.frame_index);
|
||||||
EXPECT_EQ(kAlphaCodecStreams,
|
EXPECT_EQ(kAlphaCodecStreams,
|
||||||
@ -143,7 +152,7 @@ TEST_F(TestStereoAdapter, EncodeDecodeI420AFrame) {
|
|||||||
|
|
||||||
const CodecSpecificInfo& axx_info = codec_specific_infos[kAXXStream];
|
const CodecSpecificInfo& axx_info = codec_specific_infos[kAXXStream];
|
||||||
EXPECT_EQ(kVideoCodecStereo, axx_info.codecType);
|
EXPECT_EQ(kVideoCodecStereo, axx_info.codecType);
|
||||||
EXPECT_EQ(kVideoCodecVP9,
|
EXPECT_EQ(kStereoAssociatedCodecType,
|
||||||
axx_info.codecSpecific.stereo.associated_codec_type);
|
axx_info.codecSpecific.stereo.associated_codec_type);
|
||||||
EXPECT_EQ(kAXXStream, axx_info.codecSpecific.stereo.indices.frame_index);
|
EXPECT_EQ(kAXXStream, axx_info.codecSpecific.stereo.indices.frame_index);
|
||||||
EXPECT_EQ(kAlphaCodecStreams,
|
EXPECT_EQ(kAlphaCodecStreams,
|
||||||
|
@ -39,6 +39,20 @@ bool VideoCodecInitializer::SetupCodec(
|
|||||||
bool nack_enabled,
|
bool nack_enabled,
|
||||||
VideoCodec* codec,
|
VideoCodec* codec,
|
||||||
std::unique_ptr<VideoBitrateAllocator>* bitrate_allocator) {
|
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 =
|
*codec =
|
||||||
VideoEncoderConfigToVideoCodec(config, streams, settings.payload_name,
|
VideoEncoderConfigToVideoCodec(config, streams, settings.payload_name,
|
||||||
settings.payload_type, nack_enabled);
|
settings.payload_type, nack_enabled);
|
||||||
|
@ -79,6 +79,7 @@ class VideoCodecInitializerTest : public ::testing::Test {
|
|||||||
webrtc::VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
|
webrtc::VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
|
||||||
settings_.payload_name = kVp8PayloadName;
|
settings_.payload_name = kVp8PayloadName;
|
||||||
settings_.payload_type = kVp8PayloadType;
|
settings_.payload_type = kVp8PayloadType;
|
||||||
|
} else if (type == VideoCodecType::kVideoCodecStereo) {
|
||||||
} else {
|
} else {
|
||||||
ADD_FAILURE() << "Unexpected codec type: " << type;
|
ADD_FAILURE() << "Unexpected codec type: " << type;
|
||||||
}
|
}
|
||||||
@ -93,7 +94,8 @@ class VideoCodecInitializerTest : public ::testing::Test {
|
|||||||
&bitrate_allocator_out_)) {
|
&bitrate_allocator_out_)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (codec_out_.codecType == VideoCodecType::kVideoCodecStereo)
|
||||||
|
return true;
|
||||||
// Make sure temporal layers instances have been created.
|
// Make sure temporal layers instances have been created.
|
||||||
if (codec_out_.codecType == VideoCodecType::kVideoCodecVP8) {
|
if (codec_out_.codecType == VideoCodecType::kVideoCodecVP8) {
|
||||||
if (!codec_out_.VP8()->tl_factory)
|
if (!codec_out_.VP8()->tl_factory)
|
||||||
@ -215,4 +217,10 @@ TEST_F(VideoCodecInitializerTest, HighFpsSimlucastVp8Screenshare) {
|
|||||||
bitrate_allocation.GetBitrate(1, 1));
|
bitrate_allocation.GetBitrate(1, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(VideoCodecInitializerTest, SingleStreamStereoCodec) {
|
||||||
|
SetUpFor(VideoCodecType::kVideoCodecStereo, 1, 1, true);
|
||||||
|
streams_.push_back(DefaultStream());
|
||||||
|
EXPECT_TRUE(InitializeCodec());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -59,6 +59,12 @@ VideoCodec CreateDecoderVideoCodec(const VideoReceiveStream::Decoder& decoder) {
|
|||||||
*(codec.H264()) = VideoEncoder::GetDefaultH264Settings();
|
*(codec.H264()) = VideoEncoder::GetDefaultH264Settings();
|
||||||
codec.H264()->profile =
|
codec.H264()->profile =
|
||||||
H264::ParseSdpProfileLevelId(decoder.codec_params)->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;
|
codec.width = 320;
|
||||||
|
Reference in New Issue
Block a user