simple video test (2)

now with DASH (instead of HLS)
This commit is contained in:
Alan Daniels 2025-11-09 19:04:55 +11:00
parent fc4558be2c
commit c8b232d494
9 changed files with 342 additions and 11 deletions

View file

@ -1,3 +1,14 @@
# OwnMedia
Built with Zig 0.15.1 & Vite 7.1.12
## Testing different file streaming methods
### HLS
```sh
ffmpeg -i test.mp4 -codec: copy -hls_time 10 -hls_list_size 0 -f hls test.m3u8
```
### DASH
```sh
ffmpeg -i test.mp4 -map 0:v:0 -map 0:a:0 -codec: copy -use_timeline 1 -use_template 1 -f dash test.mpd
```

197
package-lock.json generated
View file

@ -6,6 +6,7 @@
"": {
"dependencies": {
"@inertiajs/vue3": "^2.2.11",
"dashjs": "^5.0.3",
"hls.js": "^1.6.14",
"tailwindcss": "^4.1.16"
},
@ -1245,6 +1246,12 @@
"win32"
]
},
"node_modules/@svta/common-media-library": {
"version": "0.12.4",
"resolved": "https://registry.npmjs.org/@svta/common-media-library/-/common-media-library-0.12.4.tgz",
"integrity": "sha512-9EuOoaNmz7JrfGwjsrD9SxF9otU5TNMnbLu1yU4BeLK0W5cDxVXXR58Z89q9u2AnHjIctscjMTYdlqQ1gojTuw==",
"license": "Apache-2.0"
},
"node_modules/@tailwindcss/node": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.16.tgz",
@ -1682,6 +1689,45 @@
"proxy-from-env": "^1.1.0"
}
},
"node_modules/bcp-47": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/bcp-47/-/bcp-47-2.1.0.tgz",
"integrity": "sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w==",
"license": "MIT",
"dependencies": {
"is-alphabetical": "^2.0.0",
"is-alphanumerical": "^2.0.0",
"is-decimal": "^2.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/bcp-47-match": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-2.0.3.tgz",
"integrity": "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/bcp-47-normalize": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/bcp-47-normalize/-/bcp-47-normalize-2.3.0.tgz",
"integrity": "sha512-8I/wfzqQvttUFz7HVJgIZ7+dj3vUaIyIxYXaTRP1YWoSDfzt6TUmxaKZeuXR62qBmYr+nvuWINFRl6pZ5DlN4Q==",
"license": "MIT",
"dependencies": {
"bcp-47": "^2.0.0",
"bcp-47-match": "^2.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
@ -1753,6 +1799,12 @@
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/codem-isoboxer": {
"version": "0.3.10",
"resolved": "https://registry.npmjs.org/codem-isoboxer/-/codem-isoboxer-0.3.10.tgz",
"integrity": "sha512-eNk3TRV+xQMJ1PEj0FQGY8KD4m0GPxT487XJ+Iftm7mVa9WpPFDMWqPt+46buiP5j5Wzqe5oMIhqBcAeKfygSA==",
"license": "MIT"
},
"node_modules/colorjs.io": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz",
@ -1781,6 +1833,24 @@
"license": "MIT",
"peer": true
},
"node_modules/dashjs": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/dashjs/-/dashjs-5.0.3.tgz",
"integrity": "sha512-TXndNnCUjFjF2nYBxDVba+hWRpVkadkQ8flLp7kHkem+5+wZTfRShJCnVkPUosmjS0YPE9fVNLbYPJxHBeQZvA==",
"license": "BSD-3-Clause",
"dependencies": {
"@svta/common-media-library": "^0.12.4",
"bcp-47-match": "^2.0.3",
"bcp-47-normalize": "^2.3.0",
"codem-isoboxer": "0.3.10",
"fast-deep-equal": "3.1.3",
"html-entities": "^2.5.2",
"imsc": "^1.1.5",
"localforage": "^1.10.0",
"path-browserify": "^1.0.1",
"ua-parser-js": "^1.0.37"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@ -1935,6 +2005,12 @@
"license": "MIT",
"peer": true
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"license": "MIT"
},
"node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
@ -2141,6 +2217,28 @@
"integrity": "sha512-CSpT2aXsv71HST8C5ETeVo+6YybqCpHBiYrCRQSn3U5QUZuLTSsvtq/bj+zuvjLVADeKxoebzo16OkH8m1+65Q==",
"license": "Apache-2.0"
},
"node_modules/html-entities": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz",
"integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/mdevils"
},
{
"type": "patreon",
"url": "https://patreon.com/mdevils"
}
],
"license": "MIT"
},
"node_modules/immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
"license": "MIT"
},
"node_modules/immutable": {
"version": "5.1.4",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz",
@ -2150,6 +2248,49 @@
"optional": true,
"peer": true
},
"node_modules/imsc": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/imsc/-/imsc-1.1.5.tgz",
"integrity": "sha512-V8je+CGkcvGhgl2C1GlhqFFiUOIEdwXbXLiu1Fcubvvbo+g9inauqT3l0pNYXGoLPBj3jxtZz9t+wCopMkwadQ==",
"license": "BSD-2-Clause",
"dependencies": {
"sax": "1.2.1"
}
},
"node_modules/is-alphabetical": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
"integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/is-alphanumerical": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz",
"integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==",
"license": "MIT",
"dependencies": {
"is-alphabetical": "^2.0.0",
"is-decimal": "^2.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/is-decimal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz",
"integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@ -2199,6 +2340,15 @@
"jiti": "lib/jiti-cli.mjs"
}
},
"node_modules/lie": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
"integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==",
"license": "MIT",
"dependencies": {
"immediate": "~3.0.5"
}
},
"node_modules/lightningcss": {
"version": "1.30.2",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz",
@ -2460,6 +2610,15 @@
"url": "https://opencollective.com/parcel"
}
},
"node_modules/localforage": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
"integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==",
"license": "Apache-2.0",
"dependencies": {
"lie": "3.1.1"
}
},
"node_modules/lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
@ -2575,6 +2734,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/path-browserify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
"license": "MIT"
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@ -3105,6 +3270,12 @@
"node": ">=14.0.0"
}
},
"node_modules/sax": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz",
"integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==",
"license": "ISC"
},
"node_modules/side-channel": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
@ -3291,6 +3462,32 @@
"license": "0BSD",
"optional": true
},
"node_modules/ua-parser-js": {
"version": "1.0.41",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.41.tgz",
"integrity": "sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/ua-parser-js"
},
{
"type": "paypal",
"url": "https://paypal.me/faisalman"
},
{
"type": "github",
"url": "https://github.com/sponsors/faisalman"
}
],
"license": "MIT",
"bin": {
"ua-parser-js": "script/cli.js"
},
"engines": {
"node": "*"
}
},
"node_modules/varint": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz",

