2014-05-15 09:35:06 +00:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2014 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 "webrtc/config.h"
|
|
|
|
|
|
|
|
|
|
#include <sstream>
|
|
|
|
|
#include <string>
|
|
|
|
|
|
2016-09-27 03:52:02 -07:00
|
|
|
#include "webrtc/base/checks.h"
|
|
|
|
|
|
2014-05-15 09:35:06 +00:00
|
|
|
namespace webrtc {
|
2016-06-14 10:02:41 -07:00
|
|
|
std::string NackConfig::ToString() const {
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
ss << "{rtp_history_ms: " << rtp_history_ms;
|
|
|
|
|
ss << '}';
|
|
|
|
|
return ss.str();
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-04 23:28:39 -07:00
|
|
|
std::string UlpfecConfig::ToString() const {
|
2014-05-15 09:35:06 +00:00
|
|
|
std::stringstream ss;
|
|
|
|
|
ss << "{ulpfec_payload_type: " << ulpfec_payload_type;
|
|
|
|
|
ss << ", red_payload_type: " << red_payload_type;
|
2016-02-03 13:29:59 +01:00
|
|
|
ss << ", red_rtx_payload_type: " << red_rtx_payload_type;
|
2014-05-15 09:35:06 +00:00
|
|
|
ss << '}';
|
|
|
|
|
return ss.str();
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-22 02:16:47 -08:00
|
|
|
bool UlpfecConfig::operator==(const UlpfecConfig& other) const {
|
|
|
|
|
return ulpfec_payload_type == other.ulpfec_payload_type &&
|
|
|
|
|
red_payload_type == other.red_payload_type &&
|
|
|
|
|
red_rtx_payload_type == other.red_rtx_payload_type;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-15 09:35:06 +00:00
|
|
|
std::string RtpExtension::ToString() const {
|
|
|
|
|
std::stringstream ss;
|
2016-05-26 11:24:55 -07:00
|
|
|
ss << "{uri: " << uri;
|
2014-05-15 09:35:06 +00:00
|
|
|
ss << ", id: " << id;
|
|
|
|
|
ss << '}';
|
|
|
|
|
return ss.str();
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-26 11:24:55 -07:00
|
|
|
const char* RtpExtension::kAudioLevelUri =
|
2015-04-29 15:24:01 +02:00
|
|
|
"urn:ietf:params:rtp-hdrext:ssrc-audio-level";
|
2016-05-26 11:24:55 -07:00
|
|
|
const int RtpExtension::kAudioLevelDefaultId = 1;
|
|
|
|
|
|
|
|
|
|
const char* RtpExtension::kTimestampOffsetUri =
|
|
|
|
|
"urn:ietf:params:rtp-hdrext:toffset";
|
|
|
|
|
const int RtpExtension::kTimestampOffsetDefaultId = 2;
|
|
|
|
|
|
|
|
|
|
const char* RtpExtension::kAbsSendTimeUri =
|
|
|
|
|
"http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
|
|
|
|
|
const int RtpExtension::kAbsSendTimeDefaultId = 3;
|
|
|
|
|
|
|
|
|
|
const char* RtpExtension::kVideoRotationUri = "urn:3gpp:video-orientation";
|
|
|
|
|
const int RtpExtension::kVideoRotationDefaultId = 4;
|
|
|
|
|
|
|
|
|
|
const char* RtpExtension::kTransportSequenceNumberUri =
|
2016-03-01 16:27:20 +01:00
|
|
|
"http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01";
|
2016-05-26 11:24:55 -07:00
|
|
|
const int RtpExtension::kTransportSequenceNumberDefaultId = 5;
|
2015-04-29 15:24:01 +02:00
|
|
|
|
2017-04-11 10:34:31 -07:00
|
|
|
const char* RtpExtension::kVideoContentTypeUri =
|
|
|
|
|
"http://www.webrtc.org/experiments/rtp-hdrext/video-content-type";
|
|
|
|
|
const int RtpExtension::kVideoContentTypeDefaultId = 6;
|
|
|
|
|
|
2016-06-08 00:24:21 -07:00
|
|
|
// This extension allows applications to adaptively limit the playout delay
|
|
|
|
|
// on frames as per the current needs. For example, a gaming application
|
|
|
|
|
// has very different needs on end-to-end delay compared to a video-conference
|
|
|
|
|
// application.
|
|
|
|
|
const char* RtpExtension::kPlayoutDelayUri =
|
|
|
|
|
"http://www.webrtc.org/experiments/rtp-hdrext/playout-delay";
|
|
|
|
|
const int RtpExtension::kPlayoutDelayDefaultId = 6;
|
|
|
|
|
|
2017-02-25 18:15:09 -08:00
|
|
|
const int RtpExtension::kMinId = 1;
|
|
|
|
|
const int RtpExtension::kMaxId = 14;
|
|
|
|
|
|
2016-05-26 11:24:55 -07:00
|
|
|
bool RtpExtension::IsSupportedForAudio(const std::string& uri) {
|
2016-11-17 06:26:52 -08:00
|
|
|
return uri == webrtc::RtpExtension::kAudioLevelUri ||
|
2016-05-26 11:24:55 -07:00
|
|
|
uri == webrtc::RtpExtension::kTransportSequenceNumberUri;
|
2015-04-29 15:24:01 +02:00
|
|
|
}
|
|
|
|
|
|
2016-05-26 11:24:55 -07:00
|
|
|
bool RtpExtension::IsSupportedForVideo(const std::string& uri) {
|
|
|
|
|
return uri == webrtc::RtpExtension::kTimestampOffsetUri ||
|
|
|
|
|
uri == webrtc::RtpExtension::kAbsSendTimeUri ||
|
|
|
|
|
uri == webrtc::RtpExtension::kVideoRotationUri ||
|
2016-06-08 00:24:21 -07:00
|
|
|
uri == webrtc::RtpExtension::kTransportSequenceNumberUri ||
|
2017-04-11 10:34:31 -07:00
|
|
|
uri == webrtc::RtpExtension::kPlayoutDelayUri ||
|
|
|
|
|
uri == webrtc::RtpExtension::kVideoContentTypeUri;
|
2015-04-29 15:24:01 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-26 13:59:22 +00:00
|
|
|
VideoStream::VideoStream()
|
|
|
|
|
: width(0),
|
|
|
|
|
height(0),
|
|
|
|
|
max_framerate(-1),
|
|
|
|
|
min_bitrate_bps(-1),
|
|
|
|
|
target_bitrate_bps(-1),
|
|
|
|
|
max_bitrate_bps(-1),
|
|
|
|
|
max_qp(-1) {}
|
|
|
|
|
|
|
|
|
|
VideoStream::~VideoStream() = default;
|
|
|
|
|
|
2014-05-15 09:35:06 +00:00
|
|
|
std::string VideoStream::ToString() const {
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
ss << "{width: " << width;
|
|
|
|
|
ss << ", height: " << height;
|
|
|
|
|
ss << ", max_framerate: " << max_framerate;
|
|
|
|
|
ss << ", min_bitrate_bps:" << min_bitrate_bps;
|
|
|
|
|
ss << ", target_bitrate_bps:" << target_bitrate_bps;
|
|
|
|
|
ss << ", max_bitrate_bps:" << max_bitrate_bps;
|
|
|
|
|
ss << ", max_qp: " << max_qp;
|
|
|
|
|
|
2014-11-06 09:35:08 +00:00
|
|
|
ss << ", temporal_layer_thresholds_bps: [";
|
2014-10-31 13:08:10 +00:00
|
|
|
for (size_t i = 0; i < temporal_layer_thresholds_bps.size(); ++i) {
|
|
|
|
|
ss << temporal_layer_thresholds_bps[i];
|
|
|
|
|
if (i != temporal_layer_thresholds_bps.size() - 1)
|
2014-11-06 09:35:08 +00:00
|
|
|
ss << ", ";
|
2014-05-15 09:35:06 +00:00
|
|
|
}
|
2014-11-06 09:35:08 +00:00
|
|
|
ss << ']';
|
2014-05-15 09:35:06 +00:00
|
|
|
|
|
|
|
|
ss << '}';
|
|
|
|
|
return ss.str();
|
|
|
|
|
}
|
2014-10-24 09:23:21 +00:00
|
|
|
|
2015-02-26 13:59:22 +00:00
|
|
|
VideoEncoderConfig::VideoEncoderConfig()
|
2015-04-28 10:01:41 +02:00
|
|
|
: content_type(ContentType::kRealtimeVideo),
|
2016-09-27 03:52:02 -07:00
|
|
|
encoder_specific_settings(nullptr),
|
Avoid unnecessary HW video encoder reconfiguration
This change reduces the number of times the Android hardware video
encoder is reconfigured when making an outgoing call. With this change,
the encoder should only be initialized once as opposed to the ~3 times
it happens currently.
Before the fix, the following sequence of events caused the extra
reconfigurations:
1. After the SetLocalDescription call, the WebRtcVideoSendStream is created.
All frames from the camera are dropped until the corresponding
VideoSendStream is created.
2. SetRemoteDescription() triggers the VideoSendStream creation. At
this point, the encoder is configured for the first time, with the
frame dimensions set to a low resolution default (176x144).
3. When the first video frame is received from the camera after the
VideoSendStreamIsCreated, the encoder is reconfigured to the correct
dimensions. If we are using the Android hardware encoder, the default
configuration is set to encode from a memory buffer (use_surface=false).
4. When the frame is passed down to the encoder in
androidmediaencoder_jni.cc EncodeOnCodecThread(), it may be stored in
a texture instead of a memory buffer. In this case, yet another
reconfiguration takes place to enable encoding from a texture.
5. Even if the resolution and texture flag were known at the start of
the call, there would be a reconfiguration involved if the camera is
rotated (such as when making a call from a phone in portrait orientation).
The reason for that is that at construction time, WebRtcVideoEngine2
sets the VideoSinkWants structure parameter to request frames rotated
by the source; the early frames will then arrive in portrait resolution.
When the remote description is finally set, if the rotation RTP extension
is supported by the remote receiver, the source is asked to provide
non-rotated frames. The very next frame will then arrive in landscape
resolution with a non-zero rotation value to be applied by the receiver.
Since the encoder was configured with the last (portrait) frame size,
it's going to need to be reconfigured again.
The fix makes the following changes:
1. WebRtcVideoSendStream::OnFrame() now caches the last seen frame
dimensions, and whether the frame was stored in a texture.
2. When the encoder is configured the first time
(WebRtcVideoSendStream::SetCodec()) - the last seen frame dimensions
are used instead of the default dimensions.
3. A flag that indicates if encoding is to be done from a texture has
been added to the webrtc::VideoStream and webrtc::VideoCodec structs,
and it's been wired up to be passed down all the way to the JNI code in
androidmediaencoder_jni.cc.
4. MediaCodecVideoEncoder::InitEncode is now reading the is_surface
flag from the VideoCodec structure instead of guessing the default as
false. This way we end up with the correct encoder configuration the
first time around.
5. WebRtcVideoSendStream now takes an optimistic guess and requests non-
rotated frames when the supported RtpExtensions list is not available.
This makes the "early" frames arrive non-rotated, and the cached dimensions
will be correct for the common case when the rotation extension is supported.
If the other side is an older endpoint which does not support rotation,
the encoder will have to be reconfigured - but it's better to penalize the
uncommon case rather than the common one.
Review-Url: https://codereview.webrtc.org/2067103002
Cr-Commit-Position: refs/heads/master@{#13173}
2016-06-16 12:08:03 -07:00
|
|
|
min_transmit_bitrate_bps(0),
|
2016-10-02 23:45:26 -07:00
|
|
|
max_bitrate_bps(0),
|
|
|
|
|
number_of_streams(0) {}
|
2015-02-26 13:59:22 +00:00
|
|
|
|
2016-10-25 11:19:07 -07:00
|
|
|
VideoEncoderConfig::VideoEncoderConfig(VideoEncoderConfig&&) = default;
|
|
|
|
|
|
2015-02-26 13:59:22 +00:00
|
|
|
VideoEncoderConfig::~VideoEncoderConfig() = default;
|
|
|
|
|
|
2014-10-24 09:23:21 +00:00
|
|
|
std::string VideoEncoderConfig::ToString() const {
|
|
|
|
|
std::stringstream ss;
|
2016-10-02 23:45:26 -07:00
|
|
|
ss << "{content_type: ";
|
2014-10-24 09:23:21 +00:00
|
|
|
switch (content_type) {
|
2015-04-28 10:01:41 +02:00
|
|
|
case ContentType::kRealtimeVideo:
|
2014-10-24 09:23:21 +00:00
|
|
|
ss << "kRealtimeVideo";
|
|
|
|
|
break;
|
2015-04-28 10:01:41 +02:00
|
|
|
case ContentType::kScreen:
|
2014-10-24 09:23:21 +00:00
|
|
|
ss << "kScreenshare";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
ss << ", encoder_specific_settings: ";
|
|
|
|
|
ss << (encoder_specific_settings != NULL ? "(ptr)" : "NULL");
|
|
|
|
|
|
|
|
|
|
ss << ", min_transmit_bitrate_bps: " << min_transmit_bitrate_bps;
|
|
|
|
|
ss << '}';
|
|
|
|
|
return ss.str();
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-25 11:19:07 -07:00
|
|
|
VideoEncoderConfig::VideoEncoderConfig(const VideoEncoderConfig&) = default;
|
|
|
|
|
|
2016-09-27 03:52:02 -07:00
|
|
|
void VideoEncoderConfig::EncoderSpecificSettings::FillEncoderSpecificSettings(
|
|
|
|
|
VideoCodec* codec) const {
|
|
|
|
|
if (codec->codecType == kVideoCodecH264) {
|
2016-11-16 23:23:04 -08:00
|
|
|
FillVideoCodecH264(codec->H264());
|
2016-09-27 03:52:02 -07:00
|
|
|
} else if (codec->codecType == kVideoCodecVP8) {
|
2016-11-16 23:23:04 -08:00
|
|
|
FillVideoCodecVp8(codec->VP8());
|
2016-09-27 03:52:02 -07:00
|
|
|
} else if (codec->codecType == kVideoCodecVP9) {
|
2016-11-16 23:23:04 -08:00
|
|
|
FillVideoCodecVp9(codec->VP9());
|
2016-09-27 03:52:02 -07:00
|
|
|
} else {
|
|
|
|
|
RTC_NOTREACHED() << "Encoder specifics set/used for unknown codec type.";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VideoEncoderConfig::EncoderSpecificSettings::FillVideoCodecH264(
|
|
|
|
|
VideoCodecH264* h264_settings) const {
|
|
|
|
|
RTC_NOTREACHED();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VideoEncoderConfig::EncoderSpecificSettings::FillVideoCodecVp8(
|
|
|
|
|
VideoCodecVP8* vp8_settings) const {
|
|
|
|
|
RTC_NOTREACHED();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VideoEncoderConfig::EncoderSpecificSettings::FillVideoCodecVp9(
|
|
|
|
|
VideoCodecVP9* vp9_settings) const {
|
|
|
|
|
RTC_NOTREACHED();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VideoEncoderConfig::H264EncoderSpecificSettings::H264EncoderSpecificSettings(
|
|
|
|
|
const VideoCodecH264& specifics)
|
|
|
|
|
: specifics_(specifics) {}
|
|
|
|
|
|
|
|
|
|
void VideoEncoderConfig::H264EncoderSpecificSettings::FillVideoCodecH264(
|
|
|
|
|
VideoCodecH264* h264_settings) const {
|
|
|
|
|
*h264_settings = specifics_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VideoEncoderConfig::Vp8EncoderSpecificSettings::Vp8EncoderSpecificSettings(
|
|
|
|
|
const VideoCodecVP8& specifics)
|
|
|
|
|
: specifics_(specifics) {}
|
|
|
|
|
|
|
|
|
|
void VideoEncoderConfig::Vp8EncoderSpecificSettings::FillVideoCodecVp8(
|
|
|
|
|
VideoCodecVP8* vp8_settings) const {
|
|
|
|
|
*vp8_settings = specifics_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VideoEncoderConfig::Vp9EncoderSpecificSettings::Vp9EncoderSpecificSettings(
|
|
|
|
|
const VideoCodecVP9& specifics)
|
|
|
|
|
: specifics_(specifics) {}
|
|
|
|
|
|
|
|
|
|
void VideoEncoderConfig::Vp9EncoderSpecificSettings::FillVideoCodecVp9(
|
|
|
|
|
VideoCodecVP9* vp9_settings) const {
|
|
|
|
|
*vp9_settings = specifics_;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-15 09:35:06 +00:00
|
|
|
} // namespace webrtc
|