Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  eme.js   Sprache: JAVA

 
/* import-globals-from manifest.js */

const CLEARKEY_KEYSYSTEM = "org.w3.clearkey";

const gCencMediaKeySystemConfig = [
  {
    initDataTypes: ["cenc"],
    videoCapabilities: [{ contentType: "video/mp4" }],
    audioCapabilities: [{ contentType: "audio/mp4" }],
  },
];

function bail(message) {
  return function (err) {
    if (err) {
      message += "; " + String(err);
    }
    ok(false, message);
    if (err) {
      info(String(err));
    }
    SimpleTest.finish();
  };
}

function ArrayBufferToString(arr) {
  var str = "";
  var view = new Uint8Array(arr);
  for (var i = 0; i < view.length; i++) {
    str += String.fromCharCode(view[i]);
  }
  return str;
}

function StringToArrayBuffer(str) {
  var arr = new ArrayBuffer(str.length);
  var view = new Uint8Array(arr);
  for (var i = 0; i < str.length; i++) {
    view[i] = str.charCodeAt(i);
  }
  return arr;
}

function StringToHex(str) {
  var res = "";
  for (var i = 0; i < str.length; ++i) {
    res += ("0" + str.charCodeAt(i).toString(16)).slice(-2);
  }
  return res;
}

function Base64ToHex(str) {
  var bin = window.atob(str.replace(/-/g, "+").replace(/_/g, "/"));
  var res = "";
  for (var i = 0; i < bin.length; i++) {
    res += ("0" + bin.charCodeAt(i).toString(16)).substr(-2);
  }
  return res;
}