View file

@ -6,6 +6,7 @@
},
"dependencies": {
"@inertiajs/vue3": "^2.2.11",
"dashjs": "^5.0.3",
"hls.js": "^1.6.14",
"tailwindcss": "^4.1.16"
}

View file

@ -25,13 +25,18 @@ pub fn SendInertiaResponse(endpoint: anytype, context: *@This(), r: zap.Request,
// const tags = try model_tag.getTopLevelTags(context.db_connection, arena);
// const cats = try model_cat.getTopLevelcats(context.db_connection, arena);
var uri = endpoint.path;
if (r.query) |q| {
uri = try std.fmt.allocPrint(arena, "{s}?{s}", .{ endpoint.path, q });
}
const inertia_json = try std.fmt.allocPrint(
arena,
"{f}",
.{std.json.fmt(.{
.component = component,
.props = props,
.url = endpoint.path,
.url = uri,
.version = "",
}, .{
.escape_unicode = true,

View file

@ -16,12 +16,8 @@ import { Link } from "@inertiajs/vue3";
</div>
</header>
<div class="p-4 h-full">
<div class="p-4 bg-rose-950 rounded h-full">
<slot />
</div>
<slot />
</div>
<footer class="bg-slate-800 px-4">
footer
</footer>
<footer class="bg-slate-800 px-4">footer</footer>
</div>
</template>

View file

@ -0,0 +1,81 @@
<template>
<video
@pause="pause"
@ended="pause"
@keyup="changeSpeed"
ref="video"
:poster="previewImageLink"
:controls="isControls"
:title="title"
>
<source :src="link"/>
</video>
</template>
<script setup>
import { onMounted, onUpdated, ref } from "vue";
import * as dashjs from 'dashjs'
const props = defineProps({
previewImageLink: {
type: String,
default: "",
},
link: {
type: String,
default: "",
},
progress: {
type: Number,
default: 0,
},
title: {
type: String,
default: "",
},
isMuted: {
type: Boolean,
default: false,
},
isControls: {
type: Boolean,
default: true,
},
});
const emit = defineEmits(["pause", "test"]);
const video = ref(null);
onMounted(() => {
prepareVideoPlayer();
});
onUpdated(() => {
prepareVideoPlayer();
});
function prepareVideoPlayer() {
let player = dashjs.MediaPlayer().create();
player.initialize();
player.attachSource(props.link);
if (video.value) {
player.attachView(video.value);
video.value.muted = props.isMuted;
video.value.currentTime = props.progress;
}
}
function pause() {
const currentTime = video?.value?.currentTime || 0;
emit("pause", currentTime);
}
function changeSpeed(e) {
if (e.key === "w" && video.value) {
video.value.playbackRate = video.value.playbackRate + 0.25;
} else if (e.key === "s" && video.value) {
video.value.playbackRate = video.value.playbackRate - 0.25;
}
}
</script>

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import Layout from "@/layout/Layout.vue";
import { Head, Link } from "@inertiajs/vue3";
import BasePlayer from "./BasePlayer.vue";
import BasePlayer from "./BasePlayerDASH.vue";
const props = defineProps<{ thread_id; counter }>();
@ -9,11 +9,11 @@ function pause(currentTime) {
console.log("PAUSE", currentTime);
}
const link = '/test.m3u8';
const previewImageLink = '/test.jpg';
const link = "/test.mpd";
const previewImageLink = "/test.jpg";
const isMuted = false;
const isControls = true;
const progress_S = 15;
const progress_S = 0;
</script>
<template>

View file

@ -0,0 +1,40 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const builtin = @import("builtin");
const optimize_mode = builtin.mode;
const zap = @import("zap");
const sqlite = @import("sqlite");
// The global Application Context
const Context = @import("Context");
// A very simple endpoint handling only GET requests
const SimpleEndpoint = struct {
// zap.App.Endpoint Interface part
path: []const u8,
error_strategy: zap.Endpoint.ErrorStrategy = .log_to_response,
// data specific for this endpoint
component: []const u8,
pub fn init(path: []const u8, data: []const u8) SimpleEndpoint {
return .{
.path = path,
.component = data,
};
}
// handle GET requests
pub fn get(e: *SimpleEndpoint, arena: Allocator, context: *Context, r: zap.Request) !void {
const thread_id = std.Thread.getCurrentId();
r.setStatus(.ok);
try Context.SendInertiaResponse(e, context, r, arena, e.component, .{
.thread_id = thread_id,
.counter = context.counter,
});
context.*.counter += 1;
}
};