mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1244913 - resolution-based bitrates for each simulcast layer, scaleResolutionDownBy, and working maxBitrate in unicast. r=bwc,jesup
MozReview-Commit-ID: 347J1ElsOEx
This commit is contained in:
parent
ad805f4ccc
commit
9f731f009b
@ -1092,6 +1092,9 @@ RTCPeerConnection.prototype = {
|
||||
var encodings = parameters.encodings || [];
|
||||
|
||||
encodings.reduce((uniqueRids, encoding) => {
|
||||
if (encoding.scaleResolutionDownBy < 1.0) {
|
||||
throw new this._win.RangeError("scaleResolutionDownBy must be >= 1.0");
|
||||
}
|
||||
if (!encoding.rid && encodings.length > 1) {
|
||||
throw new this._win.DOMException("Missing rid", "TypeError");
|
||||
}
|
||||
|
@ -23,7 +23,8 @@ public:
|
||||
maxPps(0),
|
||||
maxMbps(0),
|
||||
maxCpb(0),
|
||||
maxDpb(0)
|
||||
maxDpb(0),
|
||||
scaleDownBy(1.0)
|
||||
{}
|
||||
|
||||
bool operator==(const EncodingConstraints& constraints) const
|
||||
@ -40,6 +41,7 @@ public:
|
||||
uint32_t maxMbps; // macroblocks per second
|
||||
uint32_t maxCpb; // coded picture buffer size
|
||||
uint32_t maxDpb; // decoded picture buffer size
|
||||
double scaleDownBy; // To preserve resolution
|
||||
};
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -682,6 +682,8 @@ WebrtcVideoConduit::ConfigureSendMediaCodec(const VideoCodecConfig* codecConfig)
|
||||
#endif
|
||||
video_codec.qpMax = 56;
|
||||
video_codec.numberOfSimulcastStreams = 1;
|
||||
video_codec.simulcastStream[0].jsScaleDownBy =
|
||||
codecConfig->mEncodingConstraints.scaleDownBy;
|
||||
video_codec.mode = mCodecMode;
|
||||
|
||||
codecFound = true;
|
||||
@ -979,6 +981,12 @@ WebrtcVideoConduit::ConfigureRecvMediaCodecs(
|
||||
return kMediaConduitNoError;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T MinIgnoreZero(const T& a, const T& b)
|
||||
{
|
||||
return std::min(a? a:b, b? b:a);
|
||||
}
|
||||
|
||||
struct ResolutionAndBitrateLimits {
|
||||
uint32_t resolution_in_mb;
|
||||
uint16_t min_bitrate;
|
||||
@ -986,7 +994,7 @@ struct ResolutionAndBitrateLimits {
|
||||
uint16_t max_bitrate;
|
||||
};
|
||||
|
||||
#define MB_OF(w,h) ((unsigned int)((((w)>>4))*((unsigned int)((h)>>4))))
|
||||
#define MB_OF(w,h) ((unsigned int)((((w+15)>>4))*((unsigned int)((h+15)>>4))))
|
||||
|
||||
// For now, try to set the max rates well above the knee in the curve.
|
||||
// Chosen somewhat arbitrarily; it's hard to find good data oriented for
|
||||
@ -1007,24 +1015,25 @@ static ResolutionAndBitrateLimits kResolutionAndBitrateLimits[] = {
|
||||
void
|
||||
WebrtcVideoConduit::SelectBitrates(unsigned short width,
|
||||
unsigned short height,
|
||||
unsigned int cap,
|
||||
mozilla::Atomic<int32_t, mozilla::Relaxed>& aLastFramerateTenths,
|
||||
unsigned int& out_start,
|
||||
unsigned int& out_min,
|
||||
unsigned int& out_start,
|
||||
unsigned int& out_max)
|
||||
{
|
||||
// max bandwidth should be proportional (not linearly!) to resolution, and
|
||||
// proportional (perhaps linearly, or close) to current frame rate.
|
||||
unsigned int fs, mb_width, mb_height;
|
||||
|
||||
mb_width = (width + 15) >> 4;
|
||||
mb_height = (height + 15) >> 4;
|
||||
fs = mb_width * mb_height;
|
||||
unsigned int fs = MB_OF(width, height);
|
||||
|
||||
for (ResolutionAndBitrateLimits resAndLimits : kResolutionAndBitrateLimits) {
|
||||
if (fs > resAndLimits.resolution_in_mb) {
|
||||
out_min = resAndLimits.min_bitrate;
|
||||
out_start = resAndLimits.start_bitrate;
|
||||
out_max = resAndLimits.max_bitrate;
|
||||
if (fs > resAndLimits.resolution_in_mb &&
|
||||
// pick the highest range where at least start rate is within cap
|
||||
// (or if we're at the end of the array).
|
||||
(!cap || resAndLimits.start_bitrate <= cap ||
|
||||
resAndLimits.resolution_in_mb == 0)) {
|
||||
out_min = MinIgnoreZero((unsigned int)resAndLimits.min_bitrate, cap);
|
||||
out_start = MinIgnoreZero((unsigned int)resAndLimits.start_bitrate, cap);
|
||||
out_max = MinIgnoreZero((unsigned int)resAndLimits.max_bitrate, cap);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1069,19 +1078,16 @@ static void ConstrainPreservingAspectRatioExact(uint32_t max_fs,
|
||||
unsigned short* width,
|
||||
unsigned short* height)
|
||||
{
|
||||
unsigned int mb_width = (*width + 15) >> 4;
|
||||
unsigned int mb_height = (*height + 15) >> 4;
|
||||
|
||||
// We could try to pick a better starting divisor, but it won't make any real
|
||||
// performance difference.
|
||||
for (size_t d = 1; d < std::min(mb_width, mb_height); ++d) {
|
||||
if ((mb_width % d) || (mb_height % d)) {
|
||||
for (size_t d = 1; d < std::min(*width, *height); ++d) {
|
||||
if ((*width % d) || (*height % d)) {
|
||||
continue; // Not divisible
|
||||
}
|
||||
|
||||
if ((mb_width*mb_height)/(d*d) <= max_fs) {
|
||||
*width = 16 * mb_width / d;
|
||||
*height = 16 * mb_height / d;
|
||||
if (((*width) * (*height))/(d*d) <= max_fs) {
|
||||
*width /= d;
|
||||
*height /= d;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1278,53 +1284,54 @@ WebrtcVideoConduit::ReconfigureSendCodec(unsigned short width,
|
||||
vie_codec.width = width;
|
||||
vie_codec.height = height;
|
||||
vie_codec.maxFramerate = mSendingFramerate;
|
||||
SelectBitrates(vie_codec.width, vie_codec.height,
|
||||
SelectBitrates(vie_codec.width, vie_codec.height, 0,
|
||||
mLastFramerateTenths,
|
||||
vie_codec.startBitrate,
|
||||
vie_codec.minBitrate,
|
||||
vie_codec.startBitrate,
|
||||
vie_codec.maxBitrate);
|
||||
|
||||
// TODO: If/when we begin supporting width/height constraints on simulcast
|
||||
// streams, for each such constraint we will need to choose a resolution
|
||||
// that is the same aspect ratio as all other streams. This requires us to
|
||||
// store the original constraints somewhere.
|
||||
for (size_t i = vie_codec.numberOfSimulcastStreams; i > 0; --i) {
|
||||
webrtc::SimulcastStream& stream(vie_codec.simulcastStream[i - 1]);
|
||||
if (stream.maxBitrate && (stream.maxBitrate < vie_codec.minBitrate)) {
|
||||
// This stream cannot do full resolution with good quality. Need to
|
||||
// scale down.
|
||||
stream.width = 0;
|
||||
stream.height = 0;
|
||||
uint32_t max_fs_in_mb = kResolutionAndBitrateLimits[0].resolution_in_mb;
|
||||
for (ResolutionAndBitrateLimits resAndLimits :
|
||||
kResolutionAndBitrateLimits) {
|
||||
if (resAndLimits.min_bitrate < stream.maxBitrate) {
|
||||
// Use the resolution from the _previous_ entry
|
||||
unsigned short adjusted_width = width;
|
||||
unsigned short adjusted_height = height;
|
||||
// webrtc.org won't tolerate simulcast unless every stream is
|
||||
// exactly the same aspect ratio
|
||||
ConstrainPreservingAspectRatioExact(max_fs_in_mb,
|
||||
&adjusted_width,
|
||||
&adjusted_height);
|
||||
stream.width = adjusted_width;
|
||||
stream.height = adjusted_height;
|
||||
break;
|
||||
}
|
||||
max_fs_in_mb = resAndLimits.resolution_in_mb;
|
||||
stream.width = width;
|
||||
stream.height = height;
|
||||
MOZ_ASSERT(stream.jsScaleDownBy >= 1.0);
|
||||
uint32_t new_width = uint32_t(width / stream.jsScaleDownBy);
|
||||
uint32_t new_height = uint32_t(height / stream.jsScaleDownBy);
|
||||
// TODO: If two layers are similar, only alloc bits to one (Bug 1249859)
|
||||
if (new_width != width || new_height != height) {
|
||||
if (vie_codec.numberOfSimulcastStreams == 1) {
|
||||
// Use less strict scaling in unicast. That way 320x240 / 3 = 106x79.
|
||||
ConstrainPreservingAspectRatio(new_width, new_height,
|
||||
&stream.width, &stream.height);
|
||||
} else {
|
||||
// webrtc.org supposedly won't tolerate simulcast unless every stream
|
||||
// is exactly the same aspect ratio. 320x240 / 3 = 80x60.
|
||||
ConstrainPreservingAspectRatioExact(new_width*new_height,
|
||||
&stream.width, &stream.height);
|
||||
}
|
||||
} else {
|
||||
stream.width = width;
|
||||
stream.height = height;
|
||||
}
|
||||
// webrtc.org also gets upset if the last simulcast stream has a
|
||||
// different resolution than the vie_codec
|
||||
// Give each layer default appropriate bandwidth limits based on the
|
||||
// resolution/framerate of that layer
|
||||
SelectBitrates(stream.width, stream.height, stream.jsMaxBitrate,
|
||||
mLastFramerateTenths,
|
||||
stream.minBitrate,
|
||||
stream.targetBitrate,
|
||||
stream.maxBitrate);
|
||||
|
||||
vie_codec.minBitrate = std::min(stream.minBitrate, vie_codec.minBitrate);
|
||||
vie_codec.startBitrate += stream.targetBitrate;
|
||||
vie_codec.maxBitrate = std::max(stream.maxBitrate, vie_codec.maxBitrate);
|
||||
|
||||
// webrtc.org expects the last, highest fidelity, simulcast stream to
|
||||
// always have the same resolution as vie_codec
|
||||
if (i == vie_codec.numberOfSimulcastStreams) {
|
||||
vie_codec.width = stream.width;
|
||||
vie_codec.height = stream.height;
|
||||
}
|
||||
}
|
||||
|
||||
if (vie_codec.numberOfSimulcastStreams != 0) {
|
||||
vie_codec.startBitrate /= vie_codec.numberOfSimulcastStreams;
|
||||
}
|
||||
if ((err = mPtrViECodec->SetSendCodec(mChannel, vie_codec)) != 0)
|
||||
{
|
||||
CSFLogError(logTag, "%s: SetSendCodec(%ux%u) failed, err %d",
|
||||
@ -1787,18 +1794,6 @@ WebrtcVideoConduit::DeliverI420Frame(const webrtc::I420VideoFrame& webrtc_frame)
|
||||
return -1;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T MinIgnoreZero(const T& a, const T& b)
|
||||
{
|
||||
if (!a) {
|
||||
return b;
|
||||
} else if (!b) {
|
||||
return a;
|
||||
} else {
|
||||
return std::min(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the codec passed into Conduit's database
|
||||
*/
|
||||
@ -1895,14 +1890,24 @@ WebrtcVideoConduit::CodecConfigToWebRTCCodec(const VideoCodecConfig* codecInfo,
|
||||
stream.height,
|
||||
(unsigned short)encoding.constraints.maxHeight);
|
||||
|
||||
if (encoding.constraints.maxBr) {
|
||||
// webrtc.org uses kbps, we use bps
|
||||
stream.maxBitrate = encoding.constraints.maxBr/1000;
|
||||
stream.minBitrate = MinIgnoreZero(stream.minBitrate, stream.maxBitrate);
|
||||
stream.targetBitrate = MinIgnoreZero(stream.targetBitrate,
|
||||
stream.maxBitrate);
|
||||
}
|
||||
// webrtc.org uses kbps, we use bps
|
||||
stream.jsMaxBitrate = encoding.constraints.maxBr/1000;
|
||||
stream.jsScaleDownBy = encoding.constraints.scaleDownBy;
|
||||
|
||||
MOZ_ASSERT(stream.jsScaleDownBy >= 1.0);
|
||||
uint32_t width = stream.width? stream.width : 640;
|
||||
uint32_t height = stream.height? stream.height : 480;
|
||||
uint32_t new_width = uint32_t(width / stream.jsScaleDownBy);
|
||||
uint32_t new_height = uint32_t(height / stream.jsScaleDownBy);
|
||||
|
||||
if (new_width != width || new_height != height) {
|
||||
// Estimate. Overridden on first frame.
|
||||
SelectBitrates(new_width, new_height, stream.jsMaxBitrate,
|
||||
mLastFramerateTenths,
|
||||
stream.minBitrate,
|
||||
stream.targetBitrate,
|
||||
stream.maxBitrate);
|
||||
}
|
||||
// webrtc.org expects simulcast streams to be ordered by increasing
|
||||
// fidelity, our jsep code does the opposite.
|
||||
cinst.simulcastStream[codecInfo->mSimulcastEncodings.size()-i-1] = stream;
|
||||
|
@ -141,14 +141,16 @@ public:
|
||||
/**
|
||||
* Function to set the encoding bitrate limits based on incoming frame size and rate
|
||||
* @param width, height: dimensions of the frame
|
||||
* @param cap: user-enforced max bitrate, or 0
|
||||
* @param aLastFramerateTenths: holds the current input framerate
|
||||
* @param out_start, out_min, out_max: bitrate results
|
||||
*/
|
||||
void SelectBitrates(unsigned short width,
|
||||
unsigned short height,
|
||||
unsigned int cap,
|
||||
mozilla::Atomic<int32_t, mozilla::Relaxed>& aLastFramerateTenths,
|
||||
unsigned int& out_start,
|
||||
unsigned int& out_min,
|
||||
unsigned int& out_start,
|
||||
unsigned int& out_max);
|
||||
|
||||
/**
|
||||
|
@ -2415,6 +2415,7 @@ PeerConnectionImpl::SetParameters(MediaStreamTrack& aTrack,
|
||||
if (encoding.mMaxBitrate.WasPassed()) {
|
||||
constraint.constraints.maxBr = encoding.mMaxBitrate.Value();
|
||||
}
|
||||
constraint.constraints.scaleDownBy = encoding.mScaleResolutionDownBy;
|
||||
constraints.push_back(constraint);
|
||||
}
|
||||
}
|
||||
@ -2449,6 +2450,7 @@ PeerConnectionImpl::GetParameters(MediaStreamTrack& aTrack,
|
||||
RTCRtpEncodingParameters encoding;
|
||||
encoding.mRid.Construct(NS_ConvertASCIItoUTF16(constraint.rid.c_str()));
|
||||
encoding.mMaxBitrate.Construct(constraint.constraints.maxBr);
|
||||
encoding.mScaleResolutionDownBy = constraint.constraints.scaleDownBy;
|
||||
aOutParameters.mEncodings.Value().AppendElement(Move(encoding), fallible);
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -690,6 +690,8 @@ struct SimulcastStream {
|
||||
unsigned int minBitrate; // kilobits/sec.
|
||||
unsigned int qpMax; // minimum quality
|
||||
char rid[kRIDSize];
|
||||
unsigned int jsMaxBitrate; // user-controlled max bitrate
|
||||
double jsScaleDownBy; // user-controlled downscale
|
||||
|
||||
bool operator==(const SimulcastStream& other) const {
|
||||
return width == other.width &&
|
||||
@ -699,7 +701,9 @@ struct SimulcastStream {
|
||||
targetBitrate == other.targetBitrate &&
|
||||
minBitrate == other.minBitrate &&
|
||||
qpMax == other.qpMax &&
|
||||
strcmp(rid, other.rid) == 0;
|
||||
strcmp(rid, other.rid) == 0 &&
|
||||
jsMaxBitrate == other.jsMaxBitrate &&
|
||||
jsScaleDownBy == other.jsScaleDownBy;
|
||||
}
|
||||
|
||||
bool operator!=(const SimulcastStream& other) const {
|
||||
|
Loading…
Reference in New Issue
Block a user