Skip to content

Commit

Permalink
#3 Add an initial implementation of WebCodecs
Browse files Browse the repository at this point in the history
  • Loading branch information
atiernan committed May 15, 2021
1 parent ca4c43c commit 3351e89
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 5 deletions.
8 changes: 5 additions & 3 deletions src/Goggles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@ export default class Goggles {
await this.device.claimInterface(3);
}

async close() {
this.device.close();
}

async requestVideo() {
const writeResult = await this.sendRawData(new Uint8Array([0x52, 0x4d, 0x56, 0x54]));
return writeResult.status === 'ok';
this.sendRawData(new Uint8Array([0x52, 0x4d, 0x56, 0x54]));
}

async startPolling() {
Expand All @@ -43,7 +46,6 @@ export default class Goggles {
if (this.device.opened) {
const result = await this.device.transferIn(ENDPOINT_IN, BUFFER_LENGTH);
if (this.onDataCallback !== null && result.data) {
console.log(result);
this.onDataCallback(result.data);
}
}
Expand Down
1 change: 1 addition & 0 deletions src/ui/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<title>DigiView - Web</title>
<meta name="description" content="View your digital FPV in your browser!">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="origin-trial" content="Ai6skJj2lyH5e2FNv8q3AJrvApFLk0nxv8as7CXZcfNYTbpvSkq+NRXHPuVpd9lJ2sKHYIVD6OXTw9gy7HaXsQ8AAABSeyJvcmlnaW4iOiJodHRwczovL2xpdmUuZnB2b3V0LmNvbTo0NDMiLCJmZWF0dXJlIjoiV2ViQ29kZWNzIiwiZXhwaXJ5IjoxNjI2MjIwNzk5fQ==">
</head>

<body>
Expand Down
2 changes: 1 addition & 1 deletion src/ui/views/ViewUSB/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

<script>
import GogglesDevice, {VID, PID} from '~/Goggles';
import Goggles from '~/ui/views/ViewUSB/Goggle.vue';
import Goggles from '~/ui/views/ViewUSB/VideoPlayer/Index.vue';
export default {
components: {Goggles},
Expand Down
29 changes: 29 additions & 0 deletions src/ui/views/ViewUSB/VideoPlayer/Index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<template>
<div>
<md-switch v-model="userEnabledWebCodecs">Enable WebCodecs<small>(experimental)</small></md-switch>
<component :is="isWebCodecAvailable ? 'web-codec' : 'jmuxer'" :device="device" />
</div>
</template>

<script>
import Jmuxer from './Jmuxer.vue';
import WebCodec from './WebCodec.vue';
export default {
props: ['device'],
data() {
return {
userEnabledWebCodecs: false,
}
},
components: {Jmuxer, WebCodec},
computed: {
webCodecsEnabled() {
return this.isWebCodecAvailable && this.userEnabledWebCodecs;
},
isWebCodecAvailable() {
return 'VideoEncoder' in window;
}
}
}
</script>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div>
<video ref="player" controls autoplay :class="{hidden: !isPlaying}" :id="playerId"></video>
<div v-if="!isPlayer">
<div v-if="!isPlaying">
<p class="text-center md-title">Waiting to recieve video...</p>
</div>
</div>
Expand Down
92 changes: 92 additions & 0 deletions src/ui/views/ViewUSB/VideoPlayer/WebCodec.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<template>
<div>
<canvas ref="player" style="width:50%;border: 1px solid #bababa" width="720" height="576"></canvas>
</div>
</template>

<script>
function dec2hex(array) {
return array.map((val) => val.toString(16).padStart(2, '0')).join(' ').toUpperCase()
}
const MICROSECONDS_PER_FRAME = 16700;
export default {
props: ['device'],
data() {
return {
isPlaying: false,
}
},
computed: { },
methods: {
stopVideo() {
this.device.stopPolling();
},
startVideo() {
this.device.startPolling();
}
},
mounted() {
const canvasContext = this.$refs.player.getContext('2d');
const handleFrame = (frame) => {
canvasContext.drawImage(frame, 0, 0);
frame.close();
}
const init = {
output: handleFrame,
error: (e) => {
console.log(e);
this.device.close();
},
};
let decoder = new VideoDecoder(init);
decoder.configure({ codec: 'avc1.64002A' });
let currentTimestamp = 0;
this.device.onData = (data) => {
if (data.buffer.byteLength === 0) {
return;
}
const chunkData = new Uint8Array(data.buffer);
let NALUnitsFound = 0;
chunkData.forEach((val, index, self) => {
if (self.length > index + 2 && self[index] === 0 && self[index + 1] === 0 && self[index + 2] === 0) {
NALUnitsFound++;
}
});
if (NALUnitsFound === 4 && currentTimestamp !== undefined && currentTimestamp !== 0) {
return;
}
if (NALUnitsFound % 2 === 1) {
console.log(`Uneven number of NAL units found: ${NALUnitsFound}`);
return;
}
currentTimestamp += MICROSECONDS_PER_FRAME;
const chunk = new EncodedVideoChunk({
type: "delta",
timestamp: currentTimestamp,
data: chunkData,
})
decoder.decode(chunk);
};
this.device.startPolling();
},
}
</script>

<style scoped>
.hidden {
display: none;
}
.text-center {
text-align: center;
}
</style>

0 comments on commit 3351e89

Please sign in to comment.