function HexToBase64(hex) {
  var bin = "";
  for (var i = 0; i < hex.length; i += 2) {
    bin += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
  }
  return window
    .btoa(bin)
    .replace(/=/g, "")
    .replace(/\+/g, "-")
    .replace(/\//g, "_");
}

function TimeRangesToString(trs) {
  var l = trs.length;
  if (l === 0) {
    return "-";
  }
  var s = "";
  var i = 0;
  for (;;) {
    s += trs.start(i) + "-" + trs.end(i);
    if (++i === l) {
      return s;
    }
    s += ",";
  }
}

function SourceBufferToString(sb) {
  return (
    "SourceBuffer{" +
    "AppendMode=" +
    (sb.AppendMode || "-") +
    ", updating=" +
    (sb.updating ? "true" : "false") +
    ", buffered=" +
    TimeRangesToString(sb.buffered) +
    ", audioTracks=" +
    (sb.audioTracks ? sb.audioTracks.length : "-") +
    ", videoTracks=" +
    (sb.videoTracks ? sb.videoTracks.length : "-") +
    "}"
  );
}

function SourceBufferListToString(sbl) {
  return "SourceBufferList[" + sbl.map(SourceBufferToString).join(", ") + "]";
}

function GenerateClearKeyLicense(licenseRequest, keyStore) {
  var msgStr = ArrayBufferToString(licenseRequest);
  var msg = JSON.parse(msgStr);

  var keys = [];
  for (var i = 0; i < msg.kids.length; i++) {
    var id64 = msg.kids[i];
    var idHex = Base64ToHex(msg.kids[i]).toLowerCase();
    var key = keyStore[idHex];

    if (key) {
      keys.push({
        kty: "oct",
        kid: id64,
        k: HexToBase64(key),
      });
    }
  }

  return new TextEncoder().encode(
    JSON.stringify({
      keys,
      type: msg.type || "temporary",
    })
  );
}

function UpdateSessionFunc(test, token, sessionType, resolve, reject) {
  return function (ev) {
    var license = GenerateClearKeyLicense(ev.message, test.keys);
    Log(
      token,
      "sending update message to CDM: " + new TextDecoder().decode(license)
    );
    ev.target
      .update(license)
      .then(function () {
        Log(token, "MediaKeySession update ok!");
        resolve(ev.target);
      })
      .catch(function (reason) {
        reject(`${token} MediaKeySession update failed: ${reason}`);
      });
  };
}

function MaybeCrossOriginURI(test, uri) {
  if (test.crossOrigin) {
    return "https://example.com:443/tests/dom/media/test/allowed.sjs?" + uri;
  }
  return uri;
}

function AppendTrack(test, ms, track, token) {
  return new Promise(function (resolve, reject) {
    var sb;
    var curFragment = 0;
    var fragments = track.fragments;
    var fragmentFile;

    function addNextFragment() {
      if (curFragment >= fragments.length) {
        Log(token, track.name + ": end of track");
        resolve();
        return;
      }

      fragmentFile = MaybeCrossOriginURI(test, fragments[curFragment++]);

      var req = new XMLHttpRequest();
      req.open("GET", fragmentFile);
      req.responseType = "arraybuffer";

      req.addEventListener("load"function () {
        Log(
          token,
          track.name + ": fetch of " + fragmentFile + " complete, appending"
        );
        sb.appendBuffer(new Uint8Array(req.response));
      });

      req.addEventListener("error"function () {
        reject(`${token} - ${track.name}: error fetching ${fragmentFile}`);
      });
      req.addEventListener("abort"function () {
        reject(`${token} - ${track.name}: aborted fetching ${fragmentFile}`);
      });

      Log(
        token,
        track.name +
          ": addNextFragment() fetching next fragment " +
          fragmentFile
      );
      req.send(null);
    }

    Log(token, track.name + ": addSourceBuffer(" + track.type + ")");
    sb = ms.addSourceBuffer(track.type);
    sb.addEventListener("updateend"function () {
      Log(
        token,
        track.name +
          ": updateend for " +
          fragmentFile +
          ", " +
          SourceBufferToString(sb)
      );
      addNextFragment();
    });

    addNextFragment();
  });
}

//Returns a promise that is resolved when the media element is ready to have
//its play() function called; when it's loaded MSE fragments.
function LoadTest(test, elem, token, endOfStream = true) {
  if (!test.tracks) {
    ok(false, token + " test does not have a tracks list");
    return Promise.reject();
  }

  var ms = new MediaSource();
  elem.src = URL.createObjectURL(ms);
  elem.crossOrigin = test.crossOrigin || false;

  return new Promise(function (resolve, reject) {
    ms.addEventListener(
      "sourceopen",
      function () {
        Log(token, "sourceopen");
        Promise.all(
          test.tracks.map(function (track) {
            return AppendTrack(test, ms, track, token);
          })
        )
          .then(function () {
            Log(token, "Tracks loaded, calling MediaSource.endOfStream()");
            if (endOfStream) {
              ms.endOfStream();
            }
            resolve();
          })
          .catch(reject);
      },
      { once: true }
    );
  });
}

function EMEPromise() {
  var self = this;
  self.promise = new Promise(function (resolve, reject) {
    self.resolve = resolve;
    self.reject = reject;
  });
}

/*
 * Create a new MediaKeys object.
 * Return a promise which will be resolved with a new MediaKeys object,
 * or will be rejected with a string that describes the failure.
 */

function CreateMediaKeys(v, test, token) {
  let p = new EMEPromise();

  function streamType(type) {
    var x = test.tracks.find(o => o.name == type);
    return x ? x.type : undefined;
  }

  function onencrypted(ev) {
    var options = { initDataTypes: [ev.initDataType] };
    if (streamType("video")) {
      options.videoCapabilities = [{ contentType: streamType("video") }];
    }
    if (streamType("audio")) {
      options.audioCapabilities = [{ contentType: streamType("audio") }];
    }
    navigator.requestMediaKeySystemAccess(CLEARKEY_KEYSYSTEM, [options]).then(
      keySystemAccess => {
        keySystemAccess
          .createMediaKeys()
          .then(p.resolve, () =>
            p.reject(`${token} Failed to create MediaKeys object.`)
          );
      },
      () => p.reject(`${token} Failed to request key system access.`)
    );
  }

  v.addEventListener("encrypted", onencrypted, { once: true });
  return p.promise;
}

/*
 * Create a new MediaKeys object and provide it to the media element.
 * Return a promise which will be resolved if succeeded, or will be rejected
 * with a string that describes the failure.
 */

function CreateAndSetMediaKeys(v, test, token) {
  let p = new EMEPromise();

  CreateMediaKeys(v, test, token).then(mediaKeys => {
    v.setMediaKeys(mediaKeys).then(p.resolve, () =>
      p.reject(`${token} Failed to set MediaKeys on <video> element.`)
    );
  }, p.reject);

  return p.promise;
}

/*
 * Collect the init data from 'encrypted' events.
 * Return a promise which will be resolved with the init data when collection
 * is completed (specified by test.sessionCount).
 */

function LoadInitData(v, test, token) {
  let p = new EMEPromise();
  let initDataQueue = [];

  // Call SimpleTest._originalSetTimeout() to bypass the flaky timeout checker.
  let timer = SimpleTest._originalSetTimeout.call(
    window,
    () => {
      p.reject(`${token} Timed out in waiting for the init data.`);
    },
    60000
  );

  function onencrypted(ev) {
    initDataQueue.push(ev);
    Log(
      token,
      `got encrypted(${ev.initDataType}, ` +
        `${StringToHex(ArrayBufferToString(ev.initData))}) event.`
    );
    if (test.sessionCount == initDataQueue.length) {
      p.resolve(initDataQueue);
      clearTimeout(timer);
    }
  }

  v.addEventListener("encrypted", onencrypted);
  return p.promise;
}

/*
 * Generate a license request and update the session.
 * Return a promsise which will be resolved with the updated session
 * or rejected with a string that describes the failure.
 */

function MakeRequest(test, token, ev, session, sessionType) {
  sessionType = sessionType || "temporary";
  let p = new EMEPromise();
  let str =
    `session[${session.sessionId}].generateRequest(` +
    `${ev.initDataType}, ${StringToHex(ArrayBufferToString(ev.initData))})`;

  session.addEventListener(
    "message",
    UpdateSessionFunc(test, token, sessionType, p.resolve, p.reject)
  );

  Log(token, str);
  session.generateRequest(ev.initDataType, ev.initData).catch(reason => {
    // Reject the promise if generateRequest() failed.
    // Otherwise it will be resolved in UpdateSessionFunc().
    p.reject(`${token}: ${str} failed; ${reason}`);
  });

  return p.promise;
}

/*
 * Process the init data by calling MakeRequest().
 * Return a promise which will be resolved with the updated sessions
 * when all init data are processed or rejected if any failure.
 */

function ProcessInitData(v, test, token, initData, sessionType) {
  return Promise.all(
    initData.map(ev => {
      let session = v.mediaKeys.createSession(sessionType);
      return MakeRequest(test, token, ev, session, sessionType);
    })
  );
}

/*
 * Clean up the |v| element.
 */

function CleanUpMedia(v) {
  v.setMediaKeys(null);
  v.remove();
  v.removeAttribute("src");
  v.load();
}

/*
 * Close all sessions and clean up the |v| element.
 */

function CloseSessions(v, sessions) {
  return Promise.all(sessions.map(s => s.close())).then(CleanUpMedia(v));
}

/*
 * Set up media keys and source buffers for the media element.
 * Return a promise resolved when all key sessions are updated or rejected
 * if any failure.
 */

function SetupEME(v, test, token) {
  let p = new EMEPromise();

  v.onerror = function () {
    p.reject(`${token} got an error event.`);
  };

  Promise.all([
    LoadInitData(v, test, token),
    CreateAndSetMediaKeys(v, test, token),
    LoadTest(test, v, token),
  ])
    .then(values => {
      let initData = values[0];
      return ProcessInitData(v, test, token, initData);
    })
    .then(p.resolve, p.reject);

  return p.promise;
}

function fetchWithXHR(uri, onLoadFunction) {
  var p = new Promise(function (resolve) {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", uri, true);
    xhr.responseType = "arraybuffer";
    xhr.addEventListener("load"function () {
      is(
        xhr.status,
        200,
        "fetchWithXHR load uri='" + uri + "' status=" + xhr.status
      );
      resolve(xhr.response);
    });
    xhr.send();
  });

  if (onLoadFunction) {
    p.then(onLoadFunction);
  }

  return p;
}

function once(target, name, cb) {
  var p = new Promise(function (resolve) {
    target.addEventListener(
      name,
      function (arg) {
        resolve(arg);
      },
      { once: true }
    );
  });
  if (cb) {
    p.then(cb);
  }
  return p;
}

Messung V0.5
C=87 H=95 G=90

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge