tor-browser

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

per-frame-qp-encoding.https.any.js (3699B)


      1 // META: global=window,dedicatedworker
      2 // META: script=/webcodecs/video-encoder-utils.js
      3 // META: variant=?av1
      4 // META: variant=?vp9_p0
      5 // META: variant=?vp9_p2
      6 
      7 function get_config() {
      8  const config = {
      9    '?av1': {codec: 'av01.0.04M.08'},
     10    '?vp8': {codec: 'vp8'},
     11    '?vp9_p0': {codec: 'vp09.00.10.08'},
     12    '?vp9_p2': {codec: 'vp09.02.10.10'},
     13    '?h264': {codec: 'avc1.42001E', avc: {format: 'annexb'}},
     14    '?h265': {codec: 'hev1.1.6.L93.90', hevc: {format: 'annexb'}}
     15  }[location.search];
     16  config.width = 320;
     17  config.height = 200;
     18  config.bitrate = 1000000;
     19  config.bitrateMode = 'quantizer';
     20  config.framerate = 30;
     21  return config;
     22 }
     23 
     24 function get_qp_range() {
     25  switch (location.search) {
     26    case '?av1':
     27      return {min: 1, max: 255};
     28    case '?vp9_p0':
     29      return {min: 1, max: 255};
     30    case '?vp9_p2':
     31      return {min: 1, max: 255};
     32    case '?h264':
     33      return {min: 1, max: 51};
     34    case '?h265':
     35      return {min: 1, max: 51};
     36  }
     37  return null;
     38 }
     39 
     40 function set_qp(options, value) {
     41  switch (location.search) {
     42    case '?av1':
     43      options.av1 = {quantizer: value};
     44      return;
     45    case '?vp9_p0':
     46      options.vp9 = {quantizer: value};
     47      return;
     48    case '?vp9_p2':
     49      options.vp9 = {quantizer: value};
     50      return;
     51    case '?h264':
     52      options.avc = {quantizer: value};
     53      return;
     54    case '?h265':
     55      options.hevc = {quantizer: value};
     56  }
     57 }
     58 
     59 async function per_frame_qp_test(t, encoder_config, qp_range, validate_result) {
     60  const w = encoder_config.width;
     61  const h = encoder_config.height;
     62  await checkEncoderSupport(t, encoder_config);
     63 
     64  const frames_to_encode = 12;
     65  let frames_decoded = 0;
     66  let frames_encoded = 0;
     67  let chunks = [];
     68  let corrupted_frames = [];
     69 
     70  const encoder_init = {
     71    output(chunk, metadata) {
     72      frames_encoded++;
     73      chunks.push(chunk);
     74    },
     75    error(e) {
     76      assert_unreached(e.message);
     77    }
     78  };
     79 
     80  let encoder = new VideoEncoder(encoder_init);
     81  encoder.configure(encoder_config);
     82 
     83  let qp = qp_range.min;
     84  for (let i = 0; i < frames_to_encode; i++) {
     85    let frame = createDottedFrame(w, h, i);
     86    let encode_options = {keyFrame: false};
     87    set_qp(encode_options, qp);
     88    encoder.encode(frame, encode_options);
     89    frame.close();
     90    qp += 3;
     91    if (qp > qp_range.max) {
     92      qp = qp_range.min
     93    }
     94  }
     95  await encoder.flush();
     96 
     97  let decoder = new VideoDecoder({
     98    output(frame) {
     99      frames_decoded++;
    100      // Check that we have intended number of dots and no more.
    101      // Completely black frame shouldn't pass the test.
    102      if (validate_result && !validateBlackDots(frame, frame.timestamp) ||
    103          validateBlackDots(frame, frame.timestamp + 1)) {
    104        corrupted_frames.push(frame.timestamp)
    105      }
    106      frame.close();
    107    },
    108    error(e) {
    109      assert_unreached(e.message);
    110    }
    111  });
    112 
    113  let decoder_config = {
    114    codec: encoder_config.codec,
    115    codedWidth: w,
    116    codedHeight: h,
    117  };
    118  decoder.configure(decoder_config);
    119 
    120  for (let chunk of chunks) {
    121    decoder.decode(chunk);
    122  }
    123  await decoder.flush();
    124 
    125  encoder.close();
    126  decoder.close();
    127  assert_equals(frames_encoded, frames_to_encode);
    128  assert_equals(chunks.length, frames_to_encode);
    129  assert_equals(frames_decoded, frames_to_encode);
    130  assert_equals(
    131      corrupted_frames.length, 0, `corrupted_frames: ${corrupted_frames}`);
    132 }
    133 
    134 promise_test(async t => {
    135  let config = get_config();
    136  let range = get_qp_range();
    137  return per_frame_qp_test(t, config, range, false);
    138 }, 'Frame QP encoding, full range');
    139 
    140 promise_test(async t => {
    141  let config = get_config();
    142  return per_frame_qp_test(t, config, {min: 1, max: 20}, true);
    143 }, 'Frame QP encoding, good range with validation');