Skip to content

Commit

Permalink
Added ability to (optionally) select a DJI srt file to overlay mbps, …
Browse files Browse the repository at this point in the history
…delay, channel, etc (#409)
  • Loading branch information
FinalFrag authored Nov 15, 2023
1 parent 2e3a493 commit 38adcb8
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/features/osd-overlay/FileDrop.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export function useFileDropState() {
fontFileSd1: null,
fontFileSd2: null,
osdFile: null,
srtFile: null,
videoFile: null,
});

Expand Down Expand Up @@ -55,6 +56,10 @@ export default function FileDrop(props) {
changedFiles.osdFile = file;
break;

case "srt":
changedFiles.srtFile = file;
break;

case "bin":
if (name.includes("hd")) {
if (name.includes("_2")) {
Expand Down Expand Up @@ -146,6 +151,12 @@ export default function FileDrop(props) {
label={t("fileDropOsd")}
/>

<FileDropEntry
file={files.srtFile}
icon={OsdIcon}
label={t("fileDropSrt")}
/>

<FileDropEntry
file={files.fontFileSd1}
icon={FontIcon}
Expand Down
3 changes: 3 additions & 0 deletions src/features/osd-overlay/OsdOverlay.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default function OsdOverlay() {
const [files, setFiles] = useFileDropState();
const videoFile = files.videoFile;
const osdFile = files.osdFile;
const srtFile = files.srtFile;
const fontFiles = React.useMemo(() => ({
sd1: files.fontFileSd1,
sd2: files.fontFileSd2,
Expand Down Expand Up @@ -169,13 +170,15 @@ export default function OsdOverlay() {
chromaKeyColor: config.chromaKeyColor,
fontFiles: fontFiles,
osdFile: osdFile,
srtFile: srtFile,
outHandle: handle,
videoFile: videoFile,
});
}, [
config,
fontFiles,
osdFile,
srtFile,
setInProgress,
setStartedOnce,
videoFile,
Expand Down
1 change: 1 addition & 0 deletions src/osd-overlay/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export default class VideoWorkerManager {
chromaKeyColor: string
fontFiles: FontPackFiles,
osdFile: File,
srtFile: File,
outHandle: FileSystemFileHandle
videoFile: File,
}) {
Expand Down
1 change: 1 addition & 0 deletions src/osd-overlay/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ namespace VideoWorkerShared {

fontFiles: FontPackFiles,
osdFile: File;
srtFile: File;
outHandle: FileSystemFileHandle;
videoFile: File;
}
Expand Down
75 changes: 75 additions & 0 deletions src/osd-overlay/srt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
interface SrtFrame {
start: number;
end: number;
signal: string;
ch: string;
flightTime: string;
uavBat: string;
glsBat: string;
uavBatCells: string;
glsBatCells: string;
delay: string;
bitrate:string;
rcSignal:string;
}

export class SrtReader {
readonly frames: SrtFrame[] = [];

constructor(data: String) {
const blocks = data.split('\n\n').slice(0, -1);

for (const block of blocks) {
const [ , timestamps, text ] = block.split('\n');
const [ startHours, startMinutes, startSeconds, startMilliseconds ] = timestamps
.substring(0, 12)
.split(/\D/)
.map(it => parseInt(it));
const [ endHours, endMinutes, endSeconds, endMilliseconds ] = timestamps
.substring(17)
.split(/\D/)
.map(it => parseInt(it));

const start = startHours * 1000 * 60 * 60 + startMinutes * 1000 * 60 + startSeconds * 1000 + startMilliseconds;
const end = endHours * 1000 * 60 * 60 + endMinutes * 1000 * 60 + endSeconds * 1000 + endMilliseconds;

const [ signalRaw, chRaw, flightTimeRaw, uavBatRaw, glsBatRaw, uavBatCellsRaw, glsBatCellsRaw, delayRaw, bitrateRaw, rcSignalRaw ] = text.split(' ');
const signal = signalRaw.split(':')[1];
const ch = chRaw.split(':')[1];
const flightTime = parseInt(flightTimeRaw.split(':')[1]);
const uavBat = uavBatRaw.split(':')[1];
const glsBat = glsBatRaw.split(':')[1];
const uavBatCells = uavBatCellsRaw.split(':')[1];
const glsBatCells = glsBatCellsRaw.split(':')[1];
const delay = delayRaw.split(':')[1];
const bitrate = bitrateRaw.split(':')[1];
const rcSignal = rcSignalRaw.split(':')[1];

const formatFlightTime = (totalSeconds: number) => {
const minutes = String(Math.floor(totalSeconds / 60)).padStart(2, "0");
const seconds = String(totalSeconds % 60).padStart(2, "0");
return `${minutes}' ${seconds}"`;
}

this.frames.push({
start,
end,
signal,
ch: "CH" + ch,
flightTime: formatFlightTime(flightTime),
uavBat,
glsBat,
uavBatCells,
glsBatCells,
delay,
bitrate,
rcSignal,
});
}
}

static async fromFile(file: File): Promise<SrtReader> {
const data = await file.text();
return new SrtReader(data);
}
}
42 changes: 42 additions & 0 deletions src/osd-overlay/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
TILES_PER_PAGE,
} from "./fonts";
import { OsdReader } from "./osd";
import { SrtReader } from "./srt";

const MAX_DISPLAY_X = 60;
const MAX_DISPLAY_Y = 22;
Expand All @@ -21,6 +22,7 @@ export class VideoWorker {

fontPack?: FontPack;
osdReader?: OsdReader;
srtReader?: SrtReader;

lastOsdIndex: number = 0;

Expand Down Expand Up @@ -50,13 +52,19 @@ export class VideoWorker {

fontFiles: FontPackFiles,
osdFile: File,
srtFile: File,
outHandle: FileSystemFileHandle,
videoFile: File,
}) {
this.chromaKey = options.chromaKey;
this.chromaKeyColor = options.chromaKeyColor;

this.osdReader = await OsdReader.fromFile(options.osdFile);

if (options.srtFile) {
this.srtReader = await SrtReader.fromFile(options.srtFile);
}

this.fontPack = await Font.fromFiles(options.fontFiles);

const { width, height } = await this.processor.open(options.videoFile, options.outHandle);
Expand Down Expand Up @@ -142,6 +150,39 @@ export class VideoWorker {
}
}

if (this.srtReader) {
// If a srt file is supplied, render the DJI goggle osd elements
const drawText = (osdCtx: OffscreenCanvasRenderingContext2D, text: string, x: number, y: number, bigFont= false) => {
osdCtx.font = `${bigFont ? '30px' : '26px'} calibri`;
osdCtx.strokeStyle = '#333333';
osdCtx.lineWidth = 4;
osdCtx.strokeText(text, x, y);
osdCtx.fillStyle = 'white';
osdCtx.fillText(text, x, y);
}

const currentFrameInMilliseconds = frameIndex * 1000 / 60;
let srtFrame = this.srtReader.frames.find(it => it.start <= currentFrameInMilliseconds && it.end > currentFrameInMilliseconds);

if (currentFrameInMilliseconds < this.srtReader.frames[0].start) {
// DJI subtitles don't start at 0 milliseconds
// Take the first one as a filler at the start
srtFrame = this.srtReader.frames[0];
} else if (currentFrameInMilliseconds > this.srtReader.frames[this.srtReader.frames.length - 1].end) {
// Show the last subtitle in case there is more video than subtitles
srtFrame = this.srtReader.frames[this.srtReader.frames.length - 1];
}

if (srtFrame) {
drawText(osdCtx, srtFrame.ch, 120, 785, true);
drawText(osdCtx, srtFrame.delay, 1190, 710);
drawText(osdCtx, srtFrame.bitrate, 1320, 710);
drawText(osdCtx, srtFrame.uavBat, 1060, 785, true);
drawText(osdCtx, srtFrame.flightTime, 1200, 785, true);
drawText(osdCtx, srtFrame.glsBat, 1350, 785, true);
}
}

const osdFrame = this.osdReader!.frames[this.lastOsdIndex];
for (let y = 0; y < MAX_DISPLAY_Y; y++) {
for (let x = 0; x < MAX_DISPLAY_X; x++) {
Expand Down Expand Up @@ -228,6 +269,7 @@ export class VideoWorker {
chromaKeyColor: message.chromaKeyColor,
fontFiles: message.fontFiles,
osdFile: message.osdFile,
srtFile: message.srtFile,
outHandle: message.outHandle,
videoFile: message.videoFile,
});
Expand Down
1 change: 1 addition & 0 deletions src/translations/en/osdOverlay.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"fileDropFontSd2": "Font 2 (SD)",
"fileDropHelp": "You can drop any of your files here, or click to select them individually.",
"fileDropOsd": "OSD",
"fileDropSrt": "SRT (optional)",
"fileDropVideo": "Video",
"noteConfigLink": "Configure this in the Package Manager.",
"noteHeader": "OSD recording is an opt-in feature on the goggle side.",
Expand Down

0 comments on commit 38adcb8

Please sign in to comment.