--- a/dom/media/tests/mochitest/test_peerConnection_scaleResolution.html
+++ b/dom/media/tests/mochitest/test_peerConnection_scaleResolution.html
@@ -7,63 +7,77 @@
<pre id="test">
<script type="application/javascript;version=1.8">
createHTML({
bug: "1244913",
title: "Scale resolution down on a PeerConnection",
visible: true
});
- var pc1 = new RTCPeerConnection();
- var pc2 = new RTCPeerConnection();
-
- var add = (pc, can, failed) => can && pc.addIceCandidate(can).catch(failed);
- pc1.onicecandidate = e => add(pc2, e.candidate, generateErrorCallback());
- pc2.onicecandidate = e => add(pc1, e.candidate, generateErrorCallback());
-
- pc1.onnegotiationneeded = e =>
- pc1.createOffer().then(d => pc1.setLocalDescription(d))
- .then(() => pc2.setRemoteDescription(pc1.localDescription))
- .then(() => pc2.createAnswer()).then(d => pc2.setLocalDescription(d))
- .then(() => pc1.setRemoteDescription(pc2.localDescription))
- .catch(generateErrorCallback());
-
var mustRejectWith = (msg, reason, f) =>
f().then(() => ok(false, msg),
e => is(e.name, reason, msg));
- var v1, v2;
+
+ var removeVP8 = d => (d.sdp = d.sdp.replace("a=rtpmap:120 VP8/90000\r\n", ""), d);
+
+ function testScale(codec) {
+ var pc1 = new RTCPeerConnection();
+ var pc2 = new RTCPeerConnection();
+
+ var add = (pc, can, failed) => can && pc.addIceCandidate(can).catch(failed);
+ pc1.onicecandidate = e => add(pc2, e.candidate, generateErrorCallback());
+ pc2.onicecandidate = e => add(pc1, e.candidate, generateErrorCallback());
+
+ info("testing scaling with " + codec);
- runNetworkTest(function() {
- v1 = createMediaElement('video', 'v1');
- v2 = createMediaElement('video', 'v2');
+ pc1.onnegotiationneeded = e =>
+ pc1.createOffer()
+ .then(d => pc1.setLocalDescription(codec == "VP8" ? d : removeVP8(d)))
+ .then(() => pc2.setRemoteDescription(pc1.localDescription))
+ .then(() => pc2.createAnswer()).then(d => pc2.setLocalDescription(d))
+ .then(() => pc1.setRemoteDescription(pc2.localDescription))
+ .catch(generateErrorCallback());
- is(v2.currentTime, 0, "v2.currentTime is zero at outset");
+ return navigator.mediaDevices.getUserMedia({ video: true })
+ .then(stream => {
+ var v1 = createMediaElement('video', 'v1');
+ var v2 = createMediaElement('video', 'v2');
- navigator.mediaDevices.getUserMedia({ video: true })
- .then(stream => {
+ is(v2.currentTime, 0, "v2.currentTime is zero at outset");
+
v1.srcObject = stream;
var sender = pc1.addTrack(stream.getVideoTracks()[0], stream);
return mustRejectWith("Invalid scaleResolutionDownBy must reject", "RangeError",
() => sender.setParameters({ encodings:
[{ scaleResolutionDownBy: 0.5 } ] }))
.then(() => sender.setParameters({ encodings: [{ maxBitrate: 60000,
- scaleResolutionDownBy: 2 }] }))
+ scaleResolutionDownBy: 2 }] }))
+ .then(() => new Promise(resolve => pc2.ontrack = e => resolve(e)))
+ .then(e => v2.srcObject = e.streams[0])
+ .then(() => new Promise(resolve => v2.onloadedmetadata = resolve))
+ .then(() => waitUntil(() => v2.currentTime > 0 && v2.srcObject.currentTime > 0))
+ .then(() => ok(v2.currentTime > 0, "v2.currentTime is moving (" + v2.currentTime + ")"))
+ .then(() => wait(3000)) // TODO: Bug 1248154
+ .then(() => {
+ ok(v1.videoWidth > 0, "source width is positive");
+ ok(v1.videoHeight > 0, "source height is positive");
+ if (v2.videoWidth == 640 && v2.videoHeight == 480) { // TODO: Bug 1248154
+ info("Skipping test due to Bug 1248154");
+ } else {
+ is(v2.videoWidth, v1.videoWidth / 2, "sink is half the width of source");
+ is(v2.videoHeight, v1.videoHeight / 2, "sink is half the height of source");
+ }
+ })
+ .then(() => {
+ stream.getTracks().forEach(track => track.stop());
+ v1.srcObject = v2.srcObject = null;
+ })
})
- .then(() => new Promise(resolve => pc2.ontrack = e => resolve(e)))
- .then(e => v2.srcObject = e.streams[0])
- .then(() => new Promise(resolve => v2.onloadedmetadata = resolve))
- .then(() => waitUntil(() => v2.currentTime > 0 && v2.srcObject.currentTime > 0))
- .then(() => ok(v2.currentTime > 0, "v2.currentTime is moving (" + v2.currentTime + ")"))
- .then(() => wait(1000)) // TODO: Bug 1248154
- .then(() => {
- ok(v1.videoWidth > 0, "source width is positive");
- ok(v1.videoHeight > 0, "source height is positive");
- is(v2.videoWidth, v1.videoWidth / 2, "sink is half the width of source");
- is(v2.videoHeight, v1.videoHeight / 2, "sink is half the height of source");
- })
- .catch(generateErrorCallback())
- .then(networkTestFinished);
- });
+ .catch(generateErrorCallback());
+ }
+
+ runNetworkTest(() => testScale("VP8").then(() => testScale("H264"))
+ .then(networkTestFinished));
</script>
</pre>
</body>
</html>
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -1272,90 +1272,86 @@ WebrtcVideoConduit::ReconfigureSendCodec
{
CSFLogError(logTag, "%s: GetSendCodec failed, err %d", __FUNCTION__, err);
return NS_ERROR_FAILURE;
}
CSFLogDebug(logTag,
"%s: Requesting resolution change to %ux%u (from %ux%u)",
__FUNCTION__, width, height, vie_codec.width, vie_codec.height);
- // Likely spurious unless there was some error, but rarely checked
- if (vie_codec.width != width || vie_codec.height != height ||
- vie_codec.maxFramerate != mSendingFramerate)
- {
- vie_codec.width = width;
- vie_codec.height = height;
- vie_codec.maxFramerate = mSendingFramerate;
- SelectBitrates(vie_codec.width, vie_codec.height, 0,
- mLastFramerateTenths,
- vie_codec.minBitrate,
- vie_codec.startBitrate,
- vie_codec.maxBitrate);
+
+ vie_codec.width = width;
+ vie_codec.height = height;
+ vie_codec.maxFramerate = mSendingFramerate;
+ SelectBitrates(vie_codec.width, vie_codec.height, 0,
+ mLastFramerateTenths,
+ vie_codec.minBitrate,
+ vie_codec.startBitrate,
+ vie_codec.maxBitrate);
- for (size_t i = vie_codec.numberOfSimulcastStreams; i > 0; --i) {
- webrtc::SimulcastStream& stream(vie_codec.simulcastStream[i - 1]);
- 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);
- }
- }
- // 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;
+ for (size_t i = vie_codec.numberOfSimulcastStreams; i > 0; --i) {
+ webrtc::SimulcastStream& stream(vie_codec.simulcastStream[i - 1]);
+ 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);
}
}
- 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",
- __FUNCTION__, width, height, err);
- return NS_ERROR_FAILURE;
+ // 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 (mMinBitrateEstimate != 0) {
- mPtrViENetwork->SetBitrateConfig(mChannel,
- mMinBitrateEstimate,
- std::max(vie_codec.startBitrate,
- mMinBitrateEstimate),
- std::max(vie_codec.maxBitrate,
- mMinBitrateEstimate));
- }
+ }
+ 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",
+ __FUNCTION__, width, height, err);
+ return NS_ERROR_FAILURE;
+ }
+ if (mMinBitrateEstimate != 0) {
+ mPtrViENetwork->SetBitrateConfig(mChannel,
+ mMinBitrateEstimate,
+ std::max(vie_codec.startBitrate,
+ mMinBitrateEstimate),
+ std::max(vie_codec.maxBitrate,
+ mMinBitrateEstimate));
+ }
- CSFLogDebug(logTag, "%s: Encoder resolution changed to %ux%u @ %ufps, bitrate %u:%u",
- __FUNCTION__, width, height, mSendingFramerate,
- vie_codec.minBitrate, vie_codec.maxBitrate);
- } // else no change; mSendingWidth likely was 0
+ CSFLogDebug(logTag, "%s: Encoder resolution changed to %ux%u @ %ufps, bitrate %u:%u",
+ __FUNCTION__, width, height, mSendingFramerate,
+ vie_codec.minBitrate, vie_codec.maxBitrate);
if (frame) {
// XXX I really don't like doing this from MainThread...
mPtrExtCapture->IncomingFrame(*frame);
mVideoCodecStat->SentFrame();
CSFLogDebug(logTag, "%s Inserted a frame from reconfig lambda", __FUNCTION__);
}
return NS_OK;
}
@@ -1859,67 +1855,67 @@ WebrtcVideoConduit::CodecConfigToWebRTCC
CSFLogError(logTag, "%s H.264 max_mbps not supported yet ", __FUNCTION__);
}
// XXX parse the encoded SPS/PPS data
// paranoia
cinst.codecSpecific.H264.spsData = nullptr;
cinst.codecSpecific.H264.spsLen = 0;
cinst.codecSpecific.H264.ppsData = nullptr;
cinst.codecSpecific.H264.ppsLen = 0;
- } else {
- // TODO(bug 1210175): H264 doesn't support simulcast yet.
- for (size_t i = 0; i < codecInfo->mSimulcastEncodings.size(); ++i) {
- const VideoCodecConfig::SimulcastEncoding& encoding =
- codecInfo->mSimulcastEncodings[i];
- // Make sure the constraints on the whole stream are reflected.
- webrtc::SimulcastStream stream;
- memset(&stream, 0, sizeof(stream));
- stream.width = cinst.width;
- stream.height = cinst.height;
- stream.numberOfTemporalLayers = 1;
- stream.maxBitrate = cinst.maxBitrate;
- stream.targetBitrate = cinst.targetBitrate;
- stream.minBitrate = cinst.minBitrate;
- stream.qpMax = cinst.qpMax;
- strncpy(stream.rid, encoding.rid.c_str(), sizeof(stream.rid)-1);
- stream.rid[sizeof(stream.rid) - 1] = 0;
-
- // Apply encoding-specific constraints.
- stream.width = MinIgnoreZero(
- stream.width,
- (unsigned short)encoding.constraints.maxWidth);
- stream.height = MinIgnoreZero(
- stream.height,
- (unsigned short)encoding.constraints.maxHeight);
+ }
+ // Init mSimulcastEncodings always since they hold info from setParameters.
+ // TODO(bug 1210175): H264 doesn't support simulcast yet.
+ for (size_t i = 0; i < codecInfo->mSimulcastEncodings.size(); ++i) {
+ const VideoCodecConfig::SimulcastEncoding& encoding =
+ codecInfo->mSimulcastEncodings[i];
+ // Make sure the constraints on the whole stream are reflected.
+ webrtc::SimulcastStream stream;
+ memset(&stream, 0, sizeof(stream));
+ stream.width = cinst.width;
+ stream.height = cinst.height;
+ stream.numberOfTemporalLayers = 1;
+ stream.maxBitrate = cinst.maxBitrate;
+ stream.targetBitrate = cinst.targetBitrate;
+ stream.minBitrate = cinst.minBitrate;
+ stream.qpMax = cinst.qpMax;
+ strncpy(stream.rid, encoding.rid.c_str(), sizeof(stream.rid)-1);
+ stream.rid[sizeof(stream.rid) - 1] = 0;
- // webrtc.org uses kbps, we use bps
- stream.jsMaxBitrate = encoding.constraints.maxBr/1000;
- stream.jsScaleDownBy = encoding.constraints.scaleDownBy;
+ // Apply encoding-specific constraints.
+ stream.width = MinIgnoreZero(
+ stream.width,
+ (unsigned short)encoding.constraints.maxWidth);
+ stream.height = MinIgnoreZero(
+ stream.height,
+ (unsigned short)encoding.constraints.maxHeight);
- 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);
+ // webrtc.org uses kbps, we use bps
+ stream.jsMaxBitrate = encoding.constraints.maxBr/1000;
+ stream.jsScaleDownBy = encoding.constraints.scaleDownBy;
- 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;
+ 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;
+ }
- cinst.numberOfSimulcastStreams = codecInfo->mSimulcastEncodings.size();
- }
+ cinst.numberOfSimulcastStreams = codecInfo->mSimulcastEncodings.size();
}
//Copy the codec passed into Conduit's database
bool
WebrtcVideoConduit::CopyCodecToDB(const VideoCodecConfig* codecInfo)
{
VideoCodecConfig* cdcConfig = new VideoCodecConfig(*codecInfo);
mRecvCodecList.push_back(cdcConfig);