Rename player folder and initial broadcaster code.
This commit is contained in:
parent
9f0c24b552
commit
29921ba46d
|
@ -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
|
||||
```
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
export default class Broadcaster {
|
||||
constructor() {
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue