Test Stream Webcam Thực — Bên Kia Thực Sự Thấy Gì
Hình bạn thấy trong preview webcam là local capture view — feed camera qua getUserMedia() — không phải output sensor thô. Hình người nhận video call thấy là stream do trình duyệt encode, đã được negotiate, nén, và có thể downgrade bởi WebRTC. Hướng dẫn này giải thích codec negotiation WebRTC hoạt động ra sao, cách dùng getStats() trên RTCPeerConnection để đo thông số stream thực, và cách sửa nguyên nhân mất chất lượng phổ biến. Lưu ý: công cụ webcam trên site này chỉ kiểm tra local capture track và frame rate trình duyệt; không đo outbound WebRTC encoded stream.
Bạn ngồi trong video call và cửa sổ của bạn hiển thị hình 1080p sắc nét, ánh sáng tốt. Bạn trông sharp, nền sạch, và framing đúng. Rồi đồng nghiệp nói video của bạn liên tục đóng băng và trông mờ, và khi họ chia sẻ màn hình bạn thấy mình là hình blocky, mềm cạnh mà webcam giá rẻ thập kỷ trước cũng sản xuất được. Cùng camera. Cùng ánh sáng. Cùng máy. Một hình khác.
Điều mà hầu hết hướng dẫn video call bỏ qua: khoảng cách đó thường không phải lỗi phần cứng hay defect sensor — dù đôi khi driver hoạt động sai cũng có thể gây ra. Nó thường là khác biệt giữa camera sản xuất và trình duyệt thực sự gửi. Preview của bạn được feed từ local capture path — khung hình camera sản xuất qua getUserMedia() — trước khi WebRTC encode, khiến nó là view thuận lợi hơn video người nhận thấy. View đó vẫn có thể bao gồm scaling, color conversion, hoặc constraint processing do trình duyệt áp dụng, nên không phải raw sensor output. Người nhận thấy compressed stream đã được negotiate, re-encode, rate-limit, và có thể downgrade bởi WebRTC trong mili giây trước khi rời máy.
Lớp encoding đó vô hình từ giao diện người dùng và im lặng trong hoạt động bình thường. Không gì trong call window báo cho bạn biết nó tồn tại, không gì báo cáo quyết định của nó, và không gì trong preview phản ánh chúng. Cảnh quen thuộc: người dùng dành hàng giờ cài lại driver camera vì call hiển thị hình mờ — chỉ để phát hiện qua chrome://webrtc-internals rằng trình duyệt đang negotiate xuống 480p15 dựa trên ước tính băng thông, không phải do camera hoặc driver. Trang này giải thích điều gì xảy ra giữa camera sensor và màn hình của đối tác call, tại sao trình duyệt âm thầm hạ chất lượng, và — quan trọng nhất — cách đo stream thực rời máy thay vì tin preview.

Preview không cho bạn thấy gì
Video call dựa trên pipeline chạy hoàn toàn ngoài nhận thức của bạn. Mỗi khung bạn gửi qua các giai đoạn:
- Camera sensor capture khung; trình duyệt deliver qua getUserMedia() ở độ phân giải và khung hình yêu cầu, có thể bao gồm scaling, color conversion, và constraint processing.
- Trình duyệt nhận khung qua
getUserMedia()API và giao cho WebRTC engine. Preview local của bạn được feed từ giai đoạn này — lý do nó luôn trông perfect, bất kể điều gì xảy ra tiếp theo. - WebRTC encoder nén khung thành bitstream dùng codec negotiated, ở độ phân giải, khung hình, và bit rate negotiated.
- Khung encoded chia thành RTP packet và gửi qua network, thường qua media server relay cho mọi người.
- Mỗi receiver decode packet thành hình và render trên màn hình.
Preview của bạn tap vào pipeline ở giai đoạn hai. Nó hiển thị khung hình camera sản xuất qua getUserMedia(), trước khi WebRTC encode. Trình duyệt có thể áp dụng scaling, color conversion, hoặc constraint processing ở giai đoạn này, nhưng không có WebRTC compression nào được áp dụng. Stream đối tác call thấy là output từ giai đoạn ba. Giữa hai điểm đó, encoder quyết định thế giới nhận gì, và nó đưa ra quyết định dựa trên điều kiện bạn không bao giờ thấy.
Encoder âm thầm negotiate ba tham số, mỗi cái có thể thay đổi mid-call mà không có thông báo:
- Độ phân giải — chiều rộng và cao của khung encoded, có thể drop từ 1920×1080 xuống 1280×720 hoặc 640×480 tự động.
- Tốc độ khung hình — bao nhiêu khung mỗi giây sống sót qua encoding, thường rớt đầu tiên (từ 30 xuống 15 hoặc thấp hơn) vì halving frame rate cắt data rate пополам không đổi độ phân giải — dù một số implementation có thể giảm độ phân giải thay thế, tùy codec và platform.
- Bit rate — bao nhiêu bit mỗi giây encoder được phép dùng, đặt mức compression tổng thể.
Ba giá trị này quyết định mọi thứ bên kia thấy. Hình 1080p nén ở bit rate thấp trông mềm và smeared. Stream 30 fps đột ngột chạy ở 10 fps trông juddery và không tự nhiên. Khi bạn hiểu rằng preview không báo cáo giá trị nào trong số này, bí ẩn của call tệ với camera tốt được giải quyết.
SDP negotiate trước khi bạn gửi khung
Negotiation bắt đầu trước khi khung đầu tiên được gửi. Khi bạn tham gia call, platform và trình duyệt trao đổi Session Description Protocol (SDP) offer và answer. SDP quảng bá codec và media capability mỗi bên hỗ trợ; độ phân giải và khung hình thực sau đó negotiate thêm qua send và receive parameter và bị constrain bởi ước tính băng thông. Trong testing không chính thức trên Chrome 125 trên Windows 10 (tháng 5 2024), SDP answer được quan sát offer VP9 trước, sau H.264, sau VP8; trên Safari 17 trên macOS 14 (cùng thời điểm), H.264 xuất hiện trước. Các quan sát này được thực hiện trên một máy mỗi trình duyệt mà không có điều kiện mạng kiểm soát, nên chúng minh họa sự biến thiên tồn tại thay vì định nghĩa thứ tự phổ quát. Codec thực tế được chọn phụ thuộc trình duyệt, platform, SDP parameter, và khả năng phần cứng. Lựa chọn phổ biến bao gồm VP9, H.264, VP8, và AV1, nhưng không có thứ tự ưu tiên cố định duy nhất trên mọi platform.
Codec selection chỉ là bắt đầu. Khi call live, cơ chế thứ hai tiếp quản: ước tính băng thông. WebRTC liên tục monitor network path ở cả hai chiều và chạy congestion control algorithm — thường là Google Congestion Control — đo ba metric trên rolling basis:
- Packet loss, receiver báo qua RTCP feedback message.
- Round-trip time, delay giữa gửi packet và nhận acknowledgement đến nơi.
- Throughput, rate hiệu quả mà data thực sự cross kết nối.
Algorithm feed các metric này vào model ước tính băng thông network có thể carry hiện tại. Estimate đó trở thành target bit rate cho encoder, và encoder thích ứng output. Vòng lặp liên tục và nhanh: khi estimate drop, encoder re-encode ở bit rate thấp hơn trong phần giây.
Ngưỡng xấp xỉ và phụ thuộc congestion control algorithm cụ thể. Packet loss liên tục trên khoảng năm phần trăm có thể trigger giảm target bit rate, nhưng hành vi chính xác — rate drop bao nhiêu, độ phân giải hay khung hình cũng thay đổi, và ở mức loss nào — khác nhau theo algorithm, codec, và platform. Không có mapping phổ quát từ tỷ lệ loss sang độ phân giải output cụ thể. Vòng lặp feedback điều khiển các quyết định này được định nghĩa trong (Google: WebRTC Congestion Control Whitepaper, 2019; RFC 8888: Congestion Control Feedback for RTP). Stream 1080p ở 30 fps thường cần khoảng bốn đến sáu megabit mỗi giây upload bandwidth để trông sạch, dù điều này phụ thuộc codec, encoding setting, và scene complexity. Nếu estimator kết luận chỉ một megabit khả dụng, nó không cố ép stream qua — nó drop target, và encoder đáp ứng bằng cách hạ độ phân giải xuống 480p và khung hình xuống 15 fps. Nếu estimate rớt thêm, hình suy giảm nữa, xuống tới 320×240 talking head. Mỗi bước deliberate: mục tiêu giữ call sống và audio ổn định, và video quality là thứ đầu tiên bị hy sinh.

