From 25ae4fa72e0f7de696ae67992ed5394e5ff07163 Mon Sep 17 00:00:00 2001 From: DavidVentura Date: Thu, 1 Feb 2024 17:56:27 +0100 Subject: [PATCH] attempt to re-stitch together JPEGs at the recovery markers upon dataloss --- handlers.ts | 45 +++++++++++++++++++++++++++++++++++++++++---- http_server.ts | 5 +++-- options.ts | 1 + session.ts | 2 ++ 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/handlers.ts b/handlers.ts index 197a2f7..37025cd 100644 --- a/handlers.ts +++ b/handlers.ts @@ -152,6 +152,7 @@ const deal_with_data = (session: Session, dv: DataView) => { session.eventEmitter.emit("frame"); } + session.frame_was_fixed = false; session.frame_is_bad = false; session.curImage = [Buffer.from(data.buffer)]; session.rcvSeqId = pkt_id; @@ -164,12 +165,34 @@ const deal_with_data = (session: Session, dv: DataView) => { let b = Buffer.from(data.buffer); if (pkt_id > session.rcvSeqId + 1) { - // missed some packets -- filling with zeroes still produces a broken - // image session.frame_is_bad = true; - console.log(`Missed some packets on ${session.devName} -- skipping a frame`); - return; + // this should always be enabled but currently it seems to cause more visual distortion + // than just missing some frames + if (!session.options.attempt_to_fix_packet_loss) { + return; + } + + if (session.curImage.length == 1) return; // header does not have markers + + let lastFrameSlice = session.curImage[session.curImage.length - 1]; + const lastResetMarker = findAllResetMarkers(lastFrameSlice).pop(); + if (lastResetMarker == undefined) { + // not storing rcvSeqId as this frame did not put us back in track + return; + } + + const firstResetMarker = findAllResetMarkers(b).shift(); + if (firstResetMarker == undefined) { + // not storing rcvSeqId as this frame did not put us back in track + return; + } + + session.curImage[session.curImage.length - 1] = Buffer.from(lastFrameSlice.subarray(0, lastResetMarker)); + b = Buffer.from(b.subarray(firstResetMarker)); + session.frame_is_bad = false; + session.frame_was_fixed = true; } + session.rcvSeqId = pkt_id; if (session.curImage != null) { session.curImage.push(b); @@ -178,6 +201,20 @@ const deal_with_data = (session: Session, dv: DataView) => { } }; +const findAllResetMarkers = (b: Buffer): number[] => { + // a reset marker is a byte 0xff followed by a byte 0xd0-0xd7 + let ret = []; + for (let i = 0; i < b.length - 1; i++) { + if (b[i] == 0xff) { + const nb = b[i + 1]; + if (nb >= 0xd0 && nb <= 0xd7) { + ret.push(i); + } + } + } + return ret; +}; + const makeDrwAck = (dv: DataView): DataView => { const pkt_id = dv.add(6).readU16(); const m_stream = dv.add(5).readU8(); // data = 1, control = 0 diff --git a/http_server.ts b/http_server.ts index b2980e2..e484656 100644 --- a/http_server.ts +++ b/http_server.ts @@ -10,8 +10,9 @@ import { ServerResponse } from "http"; const opts = { debug: false, ansi: false, - discovery_ip: "192.168.40.255", //, "192.168.1.255" - // discovery_ip: "192.168.40.101", + // discovery_ip: "192.168.40.255", //, "192.168.1.255" + discovery_ip: "192.168.40.101", + attempt_to_fix_packet_loss: false, }; let BOUNDARY = "a very good boundary line"; diff --git a/options.ts b/options.ts index 2f281d6..0340529 100644 --- a/options.ts +++ b/options.ts @@ -2,4 +2,5 @@ export type opt = { debug: boolean; ansi: boolean; discovery_ip: string; + attempt_to_fix_packet_loss: boolean; }; diff --git a/session.ts b/session.ts index 34d301f..b172eaf 100644 --- a/session.ts +++ b/session.ts @@ -20,6 +20,7 @@ export type Session = { curImage: Buffer[]; rcvSeqId: number; frame_is_bad: boolean; + frame_was_fixed: boolean; options: opt; }; @@ -101,6 +102,7 @@ export const makeSession = ( curImage: [], rcvSeqId: 0, frame_is_bad: false, + frame_was_fixed: false, options: options, };