video-encoder-h26x-annexb.https.any.js (12140B)
1 // META: global=window,dedicatedworker 2 // META: script=/webcodecs/video-encoder-utils.js 3 // META: variant=?h264_annexb_software 4 // META: variant=?h264_annexb_hardware 5 // META: variant=?h265_annexb_software 6 // META: variant=?h265_annexb_hardware 7 8 var ENCODER_CONFIG = null; 9 var ANNEXB_CODEC = '' 10 promise_setup(async () => { 11 const config = { 12 '?h264_annexb_software': { 13 codec: 'avc1.42001E', 14 avc: {format: 'annexb'}, 15 hardwareAcceleration: 'prefer-software', 16 }, 17 '?h264_annexb_hardware': { 18 codec: 'avc1.42001E', 19 avc: {format: 'annexb'}, 20 hardwareAcceleration: 'prefer-hardware', 21 }, 22 '?h265_annexb_software': { 23 codec: 'hvc1.1.6.L123.00', 24 hevc: {format: 'annexb'}, 25 hardwareAcceleration: 'prefer-software', 26 }, 27 '?h265_annexb_hardware': { 28 codec: 'hvc1.1.6.L123.00', 29 hevc: {format: 'annexb'}, 30 hardwareAcceleration: 'prefer-hardware', 31 } 32 }[location.search]; 33 if (config.avc) { 34 ANNEXB_CODEC = 'h264' 35 } 36 if (config.hevc) { 37 ANNEXB_CODEC = 'h265' 38 } 39 config.width = 320; 40 config.height = 200; 41 config.bitrate = 1000000; 42 config.framerate = 30; 43 ENCODER_CONFIG = config; 44 }); 45 46 // The code is inspired from https://source.chromium.org/chromium/chromium/src/+/main:media/formats/mp4/avc.cc;l=190;drc=a6567f4fac823a8a319652bdb5070b5b72a60f30 47 // and https://source.chromium.org/chromium/chromium/src/+/main:media/formats/mp4/hevc.cc;l=425;drc=a6567f4fac823a8a319652bdb5070b5b72a60f30? 48 49 function checkNaluSyntax(test, chunk) { 50 test.step(() => { 51 52 const buffer = new Uint8Array(chunk.byteLength); 53 const keyFrame = chunk.type === "key"; 54 chunk.copyTo(buffer); 55 56 const kAUDAllowed = 1; 57 const kBeforeFirstVCL = 2; // VCL == nal_unit_types 1-5 58 const kAfterFirstVCL = 3; 59 const kEOStreamAllowed = 4; 60 const kNoMoreDataAllowed = 5; 61 // Define constants for h264 NALU types 62 const kAUD = 9; 63 const kSEIMessage = 6; 64 const kPrefix = 14; 65 const kSubsetSPS = 15; 66 const kDPS = 16; 67 const kReserved17 = 17; 68 const kReserved18 = 18; 69 const kPPS = 8; 70 const kSPS = 7; 71 const kSPSExt = 13; 72 const kNonIDRSlice = 1; 73 const kSliceDataA = 2; 74 const kSliceDataB = 3; 75 const kSliceDataC = 4; 76 const kIDRSlice = 5; 77 const kCodedSliceAux = 19; 78 const kEOSeq = 10; 79 const kEOStream = 11; 80 const kFiller = 12; 81 const kUnspecified = 0; 82 // Define constants for h265 NALU types 83 const AUD_NUT = 35; 84 const VPS_NUT = 32; 85 const SPS_NUT = 33; 86 const PPS_NUT = 34; 87 const PREFIX_SEI_NUT = 39; 88 const RSV_NVCL41 = 41; 89 const RSV_NVCL42 = 42; 90 const RSV_NVCL43 = 43; 91 const RSV_NVCL44 = 44; 92 const UNSPEC48 = 48; 93 const UNSPEC49 = 49; 94 const UNSPEC50 = 50; 95 const UNSPEC51 = 51; 96 const UNSPEC52 = 52; 97 const UNSPEC53 = 53; 98 const UNSPEC54 = 54; 99 const UNSPEC55 = 55; 100 const FD_NUT = 38; 101 const SUFFIX_SEI_NUT = 40; 102 const RSV_NVCL45 = 45; 103 const RSV_NVCL46 = 46; 104 const RSV_NVCL47 = 47; 105 const UNSPEC56 = 56; 106 const UNSPEC57 = 57; 107 const UNSPEC58 = 58; 108 const UNSPEC59 = 59; 109 const UNSPEC60 = 60; 110 const UNSPEC61 = 61; 111 const UNSPEC62 = 62; 112 const UNSPEC63 = 63; 113 const EOS_NUT = 36; 114 const EOB_NUT = 37; 115 const TRAIL_N = 0; 116 const TRAIL_R = 1; 117 const TSA_N = 2; 118 const TSA_R = 3; 119 const STSA_N = 4; 120 const STSA_R = 5; 121 const RADL_N = 6; 122 const RADL_R = 7; 123 const RASL_N = 8; 124 const RASL_R = 9; 125 const RSV_VCL_N10 = 10; 126 const RSV_VCL_R11 = 11; 127 const RSV_VCL_N12 = 12; 128 const RSV_VCL_R13 = 13; 129 const RSV_VCL_N14 = 14; 130 const RSV_VCL_R15 = 15; 131 const RSV_VCL24 = 24; 132 const RSV_VCL25 = 25; 133 const RSV_VCL26 = 26; 134 const RSV_VCL27 = 27; 135 const RSV_VCL28 = 28; 136 const RSV_VCL29 = 29; 137 const RSV_VCL30 = 30; 138 const RSV_VCL31 = 31; 139 const BLA_W_LP = 16; 140 const BLA_W_RADL = 17; 141 const BLA_N_LP = 18; 142 const IDR_W_RADL = 19; 143 const IDR_N_LP = 20; 144 const CRA_NUT = 21; 145 const RSV_IRAP_VCL22 = 22; 146 const RSV_IRAP_VCL23 = 23; 147 148 let order_state = kAUDAllowed; 149 let lastBytes = [0xFF, 0xFF, 0xFF]; 150 for (let pos = 0; pos < buffer.length; pos++) { 151 if (lastBytes[0] == 0x00 && lastBytes[1] == 0x00 152 && lastBytes[2] == 0x01) { 153 let naluType = buffer[pos] & 0x1f; 154 if (ANNEXB_CODEC === "h264") { 155 switch (naluType) { 156 case kAUD: 157 assert_less_than_equal(order_state, kAUDAllowed, "Unexpected AUD in order_state " + order_state); 158 order_state = kBeforeFirstVCL; 159 break; 160 161 case kSEIMessage: 162 case kPrefix: 163 case kSubsetSPS: 164 case kDPS: 165 case kReserved17: 166 case kReserved18: 167 case kPPS: 168 case kSPS: 169 assert_less_than_equal(order_state, kBeforeFirstVCL, "Unexpected NALU type " + naluType + " in order_state " + order_state); 170 order_state = kBeforeFirstVCL; 171 break; 172 173 case kSPSExt: 174 assert_equals(last_nalu_type, kSPS, "SPS extension does not follow an SPS."); 175 break; 176 177 case kNonIDRSlice: 178 case kSliceDataA: 179 case kSliceDataB: 180 case kSliceDataC: 181 case kIDRSlice: 182 assert_less_than_equal(order_state, kAfterFirstVCL, "Unexpected VCL in order_state " + order_state); 183 assert_equals(naluType == kIDRSlice, keyFrame, "Keyframe indicator does not match: " + (naluType == kIDRSlice) + " versus " + keyFrame); 184 order_state = kAfterFirstVCL; 185 break; 186 187 case kCodedSliceAux: 188 assert_equals(order_state, kAfterFirstVCL, "Unexpected extension in order_state " + order_state); 189 break; 190 191 case kEOSeq: 192 assert_equals(order_state, kAfterFirstVCL, "Unexpected EOSeq in order_state " + order_state); 193 order_state = kEOStreamAllowed; 194 break; 195 196 case kEOStream: 197 assert_greater_than(kAfterFirstVCL, order_state, "Unexpected EOStream in order_state " + order_state); 198 order_state = kNoMoreDataAllowed; 199 break; 200 // These syntax elements are to simply be ignored according to H264 201 // Annex B 7.4.2.7 202 case kFiller: 203 case kUnspecified: 204 // These syntax elements are to simply be ignored according to H264 Annex B 7.4.2.7 205 break; 206 207 default: 208 assert_greater_than(naluType, 19, "NALU TYPE smaller than 20 for unknown type"); 209 break; 210 } 211 } else if (ANNEXB_CODEC === 'h265') { 212 // When any VPS NAL units, SPS NAL units, PPS NAL units, prefix SEI NAL 213 // units, NAL units with nal_unit_type in the range of 214 // RSV_NVCL41..RSV_NVCL44, or NAL units with nal_unit_type in the range of 215 // UNSPEC48..UNSPEC55 are present, they shall not follow the last VCL NAL 216 // unit of the access unit. 217 218 switch (naluType) { 219 case AUD_NUT: 220 assert_less_than_equal(order_state, kAUDAllowed, "Unexpected AUD in order_state " + order_state); 221 order_state = kBeforeFirstVCL; 222 break; 223 224 case VPS_NUT: 225 case SPS_NUT: 226 case PPS_NUT: 227 case PREFIX_SEI_NUT: 228 case RSV_NVCL41: 229 case RSV_NVCL42: 230 case RSV_NVCL43: 231 case RSV_NVCL44: 232 case UNSPEC48: 233 case UNSPEC49: 234 case UNSPEC50: 235 case UNSPEC51: 236 case UNSPEC52: 237 case UNSPEC53: 238 case UNSPEC54: 239 case UNSPEC55: 240 assert_less_than_equal(order_state, kBeforeFirstVCL, "Unexpected NALU type " + nalu.nal_unit_type + " in order_state " + order_state); 241 order_state = kBeforeFirstVCL; 242 break; 243 // NAL units having nal_unit_type equal to FD_NUT or SUFFIX_SEI_NUT or in 244 // the range of RSV_NVCL45..RSV_NVCL47 or UNSPEC56..UNSPEC63 shall not 245 // precede the first VCL NAL unit of the access unit. 246 case FD_NUT: 247 case SUFFIX_SEI_NUT: 248 case RSV_NVCL45: 249 case RSV_NVCL46: 250 case RSV_NVCL47: 251 case UNSPEC56: 252 case UNSPEC57: 253 case UNSPEC58: 254 case UNSPEC59: 255 case UNSPEC60: 256 case UNSPEC61: 257 case UNSPEC62: 258 case UNSPEC63: 259 assert_less_than_equal(order_state, kAfterFirstVC, "Unexpected NALU type " + nalu.nal_unit_type + " in order_state " + order_state); 260 break; 261 262 // When an end of sequence NAL unit is present, it shall be the last NAL 263 // unit among all NAL units in the access unit other than an end of 264 // bitstream NAL unit (when present). 265 case EOS_NUT: 266 assert_equals(order_state, kAfterFirstVCL, "Unexpected EOS in order_state " + order_state); 267 order_state = kEOBitstreamAllowed; 268 break; 269 // When an end of bitstream NAL unit is present, it shall be the last NAL 270 // unit in the access unit. 271 case EOB_NUT: 272 assert_less_than_equal(order_state, kAfterFirstVCL, "Unexpected EOB in order_state " + order_state); 273 order_state = kNoMoreDataAllowed; 274 break; 275 // VCL, non-IRAP 276 case TRAIL_N: 277 case TRAIL_R: 278 case TSA_N: 279 case TSA_R: 280 case STSA_N: 281 case STSA_R: 282 case RADL_N: 283 case RADL_R: 284 case RASL_N: 285 case RASL_R: 286 case RSV_VCL_N10: 287 case RSV_VCL_R11: 288 case RSV_VCL_N12: 289 case RSV_VCL_R13: 290 case RSV_VCL_N14: 291 case RSV_VCL_R15: 292 case RSV_VCL24: 293 case RSV_VCL25: 294 case RSV_VCL26: 295 case RSV_VCL27: 296 case RSV_VCL28: 297 case RSV_VCL29: 298 case RSV_VCL30: 299 case RSV_VCL31: 300 assert_less_than_equal(order_state, kAfterFirstVCL, "Unexpected VCL in order_state " + order_state); 301 order_state = kAfterFirstVCL; 302 break; 303 // VCL, IRAP 304 case BLA_W_LP: 305 case BLA_W_RADL: 306 case BLA_N_LP: 307 case IDR_W_RADL: 308 case IDR_N_LP: 309 case CRA_NUT: 310 case RSV_IRAP_VCL22: 311 case RSV_IRAP_VCL23: 312 assert_less_than_equal(order_state, kAfterFirstVCL, "Unexpected VCL in order_state " + order_state); 313 assert_equals(keyFrame, true, "The frame is coded as Keyframe, but indicator does not match"); 314 order_state = kAfterFirstVCL; 315 break; 316 317 default: 318 assert_true(false, "Unsupported NALU type " + naluType); 319 break; 320 }; 321 322 } 323 last_nalu_type = naluType; 324 } 325 lastBytes.push(buffer[pos]); 326 lastBytes.shift(); // advance reading 327 } 328 }) 329 } 330 331 async function runAnnexBTest(t) { 332 let encoder_config = { ...ENCODER_CONFIG }; 333 const w = encoder_config.width; 334 const h = encoder_config.height; 335 let frames_to_encode = 16; 336 337 await checkEncoderSupport(t, encoder_config); 338 339 const encodedResults = []; 340 const encoder_init = { 341 output(chunk, metadata) { 342 encodedResults.push(chunk); 343 }, 344 error(e) { 345 assert_unreached(e.message); 346 } 347 }; 348 349 let encoder = new VideoEncoder(encoder_init); 350 encoder.configure(encoder_config); 351 352 for (let i = 0; i < frames_to_encode; i++) { 353 let frame = createDottedFrame(w, h, i); 354 let keyframe = (i % 5 == 0); 355 encoder.encode(frame, { keyFrame: keyframe }); 356 frame.close(); 357 } 358 359 await encoder.flush(); 360 encoder.close(); 361 362 encodedResults.forEach((chunk) => checkNaluSyntax(t, chunk)); 363 364 assert_greater_than(encodedResults.length, 0, "frames_encoded"); 365 } 366 367 promise_test(async t => { 368 return runAnnexBTest(t); 369 }, 'Verify stream compliance h26x annexb');