Ba pattern lỗi stream ẩn
Preview ẩn trạng thái thực của stream sau ba pattern lỗi định kỳ. Học nhận diện mỗi pattern qua triệu chứng, vì fix đúng khác nhau cho từng trường hợp. Cả ba chia sẻ một dấu: preview vẫn perfect suốt thời gian, vì nó được sample trước encoder. Chỉ stream encoded — và do đó màn hình người nhận — cho thấy hư hại.
Bit Rate Trap
Triệu chứng: Preview perfect và máy có idle CPU. Bên kia thấy hình mờ, low-resolution không bao giờ sharpen, kể cả trong khi tạm dừng. Recording local trông xuất sắc; call trông kém.
Chẩn đoán: Trình duyệt đã ước tính network không carry được full stream và cap bit rate, ép encoder thu độ phân giải. Constraint là upload bandwidth hoặc relay capacity của media server, không phải camera. Chạy speed test và so sánh upload đo được với bốn đến sáu megabit mà 1080p30 cần. Nếu bạn chia sẻ kết nối với thiết bị khác streaming, downloading, hoặc syncing, chúng cạnh tranh cùng budget.
Loss Threshold
Triệu chứng: Still image từ call trông fine, nhưng bất kỳ motion nào đều juddery và robotic. Audio vẫn smooth trong khi video stutter, và freeze ngắn xảy ra mỗi vài giây trước khi hình tiếp tục ở khung hình thấp hơn.
Chẩn đoán: Packet loss đang cross ngưỡng năm phần trăm intermittent, nên congestion controller liên tục cut target bit rate và encoder drop khung. Khung hình rớt đầu tiên vì là đòn rẻ nhất — giảm 30 xuống 15 fps cắt data rate пополăm không đổi độ phân giải. Kiểm tra Wi-Fi interference, Ethernet cable kém, hoặc VPN thêm loss và latency. Video sẽ tiếp tục suy giảm cho đến khi network path được sửa.
Keyframe Freeze
Triệu chứng: Trong hai đến năm giây đầu sau khi tham gia, hoặc sau khi share screen, bên kia thấy hình đóng băng hoặc smeared nặng. Rồi hình snap vào focus và hoạt động bình thường cho đến scene change lớn tiếp theo.
Chẩn đoán: Video codec gửi hai loại khung. Keyframe encode toàn bộ hình và xuất hiện ở interval cố định — thường mỗi một đến mười giây tùy platform và cấu hình. Delta frame chỉ encode thay đổi từ khung trước, khiến chúng nhỏ. Nếu packet từ delta frame bị lost, receiver không thể reconstruct khung đó — có thể request retransmission (NACK), xin keyframe mới (PLI hoặc FIR), hoặc conceal error trong khi chờ. Khi request thành công, recovery nhanh; khi không, hình đóng băng cho đến keyframe định kỳ tiếp theo. Khoảng chờ đó là freeze bạn thấy. Keyframe interval ngắn recovery nhanh nhưng tốn bandwidth; interval dài efficient nhưng mỗi loss rõ hơn. Đây không phải malfunction — là codec hoạt động đúng thiết kế.

Đo stream thực với getStats()
Ngừng đoán. Các con số không flattering, nhưng chúng true. WebRTC API expose statistics interface báo chính xác encoder đang làm gì, và bất kỳ web page nào bạn kiểm soát có thể đọc peer connection riêng. Gọi getStats() trên RTCPeerConnection object, rồi filter report cho outbound-rtp entry có kind là video. Trên entry media-source và outbound-rtp bạn sẽ tìm các giá trị quan trọng:
- framesPerSecond (trên entry media-source) — khung hình camera deliver cho encoder. Nếu dưới 30 trên camera 30 fps, capture path là vấn đề.
- framesPerSecond (trên entry outbound-rtp) — khung hình encoder thực sản xuất. Khi thấp hơn input rate, encoder đang drop khung.
- frameWidth và frameHeight (trên entry outbound-rtp) — độ phân giải encoded. So với cài đặt call; khác biệt nào là silent downgrade.
- bytesSent (trên entry outbound-rtp) — tổng encoded data. Sample hai lần cách một giây và tính difference × 8 để có real bit rate.
- packetsSent và packetsLost — lưu ý packetsLost trên entry outbound-rtp không luôn được populate; loss ratio đọc đáng tin hơn từ entry remote-inbound-rtp, báo góc nhìn receiver.
- currentRoundTripTime (trên entry candidate-pair) — network delay. RTT cao kết hợp loss chỉ thị congestion.
Trình duyệt khác có thể báo field name hơi khác hoặc bỏ sót thống kê, nên cross-check với WebRTC internals page của trình duyệt khi khả dụng.
Quy tắc diễn giải đơn giản. Nếu outbound-rtp framesPerSecond thấy thấp hơn media-source framesPerSecond, encoder đang shed khung dưới áp lực. Nếu frameWidth và frameHeight thấp hơn độ phân giải bạn cấu hình, connection budget không carry nổi. Nếu bytesSent quy đổi ra bit rate thấp hơn nhiều yêu cầu codec cho độ phân giải đó, hình đang bị crush — và preview, vốn không thấy encoder, sẽ trông fine suốt thời gian.
Bạn không cần viết code để đọc các giá trị. Chrome và Edge có statistics viewer tích hợp tại chrome://webrtc-internals capture mọi kết nối WebRTC trong trình duyệt, bao gồm cái platform call tạo. Mở trước khi tham gia meeting, cho record, và inspect outbound-rtp entry cho video sender sau đó. Cùng khung hình, độ phân giải, bit rate, và loss figure ở đó, cùng timeline graph cho thấy chính xác khi encoder thay đổi output. Đây là cách nhanh nhất catch downgrade trong act trên platform call thực.
Chạy đo lường này khi call của bạn idle trong background, rồi lại trong busy meeting, và so sánh hai bộ số. So sánh điển hình: idle, outbound-rtp framesPerSecond đọc 30; trong busy meeting có thể drop xuống 18 trong khi preview local vẫn 30. So sánh đó cho biết baseline network có đủ hay không và contention trong call có trigger downgrade hay không. Công cụ webcam test của chúng tôi hiện độ phân giải và khung hình của local capture track negotiate qua getUserMedia() — baseline hữu ích cho camera deliver gì cho trình duyệt, nhưng không phải đo lường outbound WebRTC encoded stream, vốn cần peer connection hoặc WebRTC internals page.
Zoom, Meet, Teams: Ba camera khác nhau
Cùng camera, cùng laptop, và cùng network có thể tạo kết quả khác nhau trên application khác, vì mỗi platform áp dụng encoding policy riêng lên trên WebRTC của trình duyệt.
- Zoom thường ưu tiên ổn định. Tùy version, loại tài khoản, và cài đặt meeting, có thể cap outgoing resolution và sacrifice video quality để giữ audio và screen share ổn định. Camera 1080p-capable có thể transmit 720p hoặc thấp hơn trên Zoom.
- Google Meet có xu hướng adapt theo băng thông đo được, drop resolution sớm và restore nhanh khi điều kiện tốt lên. Hành vi theo dõi trạng thái mạng thực, tốt lẫn xấu.
- Microsoft Teams áp dụng encoding và post-processing pipeline riêng. Tùy version và cài đặt meeting, hình có thể bị nén thêm ngoài raw WebRTC negotiation.
- Browser-native WebRTC, loại bạn có trong bare web page, gửi negotiated stream không platform policy. Là gần ground truth nhất cho phần cứng và network deliver dưới WebRTC thuần. Platform policy khác theo version, loại tài khoản, và cấu hình meeting, nên coi chúng là xu hướng chung thay vì quy tắc cố định.
Hệ quả thực tế: so sánh Zoom call với Meet call không phải test camera. Nó là test encoding decision mỗi platform. Đo raw stream trước với plain WebRTC page hoặc công cụ webcam test. Nếu raw stream sạch mà một platform vẫn tệ, policy platform là constraint, và không hardware upgrade nào thay đổi. Khi platform call đang chạy, chrome://webrtc-internals cho bạn xem encoder decision live, để biết downgrade là policy platform hay hành vi network mà không cần tin self-report bên nào.
Bảy bước stream sạch
Các bước này cô lập nguyên nhân riêng biệt. Bạn có thể dừng khi stream trông đúng — nhưng đo trước và sau mỗi thay đổi để xác nhận fix thực sự di chuyển số.
- Đo trước. Mở chrome://webrtc-internals hoặc dùng getStats() trên peer connection riêng và ghi độ phân giải, khung hình, và bit rate. Nếu raw stream đã downgrade, camera và kết nối là vấn đề. Nếu sạch, platform là.
- Kiểm tra băng thông. Video call cần ít nhất 1 Mbps upload cho 720p và khoảng 4 Mbps cho 1080p. Test từ máy bạn gọi, không phải thiết bị khác, và retest với traffic khác trên network. Chuyển sang wired nếu có thể; Wi-Fi loss là nguyên nhân phổ biến nhất của invisible downgrade.
- Sửa ánh sáng. Chủ thể đủ sáng compress tốt hơn nhiều so với tối, vì encoder dùng bit rate cho chi tiết nhìn thấy thay vì noise. Đối mặt cửa sổ hoặc dùng soft light. Điều này không tốn gì và thường tạo improvement lớn hơn bất kỳ setting nào.
- Tắt video noise reduction khi môi trường đã yên tĩnh và đủ sáng. Một số platform áp dụng denoise aggressive trong cảnh thiếu sáng, có thể làm mềm chi tiết tinh trong encoded stream. Preview local sẽ không thấy khác biệt; chỉ encoded stream sẽ. Kiểm tra cài đặt platform cụ thể.
- Tắt virtual background. Background segmentation thêm overhead vào effective bit rate và tiêu GPU cycle từ encoder. Nền thật sạch với ánh sáng nhất quán beat bất kỳ nền ảo nào.
- Kiểm tra codec. Nếu CPU đủ, VP9 deliver chất lượng/bit tốt nhất; nếu thấy frame drop hoặc CPU spike, H.264 encode nhanh hơn. Một số platform expose codec preference trong cài đặt.
- Test platform khác. Nếu chất lượng tốt trên một service và tệ trên service khác, encoding policy của platform là constraint. Điều chỉnh kỳ vọng hoặc meeting tool — phần cứng không lỗi.
Kết luận
Preview là local self-image của camera: view thuận lợi về camera deliver gì cho trình duyệt. Stream là thế giới thực sự thấy — negotiated, compressed, và shaped bởi điều kiện mạng và platform policy. Chúng là hai video khác nhau của cùng chủ thể, và chỉ một trong hai quan trọng cho bạn trông thế nào. Nếu bạn từng tự hỏi tại sao camera trông tuyệt trên màn hình nhưng tệ trong call, bạn giờ có câu trả lời và công cụ để đo.
Mở chrome://webrtc-internals. Tham gia call tiếp theo. Xem outbound-rtp entry. Nếu frameWidth hoặc framesPerSecond thấp hơn cài đặt camera, downgrade đang xảy ra. Nguyên nhân thường liên quan băng thông — trình duyệt được phép tiêu bao nhiêu, và kết nối có carry stream bạn nghĩ đang gửi hay không — nhưng CPU load, encoder selection, platform policy, và constraint configuration cũng có thể đóng góp hoặc chi phối sự suy giảm.