70 lines
3 KiB
JavaScript
70 lines
3 KiB
JavaScript
|
|
/// <reference path="../pb_data/types.d.ts" />
|
||
|
|
|
||
|
|
// The decode ladder the device benchmark plays.
|
||
|
|
//
|
||
|
|
// One row per rung. The app downloads a rung (which measures the link, on a
|
||
|
|
// file big enough to escape TCP slow start) and then plays it from local
|
||
|
|
// storage (which measures the decoder, with the network out of the picture).
|
||
|
|
// Keeping those two apart is the whole point: on the owner's father's box the
|
||
|
|
// connection is fine and the hardware is not, and a test that streamed while it
|
||
|
|
// measured would blame the wrong one.
|
||
|
|
//
|
||
|
|
// Why a collection rather than files baked into amber-api: 76 MB does not
|
||
|
|
// belong in a Docker image that is rebuilt on every push, and a ladder that can
|
||
|
|
// be re-cut without shipping a release is a ladder that will actually be
|
||
|
|
// maintained.
|
||
|
|
//
|
||
|
|
// The clips are cut from Big Buck Bunny (c) Blender Foundation,
|
||
|
|
// peach.blender.org, CC-BY 3.0. Same ten seconds of high-motion footage at every
|
||
|
|
// rung, so only resolution, codec and bitrate differ. Each carries an E-AC3 5.1
|
||
|
|
// track on purpose: the television decodes compressed audio in-app through
|
||
|
|
// FFmpeg, so that cost is part of what "can this box play this file" means.
|
||
|
|
//
|
||
|
|
// The file is deliberately NOT protected. There is nothing to gate (the source
|
||
|
|
// is CC-BY) and an unprotected URL can be handed straight to a player. Listing
|
||
|
|
// still needs a signed-in account, like everything else here.
|
||
|
|
|
||
|
|
migrate(
|
||
|
|
(app) => {
|
||
|
|
const clips = new Collection({
|
||
|
|
type: "base",
|
||
|
|
name: "benchmark_clips",
|
||
|
|
listRule: "@request.auth.id != ''",
|
||
|
|
viewRule: "@request.auth.id != ''",
|
||
|
|
createRule: null,
|
||
|
|
updateRule: null,
|
||
|
|
deleteRule: null,
|
||
|
|
fields: [
|
||
|
|
// Stable identifier the app switches on; the label is what a person reads.
|
||
|
|
{ type: "text", name: "key", required: true, max: 20 },
|
||
|
|
{ type: "text", name: "label", required: true, max: 40 },
|
||
|
|
// Rungs are ordered, and the order is the answer: the highest rung that
|
||
|
|
// plays clean is what the box can do.
|
||
|
|
{ type: "number", name: "rung", required: true, min: 1, onlyInt: true },
|
||
|
|
{ type: "number", name: "width", required: true, min: 1, onlyInt: true },
|
||
|
|
{ type: "number", name: "height", required: true, min: 1, onlyInt: true },
|
||
|
|
{ type: "text", name: "codec", required: true, max: 20 },
|
||
|
|
{ type: "number", name: "bitrateBps", required: true, min: 1, onlyInt: true },
|
||
|
|
{ type: "number", name: "durationS", required: true, min: 1 },
|
||
|
|
{
|
||
|
|
type: "file",
|
||
|
|
name: "file",
|
||
|
|
required: true,
|
||
|
|
maxSelect: 1,
|
||
|
|
maxSize: 104857600,
|
||
|
|
protected: false,
|
||
|
|
},
|
||
|
|
{ type: "autodate", name: "created", onCreate: true },
|
||
|
|
{ type: "autodate", name: "updated", onCreate: true, onUpdate: true },
|
||
|
|
],
|
||
|
|
indexes: [
|
||
|
|
"CREATE UNIQUE INDEX idx_benchmark_clips_key ON benchmark_clips (key)",
|
||
|
|
],
|
||
|
|
});
|
||
|
|
app.save(clips);
|
||
|
|
},
|
||
|
|
(app) => {
|
||
|
|
app.delete(app.findCollectionByNameOrId("benchmark_clips"));
|
||
|
|
},
|
||
|
|
);
|