test_peerConnection_videoCodecs.html (6658B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <script type="application/javascript" src="pc.js"></script> 5 <script type="application/javascript" src="stats.js"></script> 6 <script type="application/javascript" src="/tests/dom/canvas/test/captureStream_common.js"></script> 7 </head> 8 <body> 9 <pre id="test"> 10 <script type="application/javascript"> 11 createHTML({ 12 bug: "1395853", 13 title: "Verify video content over WebRTC for every video codec", 14 }); 15 16 async function testVideoCodec(options = {}, codec) { 17 const test = new PeerConnectionTest(options); 18 test.setMediaConstraints([{video: true}], []); 19 20 let payloadType; 21 test.chain.insertBefore("PC_LOCAL_SET_LOCAL_DESCRIPTION", [ 22 function PC_LOCAL_FILTER_OUT_CODECS() { 23 const id = sdputils.findCodecId(test.originalOffer.sdp, codec.name, codec.offset); 24 payloadType = Number(id); 25 const otherIds = []; 26 for (const otherCodec of codecs) { 27 const otherId = sdputils.findCodecId(test.originalOffer.sdp, otherCodec.name, otherCodec.offset); 28 const otherRtpmapMatcher = new RegExp(`a=rtpmap:${otherId}.*\\r\\n`, "gi"); 29 30 if (codec.offset) { 31 isnot(id, sdputils.findCodecId(test.originalOffer.sdp, codec.name, 0), 32 "Different offsets should return different payload types"); 33 } 34 if (Number(otherId) != id) { 35 otherIds.push(otherId); 36 } 37 } 38 39 test.originalOffer.sdp = 40 sdputils.removeAllButPayloadType(test.originalOffer.sdp, id); 41 42 // Bug 1901160 test receiving signaling with no H264 profile-level-id fmtp. 43 if (codec.hasOwnProperty("fmtpOverride")) { 44 test.originalOffer.sdp = test.originalOffer.sdp.replace(new RegExp(`(a=fmtp:${id}).*(\\r\\n)`, "gi"), `$1 ${codec.fmtpOverride}$2`); 45 } 46 47 for (const otherId of otherIds) { 48 ok(!test.originalOffer.sdp.match(new RegExp(`m=.*UDP/TLS/RTP/SAVPF.* ${otherId}[^0-9]`, "gi")), 49 `Other codec ${otherId} should be removed after filtering`); 50 } 51 ok(test.originalOffer.sdp.match(new RegExp(`m=.*UDP/TLS/RTP/SAVPF.* ${id}[^0-9]`, "gi")), 52 `Tested codec ${id} should remain after filtering`); 53 54 // We only set it now, or the framework would remove non-H264 codecs 55 // for us. 56 options.h264 = codec.name == "H264"; 57 // Ditto for AV1. 58 options.av1 = codec.name == "AV1"; 59 }, 60 ]); 61 62 test.chain.insertAfter("PC_LOCAL_WAIT_FOR_MEDIA_FLOW", 63 [PC_LOCAL_TEST_LOCAL_STATS]); 64 65 test.chain.insertAfter("PC_REMOTE_WAIT_FOR_MEDIA_FLOW", 66 [PC_REMOTE_TEST_REMOTE_STATS]); 67 68 test.chain.append([ 69 async function PC_LOCAL_TEST_CODEC() { 70 const stats = await test.pcLocal._pc.getStats(); 71 let codecCount = 0; 72 stats.forEach(stat => { 73 if (stat.type == "codec") { 74 is(codecCount++, 0, "expected only one encode codec stat"); 75 is(stat.payloadType, payloadType, "payloadType as expected"); 76 is(stat.mimeType, `video/${codec.name}`, "mimeType as expected"); 77 is(stat.codecType, "encode", "codecType as expected"); 78 } 79 }); 80 }, 81 async function PC_REMOTE_TEST_CODEC() { 82 const stats = await test.pcRemote._pc.getStats(); 83 let codecCount = 0; 84 stats.forEach(stat => { 85 if (stat.type == "codec") { 86 is(codecCount++, 0, "expected only one decode codec stat"); 87 is(stat.payloadType, payloadType, "payloadType as expected"); 88 is(stat.mimeType, `video/${codec.name}`, "mimeType as expected"); 89 is(stat.codecType, "decode", "codecType as expected"); 90 } 91 }); 92 }, 93 ]); 94 95 if (!navigator.userAgent.includes("Android")) { 96 // TODO: enable on Android when bug 1526207 is fixed. 97 test.chain.append([ 98 async function CHECK_VIDEO_FLOW() { 99 try { 100 const h = new VideoStreamHelper(); 101 await h.checkVideoPlaying( 102 test.pcRemote.remoteMediaElements[0], 103 10, 10, 128); 104 ok(true, `Got video flow for codec ${codec.name}, offset ${codec.offset}`); 105 } catch(e) { 106 ok(false, `No video flow for codec ${codec.name}, offset ${codec.offset}: ${e}`); 107 } 108 }, 109 ]); 110 } 111 112 await test.run(); 113 } 114 115 // We match the name against the sdp to figure out the payload type, 116 // so all other present codecs can be removed. 117 // Use `offset` when there are multiple instances of a codec expected in an sdp. 118 const codecs = [ 119 { name: "VP8" }, 120 { name: "VP9" }, 121 { name: "H264" }, 122 { name: "AV1" }, 123 ]; 124 125 runNetworkTest(async (options) => { 126 const h264Support = checkPlatformH264CodecPrefs(); 127 128 // This test expects the video being captured will change color. Use fake 129 // video device as loopback does not currently change. 130 await pushPrefs( 131 ['media.video_loopback_dev', ''], 132 ['media.navigator.streams.fake', true], 133 ["media.navigator.video.disable_h264_baseline", false], 134 ); 135 136 if (h264Support.webrtc) { 137 codecs.push( 138 { name: "H264", offset: 1 }, 139 { name: "H264", offset: 2 }, 140 { name: "H264", offset: 2, fmtpOverride: "packetization-mode=1" }, 141 { name: "H264", offset: 3 }, 142 { name: "H264", offset: 3, fmtpOverride: "packetization-mode=0" }, 143 { name: "H264", offset: 3, fmtpOverride: "" } 144 ); 145 } else { 146 // With only platform encoders we don't signal packetization-mode=0 as 147 // not all platforms support slice size control. 148 codecs.push( 149 { name: "H264", offset: 1 }, 150 { name: "H264", offset: 1, fmtpOverride: "packetization-mode=1" }, 151 ); 152 } 153 154 for (const codec of codecs) { 155 let libWebrtcCodec = true; 156 if (codec.name == "H264") { 157 libWebrtcCodec = h264Support.webrtc; 158 } 159 // Use builtin webrtc encoders where possible. 160 await pushPrefs( 161 ['media.webrtc.encoder_creation_strategy', !libWebrtcCodec], 162 // Don't use MediaDataDecoder with fakeopenh264. Remove this when we 163 // return a valid bitstream from fakeopenh264(bug 1509012). 164 ['media.navigator.mediadatadecoder_h264_enabled', !libWebrtcCodec], 165 ); 166 167 info(`Testing video for codec ${codec.name} offset ${codec.offset}`); 168 try { 169 await timerGuard(testVideoCodec(options, codec), 20000, `codec=${JSON.stringify(codec)}`); 170 } catch(e) { 171 ok(false, `Error in test for codec ${codec.name}: ${e}\n${e.stack}`); 172 } 173 info(`Tested video for codec ${codec.name}`); 174 } 175 }); 176 </script> 177 </pre> 178 </body> 179 </html>