【m】自适应分辨率,不知道有没问题
This commit is contained in:
@@ -809,7 +809,7 @@ class UIRenderer {
|
||||
container.style.alignItems = 'center';
|
||||
container.style.justifyContent = 'center';
|
||||
// 优化图像渲染
|
||||
videoElement.style.imageRendering = 'pixelated';
|
||||
videoElement.style.imageRendering = 'auto';
|
||||
// 确保视频元素在容器内正确显示
|
||||
videoElement.style.maxWidth = '100%';
|
||||
videoElement.style.maxHeight = '100%';
|
||||
|
||||
@@ -440,6 +440,19 @@ class CallStateManager {
|
||||
this.hangUp(); // 房间已关闭,挂断连接
|
||||
};
|
||||
|
||||
// SDP Answer 接收回调:重新设置编码参数以保障画质
|
||||
this.renderstreaming.onGotAnswer = (connectionId) => {
|
||||
console.log('SDP Answer received, resetting encoding parameters for connectionId:', connectionId);
|
||||
if (this.role === 'host') {
|
||||
const allParticipantIds = Object.keys(this.state.remoteStreams || {});
|
||||
for (const pid of allParticipantIds) {
|
||||
setTimeout(() => { this.setVideoEncodingParameters(pid); }, 50);
|
||||
}
|
||||
} else {
|
||||
setTimeout(() => { this.setVideoEncodingParameters(); }, 50);
|
||||
}
|
||||
};
|
||||
|
||||
// participant加入回调(host收到,新participant加入房间)
|
||||
this.renderstreaming.onParticipantJoined = (participantId) => {
|
||||
console.log(`Participant joined: ${participantId}`);
|
||||
@@ -848,43 +861,46 @@ class CallStateManager {
|
||||
* 优先选择 VP9/AV1(更高效的压缩),回退到 H264 High Profile
|
||||
*/
|
||||
setCodecPreferences(participantId) {
|
||||
const { codecs } = RTCRtpSender.getCapabilities('video');
|
||||
if (!codecs || codecs.length === 0) return;
|
||||
const capabilities = RTCRtpSender.getCapabilities('video');
|
||||
if (!capabilities || !capabilities.codecs || capabilities.codecs.length === 0) return;
|
||||
const { codecs } = capabilities;
|
||||
|
||||
let selectedCodecs = null;
|
||||
// 构建多codec优先级列表(而非只选一个)
|
||||
let selectedCodecs = [];
|
||||
|
||||
// 优先级: AV1 > VP9 > H264 High Profile > H264
|
||||
const av1Codec = codecs.find(c => c.mimeType === 'video/AV1');
|
||||
const vp9Codec = codecs.find(c => c.mimeType === 'video/VP9');
|
||||
// H264 High Profile 提供比 Baseline/Constrained Baseline 更好的画质
|
||||
const h264HighCodec = codecs.find(c =>
|
||||
c.mimeType === 'video/H264' &&
|
||||
c.sdpFmtpLine && c.sdpFmtpLine.includes('profile-level-id=6400')
|
||||
);
|
||||
const h264Codec = codecs.find(c => c.mimeType === 'video/H264');
|
||||
|
||||
if (av1Codec) {
|
||||
selectedCodecs = [av1Codec];
|
||||
console.log('Selected codec: AV1');
|
||||
} else if (vp9Codec) {
|
||||
selectedCodecs = [vp9Codec];
|
||||
console.log('Selected codec: VP9');
|
||||
} else if (h264HighCodec) {
|
||||
selectedCodecs = [h264HighCodec];
|
||||
console.log('Selected codec: H264 High Profile');
|
||||
} else if (h264Codec) {
|
||||
selectedCodecs = [h264Codec];
|
||||
console.log('Selected codec: H264');
|
||||
}
|
||||
if (av1Codec) selectedCodecs.push(av1Codec);
|
||||
if (vp9Codec) selectedCodecs.push(vp9Codec);
|
||||
if (h264HighCodec) selectedCodecs.push(h264HighCodec);
|
||||
if (h264Codec && (!h264HighCodec || h264Codec !== h264HighCodec)) selectedCodecs.push(h264Codec);
|
||||
|
||||
if (selectedCodecs == null) return;
|
||||
if (selectedCodecs.length === 0) return;
|
||||
|
||||
if (this.renderstreaming) {
|
||||
const transceivers = this.renderstreaming.getTransceivers(participantId);
|
||||
if (transceivers && transceivers.length > 0) {
|
||||
const videoTransceivers = transceivers.filter(t => t.receiver.track.kind == "video");
|
||||
const videoTransceivers = transceivers.filter(t => {
|
||||
if (t.sender && t.sender.track) {
|
||||
return t.sender.track.kind === 'video';
|
||||
}
|
||||
return t.mid !== null && t.receiver && t.receiver.track && t.receiver.track.kind === 'video';
|
||||
});
|
||||
if (videoTransceivers && videoTransceivers.length > 0) {
|
||||
videoTransceivers.forEach(t => t.setCodecPreferences(selectedCodecs));
|
||||
videoTransceivers.forEach(t => {
|
||||
try {
|
||||
t.setCodecPreferences(selectedCodecs);
|
||||
} catch(e) {
|
||||
console.error('Error setting codec preferences:', e);
|
||||
}
|
||||
});
|
||||
console.log(`Codec preferences set: ${selectedCodecs.map(c => c.mimeType).join(' > ')}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -914,8 +930,32 @@ class CallStateManager {
|
||||
params.encodings = [{}];
|
||||
}
|
||||
|
||||
// 设置最大比特率为 4Mbps(1080p@30fps 良好画质)
|
||||
params.encodings[0].maxBitrate = 4000000; // 4 Mbps = 4,000,000 bps
|
||||
// 根据实际采集分辨率动态设置maxBitrate
|
||||
const videoTrack = sender.track;
|
||||
const settings = videoTrack ? videoTrack.getSettings() : {};
|
||||
const height = settings.height || 1080;
|
||||
|
||||
const bitrateMap = {
|
||||
270: 1000000,
|
||||
480: 1500000,
|
||||
720: 2500000,
|
||||
1080: 4000000,
|
||||
1440: 6000000
|
||||
};
|
||||
// 找到最接近的分辨率对应的比特率
|
||||
let maxBitrate = 4000000;
|
||||
const heights = Object.keys(bitrateMap).map(Number).sort((a, b) => a - b);
|
||||
for (const h of heights) {
|
||||
if (height <= h) {
|
||||
maxBitrate = bitrateMap[h];
|
||||
break;
|
||||
}
|
||||
maxBitrate = bitrateMap[h];
|
||||
}
|
||||
|
||||
params.encodings[0].maxBitrate = maxBitrate;
|
||||
params.encodings[0].scaleResolutionDownBy = 1.0;
|
||||
params.encodings[0].xGoogleMinBitrate = Math.floor(maxBitrate * 0.5);
|
||||
|
||||
// 优先保持分辨率,降低帧率来适应带宽
|
||||
// 'maintain-resolution' 在带宽不足时保持清晰度
|
||||
@@ -924,7 +964,7 @@ class CallStateManager {
|
||||
}
|
||||
|
||||
sender.setParameters(params);
|
||||
console.log(`Set video encoding: maxBitrate=4Mbps, degradationPreference=maintain-resolution${participantId ? ` for ${participantId}` : ''}`);
|
||||
console.log(`Set video encoding: maxBitrate=${maxBitrate / 1000000}Mbps, scaleResolutionDownBy=1.0, xGoogleMinBitrate=${Math.floor(maxBitrate * 0.5)}${participantId ? ` for ${participantId}` : ''}`);
|
||||
} catch (error) {
|
||||
console.error('Error setting video encoding parameters:', error);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user