diff --git a/README.md b/README.md index 22e9373..7af173b 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ This can be accessed via WebTransport on `https://localhost:4443` by default. The web assets need to be hosted with a HTTPS server. If you're using a self-signed certificate, you may need to ignore the security warning in Chrome (Advanced -> proceed to localhost). ``` -cd player +cd web yarn install yarn serve ``` diff --git a/cert/generate b/cert/generate index d89953d..bcbf9c9 100755 --- a/cert/generate +++ b/cert/generate @@ -17,4 +17,4 @@ go run filippo.io/mkcert -ecdsa -install go run filippo.io/mkcert -ecdsa -days 10 -cert-file "$CRT" -key-file "$KEY" localhost 127.0.0.1 ::1 # Compute the sha256 fingerprint of the certificate for WebTransport -openssl x509 -in "$CRT" -outform der | openssl dgst -sha256 > ../player/fingerprint.hex +openssl x509 -in "$CRT" -outform der | openssl dgst -sha256 > ../web/fingerprint.hex diff --git a/player/.gitignore b/web/.gitignore similarity index 100% rename from player/.gitignore rename to web/.gitignore diff --git a/player/.proxyrc.js b/web/.proxyrc.js similarity index 100% rename from player/.proxyrc.js rename to web/.proxyrc.js diff --git a/player/package.json b/web/package.json similarity index 100% rename from player/package.json rename to web/package.json diff --git a/web/src/broadcaster/encoder.ts b/web/src/broadcaster/encoder.ts new file mode 100644 index 0000000..91b96b6 --- /dev/null +++ b/web/src/broadcaster/encoder.ts @@ -0,0 +1,104 @@ +import * as MP4 from "../mp4" + +export class Encoder { + container: MP4.ISOFile + audio: AudioEncoder + video: VideoEncoder + + constructor() { + this.container = new MP4.ISOFile(); + + this.audio = new AudioEncoder({ + output: this.onAudio.bind(this), + error: console.warn, + }); + + this.video = new VideoEncoder({ + output: this.onVideo.bind(this), + error: console.warn, + }); + + this.container.init(); + + this.audio.configure({ + codec: "mp4a.40.2", + numberOfChannels: 2, + sampleRate: 44100, + + // TODO bitrate + }) + + this.video.configure({ + codec: "avc1.42002A", // TODO h.264 baseline + avc: { format: "avc" }, // or annexb + width: 1280, + height: 720, + + // TODO bitrate + // TODO bitrateMode + // TODO framerate + // TODO latencyMode + }) + } + + onAudio(frame: EncodedAudioChunk, metadata: EncodedAudioChunkMetadata) { + const config = metadata.decoderConfig! + const track_id = 1; + + if (!this.container.getTrackById(track_id)) { + this.container.addTrack({ + id: track_id, + type: "mp4a", // TODO wrong + timescale: 1000, // TODO verify + + channel_count: config.numberOfChannels, + samplerate: config.sampleRate, + + description: config.description, // TODO verify + // TODO description_boxes?: Box[]; + }); + } + + const buffer = new Uint8Array(frame.byteLength); + frame.copyTo(buffer); + + // TODO cts? + const sample = this.container.addSample(track_id, buffer, { + is_sync: frame.type == "key", + duration: frame.duration!, + dts: frame.timestamp, + }); + + const stream = this.container.createSingleSampleMoof(sample); + } + + onVideo(frame: EncodedVideoChunk, metadata?: EncodedVideoChunkMetadata) { + const config = metadata!.decoderConfig! + const track_id = 2; + + if (!this.container.getTrackById(track_id)) { + this.container.addTrack({ + id: 2, + type: "avc1", + width: config.codedWidth, + height: config.codedHeight, + timescale: 1000, // TODO verify + + description: config.description, // TODO verify + // TODO description_boxes?: Box[]; + }); + } + + const buffer = new Uint8Array(frame.byteLength); + frame.copyTo(buffer); + + // TODO cts? + const sample = this.container.addSample(track_id, buffer, { + is_sync: frame.type == "key", + duration: frame.duration!, + dts: frame.timestamp, + }); + + const stream = this.container.createSingleSampleMoof(sample); + } +} \ No newline at end of file diff --git a/web/src/broadcaster/index.ts b/web/src/broadcaster/index.ts new file mode 100644 index 0000000..39d50e6 --- /dev/null +++ b/web/src/broadcaster/index.ts @@ -0,0 +1,4 @@ +export default class Broadcaster { + constructor() { + } +} \ No newline at end of file diff --git a/player/src/index.css b/web/src/index.css similarity index 100% rename from player/src/index.css rename to web/src/index.css diff --git a/player/src/index.html b/web/src/index.html similarity index 100% rename from player/src/index.html rename to web/src/index.html diff --git a/player/src/index.ts b/web/src/index.ts similarity index 100% rename from player/src/index.ts rename to web/src/index.ts diff --git a/player/src/mp4/index.ts b/web/src/mp4/index.ts similarity index 100% rename from player/src/mp4/index.ts rename to web/src/mp4/index.ts diff --git a/player/src/mp4/init.ts b/web/src/mp4/init.ts similarity index 100% rename from player/src/mp4/init.ts rename to web/src/mp4/init.ts diff --git a/player/src/mp4/mp4box.d.ts b/web/src/mp4/mp4box.d.ts similarity index 100% rename from player/src/mp4/mp4box.d.ts rename to web/src/mp4/mp4box.d.ts diff --git a/player/src/player/decoder.ts b/web/src/player/decoder.ts similarity index 100% rename from player/src/player/decoder.ts rename to web/src/player/decoder.ts diff --git a/player/src/player/index.ts b/web/src/player/index.ts similarity index 100% rename from player/src/player/index.ts rename to web/src/player/index.ts diff --git a/player/src/player/message.ts b/web/src/player/message.ts similarity index 100% rename from player/src/player/message.ts rename to web/src/player/message.ts diff --git a/player/src/player/renderer.ts b/web/src/player/renderer.ts similarity index 100% rename from player/src/player/renderer.ts rename to web/src/player/renderer.ts diff --git a/player/src/player/ring.ts b/web/src/player/ring.ts similarity index 100% rename from player/src/player/ring.ts rename to web/src/player/ring.ts diff --git a/player/src/player/worker.ts b/web/src/player/worker.ts similarity index 100% rename from player/src/player/worker.ts rename to web/src/player/worker.ts diff --git a/player/src/player/worklet.ts b/web/src/player/worklet.ts similarity index 100% rename from player/src/player/worklet.ts rename to web/src/player/worklet.ts diff --git a/player/src/stream/index.ts b/web/src/stream/index.ts similarity index 100% rename from player/src/stream/index.ts rename to web/src/stream/index.ts diff --git a/player/src/stream/reader.ts b/web/src/stream/reader.ts similarity index 100% rename from player/src/stream/reader.ts rename to web/src/stream/reader.ts diff --git a/player/src/stream/writer.ts b/web/src/stream/writer.ts similarity index 100% rename from player/src/stream/writer.ts rename to web/src/stream/writer.ts diff --git a/player/src/transport/index.ts b/web/src/transport/index.ts similarity index 100% rename from player/src/transport/index.ts rename to web/src/transport/index.ts diff --git a/player/src/transport/interface.ts b/web/src/transport/interface.ts similarity index 100% rename from player/src/transport/interface.ts rename to web/src/transport/interface.ts diff --git a/player/src/transport/message.ts b/web/src/transport/message.ts similarity index 100% rename from player/src/transport/message.ts rename to web/src/transport/message.ts diff --git a/player/src/transport/webtransport.d.ts b/web/src/transport/webtransport.d.ts similarity index 100% rename from player/src/transport/webtransport.d.ts rename to web/src/transport/webtransport.d.ts diff --git a/player/src/util/deferred.ts b/web/src/util/deferred.ts similarity index 100% rename from player/src/util/deferred.ts rename to web/src/util/deferred.ts diff --git a/player/src/util/index.ts b/web/src/util/index.ts similarity index 100% rename from player/src/util/index.ts rename to web/src/util/index.ts diff --git a/player/tsconfig.json b/web/tsconfig.json similarity index 100% rename from player/tsconfig.json rename to web/tsconfig.json diff --git a/player/yarn.lock b/web/yarn.lock similarity index 100% rename from player/yarn.lock rename to web/yarn.lock