diff options
Diffstat (limited to 'media')
-rw-r--r-- | media/base/fakemediaengine.h | 3 | ||||
-rw-r--r-- | media/base/filemediaengine.h | 3 | ||||
-rw-r--r-- | media/base/mediaengine.h | 10 | ||||
-rwxr-xr-x | media/webrtc/constants.h | 4 | ||||
-rw-r--r-- | media/webrtc/webrtcmediaengine.h | 3 | ||||
-rw-r--r-- | media/webrtc/webrtcvideoengine.cc | 158 | ||||
-rw-r--r-- | media/webrtc/webrtcvideoengine.h | 23 | ||||
-rw-r--r-- | media/webrtc/webrtcvideoengine2.cc | 273 | ||||
-rw-r--r-- | media/webrtc/webrtcvideoengine2.h | 20 | ||||
-rw-r--r-- | media/webrtc/webrtcvoiceengine.cc | 31 | ||||
-rw-r--r-- | media/webrtc/webrtcvoiceengine.h | 1 | ||||
-rw-r--r-- | media/webrtc/webrtcvoiceengine_unittest.cc | 26 |
12 files changed, 275 insertions, 280 deletions
diff --git a/media/base/fakemediaengine.h b/media/base/fakemediaengine.h index db5e2e4..ff6ae16 100644 --- a/media/base/fakemediaengine.h +++ b/media/base/fakemediaengine.h @@ -879,9 +879,6 @@ class FakeVideoEngine : public FakeBaseEngine { default_encoder_config_ = config; return true; } - VideoEncoderConfig GetDefaultEncoderConfig() const { - return default_encoder_config_; - } const VideoEncoderConfig& default_encoder_config() const { return default_encoder_config_; } diff --git a/media/base/filemediaengine.h b/media/base/filemediaengine.h index 9cc066d..ba29ab3 100644 --- a/media/base/filemediaengine.h +++ b/media/base/filemediaengine.h @@ -93,9 +93,6 @@ class FileMediaEngine : public MediaEngineInterface { virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config) { return true; } - virtual VideoEncoderConfig GetDefaultVideoEncoderConfig() const { - return VideoEncoderConfig(); - } virtual bool SetSoundDevices(const Device* in_dev, const Device* out_dev) { return true; } diff --git a/media/base/mediaengine.h b/media/base/mediaengine.h index e7222f2..b8d661c 100644 --- a/media/base/mediaengine.h +++ b/media/base/mediaengine.h @@ -99,10 +99,6 @@ class MediaEngineInterface { // and encode video. virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config) = 0; - // Gets the default (maximum) codec/resolution and encoder option used to - // capture and encode video, as set by SetDefaultVideoEncoderConfig or the - // default from the video engine if not previously set. - virtual VideoEncoderConfig GetDefaultVideoEncoderConfig() const = 0; // Device selection // TODO(tschmelcher): Add method for selecting the soundclip device. @@ -219,9 +215,6 @@ class CompositeMediaEngine : public MediaEngineInterface { virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config) { return video_.SetDefaultEncoderConfig(config); } - virtual VideoEncoderConfig GetDefaultVideoEncoderConfig() const { - return video_.GetDefaultEncoderConfig(); - } virtual bool SetSoundDevices(const Device* in_device, const Device* out_device) { @@ -347,9 +340,6 @@ class NullVideoEngine { return NULL; } bool SetOptions(const VideoOptions& options) { return true; } - VideoEncoderConfig GetDefaultEncoderConfig() const { - return VideoEncoderConfig(); - } bool SetDefaultEncoderConfig(const VideoEncoderConfig& config) { return true; } diff --git a/media/webrtc/constants.h b/media/webrtc/constants.h index 5390c0d..821a41f 100755 --- a/media/webrtc/constants.h +++ b/media/webrtc/constants.h @@ -35,7 +35,9 @@ extern const int kVideoRtpBufferSize; 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/media/webrtc/webrtcmediaengine.h b/media/webrtc/webrtcmediaengine.h index bfcfb2a..b4436cd 100644 --- a/media/webrtc/webrtcmediaengine.h +++ b/media/webrtc/webrtcmediaengine.h @@ -130,9 +130,6 @@ class DelegatingWebRtcMediaEngine : public cricket::MediaEngineInterface { const VideoEncoderConfig& config) OVERRIDE { return delegate_->SetDefaultVideoEncoderConfig(config); } - virtual VideoEncoderConfig GetDefaultVideoEncoderConfig() const OVERRIDE { - return delegate_->GetDefaultVideoEncoderConfig(); - } virtual bool SetSoundDevices( const Device* in_device, const Device* out_device) OVERRIDE { return delegate_->SetSoundDevices(in_device, out_device); diff --git a/media/webrtc/webrtcvideoengine.cc b/media/webrtc/webrtcvideoengine.cc index a0a8d81..46d316f 100644 --- a/media/webrtc/webrtcvideoengine.cc +++ b/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 int kVideoRtpBufferSize = 65536; 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 bool kNotSending = false; 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)); +} + +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)); } -// Returns true if Receiver Estimated Max Bitrate is enabled. -static bool IsRembEnabled(const VideoCodec& codec) { - return codec.HasFeedbackParam(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 @@ class WebRtcVideoChannelSendInfo : public sigslot::has_slots<> { 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 @@ void WebRtcVideoEngine::Construct(ViEWrapper* vie_wrapper, 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. @@ -1144,17 +1172,6 @@ bool WebRtcVideoEngine::SetDefaultEncoderConfig( return SetDefaultCodec(config.max_codec); } -VideoEncoderConfig WebRtcVideoEngine::GetDefaultEncoderConfig() const { - ASSERT(!video_codecs_.empty()); - VideoCodec max_codec(kVideoCodecPrefs[0].payload_type, - kVideoCodecPrefs[0].name, - video_codecs_[0].width, - video_codecs_[0].height, - video_codecs_[0].framerate, - 0); - return VideoEncoderConfig(max_codec); -} - // SetDefaultCodec may be called while the capturer is running. For example, a // test call is started in a page with QVGA default codec, and then a real call // is started in another page with VGA default codec. This is the corner case @@ -1225,13 +1242,12 @@ bool WebRtcVideoEngine::FindCodec(const VideoCodec& in) { 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; } @@ -1439,17 +1455,6 @@ void WebRtcVideoEngine::SetTraceOptions(const std::string& options) { } } -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. @@ -1459,27 +1464,17 @@ bool WebRtcVideoEngine::RebuildCodecList(const VideoCodec& in_codec) { 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(); @@ -1487,8 +1482,6 @@ bool WebRtcVideoEngine::RebuildCodecList(const VideoCodec& in_codec) { 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, @@ -1503,7 +1496,6 @@ bool WebRtcVideoEngine::RebuildCodecList(const VideoCodec& in_codec) { } } } - ASSERT(found); return true; } @@ -1609,12 +1601,10 @@ void WebRtcVideoEngine::SetExternalEncoderFactory( 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/media/webrtc/webrtcvideoengine.h b/media/webrtc/webrtcvideoengine.h index eee82c8..db091af 100644 --- a/media/webrtc/webrtcvideoengine.h +++ b/media/webrtc/webrtcvideoengine.h @@ -85,6 +85,15 @@ class WebRtcVoiceEngine; 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: @@ -108,7 +117,6 @@ class WebRtcVideoEngine : public sigslot::has_slots<>, int GetCapabilities(); bool SetDefaultEncoderConfig(const VideoEncoderConfig& config); - VideoEncoderConfig GetDefaultEncoderConfig() const; // TODO(pbos): Remove when all call sites use VideoOptions. virtual WebRtcVideoMediaChannel* CreateChannel( @@ -188,18 +196,6 @@ class WebRtcVideoEngine : public sigslot::has_slots<>, 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, @@ -226,6 +222,7 @@ class WebRtcVideoEngine : public sigslot::has_slots<>, 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/media/webrtc/webrtcvideoengine2.cc b/media/webrtc/webrtcvideoengine2.cc index 5062fb9..5b5f12e 100644 --- a/media/webrtc/webrtcvideoengine2.cc +++ b/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 @@ static std::string RtpExtensionsToString( 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 int kExternalVideoPayloadTypeBase = 120; 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 @@ static bool FindFirstMatchingCodec(const std::vector<VideoCodec>& codecs, 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 @@ std::vector<webrtc::VideoStream> WebRtcVideoEncoderFactory2::CreateVideoStreams( 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 @@ void DefaultUnsignalledSsrcHandler::SetDefaultRenderer( 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)), @@ -427,10 +367,6 @@ bool WebRtcVideoEngine2::SetDefaultEncoderConfig( return true; } -VideoEncoderConfig WebRtcVideoEngine2::GetDefaultEncoderConfig() const { - return VideoEncoderConfig(DefaultVideoCodec()); -} - WebRtcVideoChannel2* WebRtcVideoEngine2::CreateChannel( const VideoOptions& options, VoiceMediaChannel* voice_channel) { @@ -575,7 +511,7 @@ WebRtcVideoEncoderFactory2* WebRtcVideoEngine2::GetVideoEncoderFactory() { } 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; @@ -900,9 +836,16 @@ bool WebRtcVideoChannel2::SetSendCodecs(const std::vector<VideoCodec>& codecs) { return false; } - send_codec_.Set(supported_codecs.front()); LOG(LS_INFO) << "Using codec: " << supported_codecs.front().codec.ToString(); + VideoCodecSettings old_codec; + if (send_codec_.Get(&old_codec) && supported_codecs.front() == old_codec) { + // Using same codec, avoid reconfiguring. + return true; + } + + send_codec_.Set(supported_codecs.front()); + rtc::CritScope stream_lock(&stream_crit_); for (std::map<uint32, WebRtcVideoSendStream*>::iterator it = send_streams_.begin(); @@ -1101,19 +1044,19 @@ void WebRtcVideoChannel2::ConfigureReceiverRtp( } 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) { @@ -1336,6 +1279,7 @@ bool WebRtcVideoChannel2::SetSendRtpHeaderExtensions( return false; send_rtp_extensions_ = FilterRtpExtensions(extensions); + rtc::CritScope stream_lock(&stream_crit_); for (std::map<uint32, WebRtcVideoSendStream*>::iterator it = send_streams_.begin(); @@ -1353,8 +1297,13 @@ bool WebRtcVideoChannel2::SetMaxSendBandwidth(int bps) { } bool WebRtcVideoChannel2::SetOptions(const VideoOptions& options) { - LOG(LS_VERBOSE) << "SetOptions: " << options.ToString(); + LOG(LS_INFO) << "SetOptions: " << options.ToString(); + VideoOptions old_options = options_; options_.SetAll(options); + if (options_ == old_options) { + // No new options to set. + return true; + } rtc::CritScope stream_lock(&stream_crit_); for (std::map<uint32, WebRtcVideoSendStream*>::iterator it = send_streams_.begin(); @@ -1566,13 +1515,16 @@ bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetCapturer( LOG(LS_VERBOSE) << "Disabling capturer, sending black frame."; webrtc::I420VideoFrame black_frame; + // TODO(pbos): Base width/height on last_dimensions_. This will however + // fail the test AddRemoveCapturer which needs to be fixed to permit + // sending black frames in the same size that was previously sent. int width = format_.width; int height = format_.height; int half_width = (width + 1) / 2; black_frame.CreateEmptyFrame( width, height, width, half_width, half_width); SetWebRtcFrameToBlack(&black_frame); - SetDimensions(width, height, false); + SetDimensions(width, height, last_dimensions_.is_screencast); stream_->Input()->SwapFrame(&black_frame); } @@ -1699,13 +1651,17 @@ void WebRtcVideoChannel2::WebRtcVideoSendStream::DestroyVideoEncoder( void WebRtcVideoChannel2::WebRtcVideoSendStream::SetCodecAndOptions( const VideoCodecSettings& codec_settings, const VideoOptions& options) { - std::vector<webrtc::VideoStream> video_streams = - encoder_factory_->CreateVideoStreams( - codec_settings.codec, options, parameters_.config.rtp.ssrcs.size()); - if (video_streams.empty()) { + if (last_dimensions_.width == -1) { + last_dimensions_.width = codec_settings.codec.width; + last_dimensions_.height = codec_settings.codec.height; + last_dimensions_.is_screencast = false; + } + parameters_.encoder_config = + CreateVideoEncoderConfig(last_dimensions_, codec_settings.codec); + if (parameters_.encoder_config.streams.empty()) { return; } - parameters_.encoder_config.streams = video_streams; + format_ = VideoFormat(codec_settings.codec.width, codec_settings.codec.height, VideoFormat::FpsToInterval(30), @@ -1749,6 +1705,50 @@ void WebRtcVideoChannel2::WebRtcVideoSendStream::SetRtpExtensions( RecreateWebRtcStream(); } +webrtc::VideoEncoderConfig +WebRtcVideoChannel2::WebRtcVideoSendStream::CreateVideoEncoderConfig( + const Dimensions& dimensions, + const VideoCodec& codec) const { + webrtc::VideoEncoderConfig encoder_config; + if (dimensions.is_screencast) { + int screencast_min_bitrate_kbps; + parameters_.options.screencast_min_bitrate.Get( + &screencast_min_bitrate_kbps); + encoder_config.min_transmit_bitrate_bps = + screencast_min_bitrate_kbps * 1000; + encoder_config.content_type = webrtc::VideoEncoderConfig::kScreenshare; + } else { + encoder_config.min_transmit_bitrate_bps = 0; + encoder_config.content_type = webrtc::VideoEncoderConfig::kRealtimeVideo; + } + + // Restrict dimensions according to codec max. + int width = dimensions.width; + int height = dimensions.height; + if (!dimensions.is_screencast) { + if (codec.width < width) + width = codec.width; + if (codec.height < height) + height = codec.height; + } + + VideoCodec clamped_codec = codec; + clamped_codec.width = width; + clamped_codec.height = height; + + encoder_config.streams = encoder_factory_->CreateVideoStreams( + clamped_codec, parameters_.options, parameters_.config.rtp.ssrcs.size()); + + // Conference mode screencast uses 2 temporal layers split at 100kbit. + if (parameters_.options.conference_mode.GetWithDefaultIfUnset(false) && + dimensions.is_screencast && encoder_config.streams.size() == 1) { + encoder_config.streams[0].temporal_layer_thresholds_bps.clear(); + encoder_config.streams[0].temporal_layer_thresholds_bps.push_back( + kConferenceModeTemporalLayerBitrateBps); + } + return encoder_config; +} + void WebRtcVideoChannel2::WebRtcVideoSendStream::SetDimensions( int width, int height, @@ -1758,56 +1758,25 @@ void WebRtcVideoChannel2::WebRtcVideoSendStream::SetDimensions( // Configured using the same parameters, do not reconfigure. return; } + LOG(LS_INFO) << "SetDimensions: " << width << "x" << height + << (is_screencast ? " (screencast)" : " (not screencast)"); last_dimensions_.width = width; last_dimensions_.height = height; last_dimensions_.is_screencast = is_screencast; assert(!parameters_.encoder_config.streams.empty()); - LOG(LS_VERBOSE) << "SetDimensions: " << width << "x" << height; VideoCodecSettings codec_settings; parameters_.codec_settings.Get(&codec_settings); - // Restrict dimensions according to codec max. - if (!is_screencast) { - if (codec_settings.codec.width < width) - width = codec_settings.codec.width; - if (codec_settings.codec.height < height) - height = codec_settings.codec.height; - } - webrtc::VideoEncoderConfig encoder_config = parameters_.encoder_config; + webrtc::VideoEncoderConfig encoder_config = + CreateVideoEncoderConfig(last_dimensions_, codec_settings.codec); + encoder_config.encoder_specific_settings = encoder_factory_->CreateVideoEncoderSettings(codec_settings.codec, parameters_.options); - if (is_screencast) { - int screencast_min_bitrate_kbps; - parameters_.options.screencast_min_bitrate.Get( - &screencast_min_bitrate_kbps); - encoder_config.min_transmit_bitrate_bps = - screencast_min_bitrate_kbps * 1000; - encoder_config.content_type = webrtc::VideoEncoderConfig::kScreenshare; - } else { - encoder_config.min_transmit_bitrate_bps = 0; - encoder_config.content_type = webrtc::VideoEncoderConfig::kRealtimeVideo; - } - - VideoCodec codec = codec_settings.codec; - codec.width = width; - codec.height = height; - - encoder_config.streams = encoder_factory_->CreateVideoStreams( - codec, parameters_.options, parameters_.config.rtp.ssrcs.size()); - - // Conference mode screencast uses 2 temporal layers split at 100kbit. - if (parameters_.options.conference_mode.GetWithDefaultIfUnset(false) && - is_screencast && encoder_config.streams.size() == 1) { - encoder_config.streams[0].temporal_layer_thresholds_bps.clear(); - encoder_config.streams[0].temporal_layer_thresholds_bps.push_back( - kConferenceModeTemporalLayerBitrateBps); - } - bool stream_reconfigured = stream_->ReconfigureVideoEncoder(encoder_config); encoder_factory_->DestroyVideoEncoderSettings( @@ -2137,6 +2106,14 @@ WebRtcVideoChannel2::WebRtcVideoReceiveStream::GetVideoReceiverInfo() { WebRtcVideoChannel2::VideoCodecSettings::VideoCodecSettings() : rtx_payload_type(-1) {} +bool WebRtcVideoChannel2::VideoCodecSettings::operator==( + const WebRtcVideoChannel2::VideoCodecSettings& other) const { + return codec == other.codec && + fec.ulpfec_payload_type == other.fec.ulpfec_payload_type && + fec.red_payload_type == other.fec.red_payload_type && + rtx_payload_type == other.rtx_payload_type; +} + std::vector<WebRtcVideoChannel2::VideoCodecSettings> WebRtcVideoChannel2::MapCodecs(const std::vector<VideoCodec>& codecs) { assert(!codecs.empty()); diff --git a/media/webrtc/webrtcvideoengine2.h b/media/webrtc/webrtcvideoengine2.h index 299ac35..9a5fe65 100644 --- a/media/webrtc/webrtcvideoengine2.h +++ b/media/webrtc/webrtcvideoengine2.h @@ -145,7 +145,6 @@ class WebRtcVideoEngine2 : public sigslot::has_slots<> { int GetCapabilities(); bool SetDefaultEncoderConfig(const VideoEncoderConfig& config); - VideoEncoderConfig GetDefaultEncoderConfig() const; WebRtcVideoChannel2* CreateChannel(const VideoOptions& options, VoiceMediaChannel* voice_channel); @@ -281,6 +280,8 @@ class WebRtcVideoChannel2 : public rtc::MessageHandler, struct VideoCodecSettings { VideoCodecSettings(); + bool operator ==(const VideoCodecSettings& other) const; + VideoCodec codec; webrtc::FecConfig fec; int rtx_payload_type; @@ -349,8 +350,8 @@ class WebRtcVideoChannel2 : public rtc::MessageHandler, bool external; }; - struct LastDimensions { - LastDimensions() : width(-1), height(-1), is_screencast(false) {} + struct Dimensions { + Dimensions() : width(-1), height(-1), is_screencast(false) {} int width; int height; bool is_screencast; @@ -358,23 +359,28 @@ class WebRtcVideoChannel2 : public rtc::MessageHandler, AllocatedEncoder CreateVideoEncoder(const VideoCodec& codec) EXCLUSIVE_LOCKS_REQUIRED(lock_); - void DestroyVideoEncoder(AllocatedEncoder* encoder); + void DestroyVideoEncoder(AllocatedEncoder* encoder) + EXCLUSIVE_LOCKS_REQUIRED(lock_); void SetCodecAndOptions(const VideoCodecSettings& codec, const VideoOptions& options) EXCLUSIVE_LOCKS_REQUIRED(lock_); void RecreateWebRtcStream() EXCLUSIVE_LOCKS_REQUIRED(lock_); + webrtc::VideoEncoderConfig CreateVideoEncoderConfig( + const Dimensions& dimensions, + const VideoCodec& codec) const EXCLUSIVE_LOCKS_REQUIRED(lock_); void SetDimensions(int width, int height, bool is_screencast) EXCLUSIVE_LOCKS_REQUIRED(lock_); webrtc::Call* const call_; - WebRtcVideoEncoderFactory* const external_encoder_factory_; - WebRtcVideoEncoderFactory2* const encoder_factory_; + WebRtcVideoEncoderFactory* const external_encoder_factory_ + GUARDED_BY(lock_); + WebRtcVideoEncoderFactory2* const encoder_factory_ GUARDED_BY(lock_); rtc::CriticalSection lock_; webrtc::VideoSendStream* stream_ GUARDED_BY(lock_); VideoSendStreamParameters parameters_ GUARDED_BY(lock_); AllocatedEncoder allocated_encoder_ GUARDED_BY(lock_); - LastDimensions last_dimensions_ GUARDED_BY(lock_); + Dimensions last_dimensions_ GUARDED_BY(lock_); VideoCapturer* capturer_ GUARDED_BY(lock_); bool sending_ GUARDED_BY(lock_); diff --git a/media/webrtc/webrtcvoiceengine.cc b/media/webrtc/webrtcvoiceengine.cc index 95e16e4..74b3163 100644 --- a/media/webrtc/webrtcvoiceengine.cc +++ b/media/webrtc/webrtcvoiceengine.cc @@ -74,7 +74,7 @@ static const CodecPref kCodecPrefs[] = { { "ISAC", 32000, 1, 104, true }, { "CELT", 32000, 1, 109, true }, { "CELT", 32000, 2, 110, true }, - { "G722", 16000, 1, 9, false }, + { "G722", 8000, 1, 9, false }, { "ILBC", 8000, 1, 102, false }, { "PCMU", 8000, 1, 0, false }, { "PCMA", 8000, 1, 8, false }, @@ -110,6 +110,7 @@ static const int kDefaultAudioDeviceId = 0; static const char kIsacCodecName[] = "ISAC"; static const char kL16CodecName[] = "L16"; +static const char kG722CodecName[] = "G722"; // Parameter used for NACK. // This value is equivalent to 5 seconds of audio data at 20 ms per packet. @@ -485,12 +486,24 @@ static void GetOpusConfig(const AudioCodec& codec, webrtc::CodecInst* voe_codec, voe_codec->rate = GetOpusBitrate(codec, *max_playback_rate); } +// Changes RTP timestamp rate of G722. This is due to the "bug" in the RFC +// which says that G722 should be advertised as 8 kHz although it is a 16 kHz +// codec. +static void MaybeFixupG722(webrtc::CodecInst* voe_codec, int new_plfreq) { + if (_stricmp(voe_codec->plname, kG722CodecName) == 0) { + // If the ASSERT triggers, the codec definition in WebRTC VoiceEngine + // has changed, and this special case is no longer needed. + ASSERT(voe_codec->plfreq != new_plfreq); + voe_codec->plfreq = new_plfreq; + } +} + void WebRtcVoiceEngine::ConstructCodecs() { LOG(LS_INFO) << "WebRtc VoiceEngine codecs:"; int ncodecs = voe_wrapper_->codec()->NumOfCodecs(); for (int i = 0; i < ncodecs; ++i) { webrtc::CodecInst voe_codec; - if (voe_wrapper_->codec()->GetCodec(i, voe_codec) != -1) { + if (GetVoeCodec(i, voe_codec)) { // Skip uncompressed formats. if (_stricmp(voe_codec.plname, kL16CodecName) == 0) { continue; @@ -540,6 +553,15 @@ void WebRtcVoiceEngine::ConstructCodecs() { std::sort(codecs_.begin(), codecs_.end(), &AudioCodec::Preferable); } +bool WebRtcVoiceEngine::GetVoeCodec(int index, webrtc::CodecInst& codec) { + if (voe_wrapper_->codec()->GetCodec(index, codec) != -1) { + // Change the sample rate of G722 to 8000 to match SDP. + MaybeFixupG722(&codec, 8000); + return true; + } + return false; +} + WebRtcVoiceEngine::~WebRtcVoiceEngine() { LOG(LS_VERBOSE) << "WebRtcVoiceEngine::~WebRtcVoiceEngine"; if (voe_wrapper_->base()->DeRegisterVoiceEngineObserver() == -1) { @@ -1224,7 +1246,7 @@ bool WebRtcVoiceEngine::FindWebRtcCodec(const AudioCodec& in, int ncodecs = voe_wrapper_->codec()->NumOfCodecs(); for (int i = 0; i < ncodecs; ++i) { webrtc::CodecInst voe_codec; - if (voe_wrapper_->codec()->GetCodec(i, voe_codec) != -1) { + if (GetVoeCodec(i, voe_codec)) { AudioCodec codec(voe_codec.pltype, voe_codec.plname, voe_codec.plfreq, voe_codec.rate, voe_codec.channels, 0); bool multi_rate = IsCodecMultiRate(voe_codec); @@ -1243,6 +1265,9 @@ bool WebRtcVoiceEngine::FindWebRtcCodec(const AudioCodec& in, voe_codec.rate = in.bitrate; } + // Reset G722 sample rate to 16000 to match WebRTC. + MaybeFixupG722(&voe_codec, 16000); + // Apply codec-specific settings. if (IsIsac(codec)) { // If ISAC and an explicit bitrate is not specified, diff --git a/media/webrtc/webrtcvoiceengine.h b/media/webrtc/webrtcvoiceengine.h index f19059b..34b9f3c 100644 --- a/media/webrtc/webrtcvoiceengine.h +++ b/media/webrtc/webrtcvoiceengine.h @@ -199,6 +199,7 @@ class WebRtcVoiceEngine void Construct(); void ConstructCodecs(); + bool GetVoeCodec(int index, webrtc::CodecInst& codec); bool InitInternal(); bool EnsureSoundclipEngineInit(); void SetTraceFilter(int filter); diff --git a/media/webrtc/webrtcvoiceengine_unittest.cc b/media/webrtc/webrtcvoiceengine_unittest.cc index 5deabd2..5eb6e24 100644 --- a/media/webrtc/webrtcvoiceengine_unittest.cc +++ b/media/webrtc/webrtcvoiceengine_unittest.cc @@ -52,14 +52,16 @@ static const cricket::AudioCodec kPcmuCodec(0, "PCMU", 8000, 64000, 1, 0); static const cricket::AudioCodec kIsacCodec(103, "ISAC", 16000, 32000, 1, 0); static const cricket::AudioCodec kCeltCodec(110, "CELT", 32000, 64000, 2, 0); static const cricket::AudioCodec kOpusCodec(111, "opus", 48000, 64000, 2, 0); +static const cricket::AudioCodec kG722CodecVoE(9, "G722", 16000, 64000, 1, 0); +static const cricket::AudioCodec kG722CodecSdp(9, "G722", 8000, 64000, 1, 0); static const cricket::AudioCodec kRedCodec(117, "red", 8000, 0, 1, 0); static const cricket::AudioCodec kCn8000Codec(13, "CN", 8000, 0, 1, 0); static const cricket::AudioCodec kCn16000Codec(105, "CN", 16000, 0, 1, 0); static const cricket::AudioCodec kTelephoneEventCodec(106, "telephone-event", 8000, 0, 1, 0); static const cricket::AudioCodec* const kAudioCodecs[] = { - &kPcmuCodec, &kIsacCodec, &kCeltCodec, &kOpusCodec, &kRedCodec, - &kCn8000Codec, &kCn16000Codec, &kTelephoneEventCodec, + &kPcmuCodec, &kIsacCodec, &kCeltCodec, &kOpusCodec, &kG722CodecVoE, + &kRedCodec, &kCn8000Codec, &kCn16000Codec, &kTelephoneEventCodec, }; const char kRingbackTone[] = "RIFF____WAVE____ABCD1234"; static uint32 kSsrc1 = 0x99; @@ -770,6 +772,20 @@ TEST_F(WebRtcVoiceEngineTestFake, DontResetSetSendCodec) { EXPECT_EQ(1, voe_.GetNumSetSendCodecs()); } +// Verify that G722 is set with 16000 samples per second to WebRTC. +TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecG722) { + EXPECT_TRUE(SetupEngine()); + int channel_num = voe_.GetLastChannel(); + std::vector<cricket::AudioCodec> codecs; + codecs.push_back(kG722CodecSdp); + EXPECT_TRUE(channel_->SetSendCodecs(codecs)); + webrtc::CodecInst gcodec; + EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec)); + EXPECT_STREQ("G722", gcodec.plname); + EXPECT_EQ(1, gcodec.channels); + EXPECT_EQ(16000, gcodec.plfreq); +} + // Test that if clockrate is not 48000 for opus, we fail. TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecOpusBadClockrate) { EXPECT_TRUE(SetupEngine()); @@ -3208,7 +3224,7 @@ TEST(WebRtcVoiceEngineTest, HasCorrectCodecs) { EXPECT_TRUE(engine.FindCodec( cricket::AudioCodec(96, "PCMA", 8000, 0, 1, 0))); EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(96, "G722", 16000, 0, 1, 0))); + cricket::AudioCodec(96, "G722", 8000, 0, 1, 0))); EXPECT_TRUE(engine.FindCodec( cricket::AudioCodec(96, "red", 8000, 0, 1, 0))); EXPECT_TRUE(engine.FindCodec( @@ -3225,7 +3241,7 @@ TEST(WebRtcVoiceEngineTest, HasCorrectCodecs) { EXPECT_TRUE(engine.FindCodec( cricket::AudioCodec(8, "", 8000, 0, 1, 0))); // PCMA EXPECT_TRUE(engine.FindCodec( - cricket::AudioCodec(9, "", 16000, 0, 1, 0))); // G722 + cricket::AudioCodec(9, "", 8000, 0, 1, 0))); // G722 EXPECT_TRUE(engine.FindCodec( cricket::AudioCodec(13, "", 8000, 0, 1, 0))); // CN // Check sample/bitrate matching. @@ -3248,7 +3264,7 @@ TEST(WebRtcVoiceEngineTest, HasCorrectCodecs) { EXPECT_EQ(103, it->id); } else if (it->name == "ISAC" && it->clockrate == 32000) { EXPECT_EQ(104, it->id); - } else if (it->name == "G722" && it->clockrate == 16000) { + } else if (it->name == "G722" && it->clockrate == 8000) { EXPECT_EQ(9, it->id); } else if (it->name == "telephone-event") { EXPECT_EQ(126, it->id); |