tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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');