WebRTC 지원 판정은 통과했는데, 왜 화질이 낮아질까?

encodingInfo는 요청한 해상도를 지원한다고 답했는데, Firefox가 통화 상대에게 보내는 프레임은 그보다 작다. 지원 판정을 통과한 영상은 어디서 줄어들었을까?

WebRTC 지원 판정은 통과했는데, 왜 화질이 낮아질까?
세 줄 요약
  • Firefox 158은 H.264·AV1 송출을 협상된 코덱 레벨 안에 맞추도록 해상도와 프레임률을 조정할 수 있다.
  • encodingInfo의 supported가 true라는 결과를 요청 해상도의 송출 보장으로 해석하면 안 된다.
  • 통화 중 about:webrtc나 outbound-rtp 통계에서 실제 인코딩 프레임 크기를 확인한다.

지원 판정을 통과해도 코덱 레벨에 맞춰 줄여 보낼 수 있다

encodingInfo()에서 supported: true를 받았는데 WebRTC 영상의 해상도가 예상보다 낮다면, 지원 판정과 실제 송출 통계를 나누어 봐야 한다. Firefox 158의 변경 사항에 따르면 H.264·AV1 송출은 상대와 협상한 코덱 레벨에 맞춰 필요시 해상도와 프레임률을 낮춘다.

H.264의 레벨 정보는 profile-level-id, AV1은 level-idx에 담긴다. 요청한 설정이 레벨의 한도를 넘어도 낮춰 보낼 수 있으므로, type: "webrtc"로 묻는 지원 판정은 true가 될 수 있다. 그 결과만 보고 요청한 크기와 프레임률이 그대로 송출된다고 표시하면 실제 통화와 어긋날 수 있다.

Mozilla의 관련 변경 기록에도 H.264·AV1 인코더의 해상도와 프레임률을 협상된 레벨로 제한하는 구현이 남아 있다. 이 동작을 모든 코덱이나 모든 화질 저하의 원인으로 확대할 수는 없다.

supported·smooth·powerEfficient는 현재 통화의 측정값이 아니다

encodingInfo는 주어진 미디어 설정에 대한 인코딩 능력을 질의하는 API다. WebRTC용 설정에서는 type: "webrtc"와 영상의 형식·크기·비트레이트·프레임률 등을 넘긴다.

반환값읽어야 할 의미
supported해당 미디어를 인코딩할 수 있는지에 대한 판정이다.
smooth원활하게 처리될 것으로 보는지에 대한 판정이다.
powerEfficient전력 효율적으로 처리될 것으로 보는지에 대한 판정이다.

이 값들을 현재 통화의 출력 크기나 실측 프레임률처럼 표시해서는 안 된다. 설정 후보를 고를 때의 판정과 통화가 시작된 뒤의 측정은 서로 다른 정보다.

통화 중 출력 프레임 크기를 읽는다

Firefox에서는 통화를 유지한 채 새 탭에서 about:webrtc를 열 수 있다. Mozilla의 진단 가이드에 따르면 RTCPeerConnection Statistics에는 협상 정보, RTP 스트림 통계, 대역폭과 출력 프레임 정보가 들어 있다. 해당 통화를 펼쳐 어떤 조건으로 연결됐고 무엇을 보내는지 함께 살핀다.

앱 코드에서는 outbound-rtp 통계를 읽는다. 아래 예의 pc는 앱에서 이미 사용 중인 RTCPeerConnection이다.

const stats = await pc.getStats();
for (const report of stats.values()) {
  if (report.type === "outbound-rtp" && report.kind === "video") {
    console.log({
      id: report.id,
      width: report.frameWidth,
      height: report.frameHeight,
      fps: report.framesPerSecond
    });
  }
}

frameWidth와 frameHeight는 마지막으로 인코딩한 프레임의 픽셀 크기다. framesPerSecond는 최근 1초 동안 보낸 인코딩 프레임 수를 나타낸다. 브라우저·상황에 따라 세부 통계가 제공되지 않을 수 있으므로 값이 없다고 0으로 바꿔 기록하지 않는다. 출력 통계는 상대 화면에 실제로 렌더링된 결과와도 구별해야 한다.

카메라의 현재 설정과 송출 크기를 따로 기록한다

입력 쪽은 영상 트랙의 getSettings()로 확인한다. 이는 트랙에 적용된 현재 설정을 돌려준다. 코드에서 요청한 제약을 돌려주는 getConstraints()와도 다르다.

카메라 입력은 큰데 인코딩 프레임이 작다면 입력 설정만 올려서는 이유를 설명할 수 없다. 입력의 현재값, 상대와 합의한 코덱 레벨, 실제 출력 통계를 차례로 대조해야 한다. Firefox 158의 지원 판정은 설정 후보를 고르는 데 쓰고, 사용자에게 보여 줄 송출 해상도는 통화 중 측정값에서 가져오는 것이 맞다.