diff --git a/talk/media/webrtc/constants.h b/talk/media/webrtc/constants.h index 5390c0d51..821a41f20 100755 --- a/talk/media/webrtc/constants.h +++ b/talk/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/talk/media/webrtc/webrtcvideoengine.cc b/talk/media/webrtc/webrtcvideoengine.cc index 6dacadd15..46d316f8f 100644 --- a/talk/media/webrtc/webrtcvideoengine.cc +++ b/talk/media/webrtc/webrtcvideoengine.cc @@ -55,6 +55,7 @@ #include "webrtc/base/basictypes.h" #include "webrtc/base/buffer.h" #include "webrtc/base/byteorder.h" +#include "webrtc/base/checks.h" #include "webrtc/base/common.h" #include "webrtc/base/cpumonitor.h" #include "webrtc/base/logging.h" @@ -106,7 +107,10 @@ const 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)); } -// Returns true if Receiver Estimated Max Bitrate is enabled. -static bool IsRembEnabled(const VideoCodec& codec) { - return codec.HasFeedbackParam(FeedbackParam(kRtcpFbParamRemb, - kParamValueEmpty)); +bool IsRembEnabled(const VideoCodec& codec) { + return codec.HasFeedbackParam( + FeedbackParam(kRtcpFbParamRemb, kParamValueEmpty)); +} + +void AddDefaultFeedbackParams(VideoCodec* codec) { + codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamCcm, kRtcpFbCcmParamFir)); + codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamNack, kParamValueEmpty)); + codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamNack, kRtcpFbNackParamPli)); + codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamRemb, kParamValueEmpty)); +} + +bool CodecNameMatches(const std::string& name1, const std::string& name2) { + return _stricmp(name1.c_str(), name2.c_str()) == 0; +} + +static VideoCodec MakeVideoCodecWithDefaultFeedbackParams(int payload_type, + const char* name) { + VideoCodec codec(payload_type, name, kDefaultVideoMaxWidth, + kDefaultVideoMaxHeight, kDefaultVideoMaxFramerate, 0); + AddDefaultFeedbackParams(&codec); + return codec; +} + +static VideoCodec MakeVideoCodec(int payload_type, const char* name) { + return VideoCodec(payload_type, name, 0, 0, 0, 0); +} + +static VideoCodec MakeRtxCodec(int payload_type, int associated_payload_type) { + return VideoCodec::CreateRtxCodec(payload_type, associated_payload_type); +} + +bool CodecIsInternallySupported(const std::string& codec_name) { + if (CodecNameMatches(codec_name, kVp8CodecName)) { + return true; + } + return false; +} + +std::vector DefaultVideoCodecList() { + std::vector 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. @@ -1214,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; } @@ -1428,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. @@ -1448,27 +1464,17 @@ bool WebRtcVideoEngine::RebuildCodecList(const VideoCodec& in_codec) { video_codecs_.clear(); - bool found = false; std::set 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(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& codecs = encoder_factory_->codecs(); @@ -1476,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(i)), codecs[i].name, @@ -1492,7 +1496,6 @@ bool WebRtcVideoEngine::RebuildCodecList(const VideoCodec& in_codec) { } } } - ASSERT(found); return true; } @@ -1598,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/talk/media/webrtc/webrtcvideoengine.h b/talk/media/webrtc/webrtcvideoengine.h index d577b4bdf..db091afac 100644 --- a/talk/media/webrtc/webrtcvideoengine.h +++ b/talk/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 DefaultVideoCodecList(); +bool CodecNameMatches(const std::string& name1, const std::string& name2); +bool CodecIsInternallySupported(const std::string& codec_name); +bool IsNackEnabled(const VideoCodec& codec); +bool IsRembEnabled(const VideoCodec& codec); +void AddDefaultFeedbackParams(VideoCodec* codec); + class WebRtcVideoEngine : public sigslot::has_slots<>, public webrtc::TraceCallback { public: @@ -187,18 +196,6 @@ class WebRtcVideoEngine : public sigslot::has_slots<>, private: typedef std::vector VideoChannels; - struct VideoCodecPref { - const char* name; - int payload_type; - // For RTX, this field is the payload-type that RTX applies to. - // For other codecs, it should be set to -1. - int associated_payload_type; - int pref; - }; - - static const VideoCodecPref kVideoCodecPrefs[]; - static const VideoFormatPod kVideoFormats[]; - static const VideoFormatPod kDefaultMaxVideoFormat; void Construct(ViEWrapper* vie_wrapper, ViETraceWrapper* tracing, @@ -225,6 +222,7 @@ class WebRtcVideoEngine : public sigslot::has_slots<>, WebRtcVideoEncoderFactory* encoder_factory_; WebRtcVideoDecoderFactory* decoder_factory_; std::vector video_codecs_; + std::vector default_video_codec_list_; std::vector rtp_header_extensions_; VideoFormat default_codec_format_; diff --git a/talk/media/webrtc/webrtcvideoengine2.cc b/talk/media/webrtc/webrtcvideoengine2.cc index a641a58a0..8d53f1708 100644 --- a/talk/media/webrtc/webrtcvideoengine2.cc +++ b/talk/media/webrtc/webrtcvideoengine2.cc @@ -36,6 +36,7 @@ #include "talk/media/base/videorenderer.h" #include "talk/media/webrtc/constants.h" #include "talk/media/webrtc/webrtcvideocapturer.h" +#include "talk/media/webrtc/webrtcvideoengine.h" #include "talk/media/webrtc/webrtcvideoframe.h" #include "talk/media/webrtc/webrtcvoiceengine.h" #include "webrtc/base/buffer.h" @@ -51,26 +52,6 @@ namespace cricket { namespace { - -static bool CodecNameMatches(const std::string& name1, - const std::string& name2) { - return _stricmp(name1.c_str(), name2.c_str()) == 0; -} - -const char* kInternallySupportedCodecs[] = { - kVp8CodecName, -}; - -// True if codec is supported by a software implementation that's always -// available. -static bool CodecIsInternallySupported(const std::string& codec_name) { - for (size_t i = 0; i < ARRAY_SIZE(kInternallySupportedCodecs); ++i) { - if (CodecNameMatches(codec_name, kInternallySupportedCodecs[i])) - return true; - } - return false; -} - static std::string CodecVectorToString(const std::vector& 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& codecs, const VideoCodec& requested_codec, VideoCodec* matching_codec) { @@ -160,59 +153,6 @@ static bool FindFirstMatchingCodec(const std::vector& 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 DefaultVideoCodecs() { - std::vector 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& extensions) { std::set extensions_used; @@ -258,7 +198,7 @@ std::vector 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)), @@ -571,7 +511,7 @@ WebRtcVideoEncoderFactory2* WebRtcVideoEngine2::GetVideoEncoderFactory() { } std::vector WebRtcVideoEngine2::GetSupportedCodecs() const { - std::vector supported_codecs = DefaultVideoCodecs(); + std::vector supported_codecs = DefaultVideoCodecList(); if (external_encoder_factory_ == NULL) { return supported_codecs; @@ -1097,19 +1037,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) {