From 60a4c19eed2b4f4193f1a6637af6e62d1139172e Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Fri, 14 Jan 2022 15:46:21 +0300 Subject: [PATCH 1/2] Fixed issue with async frames fetching --- cvat-core/src/frames.js | 59 ++++++++++++------- .../annotation-page/top-bar/top-bar.tsx | 11 +++- 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/cvat-core/src/frames.js b/cvat-core/src/frames.js index f62af19f4ea0..f9c5b2e4f6d1 100644 --- a/cvat-core/src/frames.js +++ b/cvat-core/src/frames.js @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Intel Corporation +// Copyright (C) 2021-2022 Intel Corporation // // SPDX-License-Identifier: MIT @@ -477,31 +477,47 @@ let bufferedFrames = new Set(); + // if we send one request to get frame 1 with filling the buffer + // then quicky send one more request to get frame 1 + // frame 1 will be already decoded and written to buffer + // the second request gets frame 1 from the buffer, removes it from there and returns + // after the first request finishes decoding it tries to get frame 1, but failed + // because frame 1 was already removed from the buffer by the second request + // to prevent this behavior we do not write decoded frames to buffer till the end of decoding all chunks + const buffersToBeCommited = []; + const commitBuffers = () => { + for (const buffer of buffersToBeCommited) { + this._buffer = { + ...this._buffer, + ...buffer, + }; + } + }; + // Need to decode chunks in sequence // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve, reject) => { - for (const chunkIdx in this._requestedChunks) { - if (Object.prototype.hasOwnProperty.call(this._requestedChunks, chunkIdx)) { - try { - const chunkFrames = await this.requestOneChunkFrames(chunkIdx); - if (chunkIdx in this._requestedChunks) { - bufferedFrames = new Set([...bufferedFrames, ...chunkFrames]); - this._buffer = { - ...this._buffer, - ...this._requestedChunks[chunkIdx].buffer, - }; - delete this._requestedChunks[chunkIdx]; - if (Object.keys(this._requestedChunks).length === 0) { - resolve(bufferedFrames); - } - } else { - reject(chunkIdx); - break; + for (const chunkIdx of Object.keys(this._requestedChunks)) { + try { + const chunkFrames = await this.requestOneChunkFrames(chunkIdx); + if (chunkIdx in this._requestedChunks) { + bufferedFrames = new Set([...bufferedFrames, ...chunkFrames]); + + buffersToBeCommited.push(this._requestedChunks[chunkIdx].buffer); + delete this._requestedChunks[chunkIdx]; + if (Object.keys(this._requestedChunks).length === 0) { + commitBuffers(); + resolve(bufferedFrames); } - } catch (error) { - reject(error); + } else { + commitBuffers(); + reject(chunkIdx); break; } + } catch (error) { + commitBuffers(); + reject(error); + break; } } }); @@ -524,7 +540,7 @@ async require(frameNumber, taskID, jobID, fillBuffer, frameStep) { for (const frame in this._buffer) { - if (frame < frameNumber || frame >= frameNumber + this._size * frameStep) { + if (+frame < frameNumber || +frame >= frameNumber + this._size * frameStep) { delete this._buffer[frame]; } } @@ -563,7 +579,6 @@ } else if (fillBuffer) { this.clear(); await this.makeFillRequest(frameNumber, frameStep, fillBuffer ? null : 1); - frame = this._buffer[frameNumber]; } else { this.clear(); diff --git a/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx b/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx index b09c82fda670..a01578f0c906 100644 --- a/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx +++ b/cvat-ui/src/containers/annotation-page/top-bar/top-bar.tsx @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Intel Corporation +// Copyright (C) 2021-2022 Intel Corporation // // SPDX-License-Identifier: MIT @@ -49,6 +49,7 @@ interface StateToProps { frameStep: number; frameSpeed: FrameSpeed; frameDelay: number; + frameFetching: boolean; playing: boolean; saving: boolean; canvasIsReady: boolean; @@ -89,7 +90,9 @@ function mapStateToProps(state: CombinedState): StateToProps { annotation: { player: { playing, - frame: { filename: frameFilename, number: frameNumber, delay: frameDelay }, + frame: { + filename: frameFilename, number: frameNumber, delay: frameDelay, fetching: frameFetching, + }, }, annotations: { saving: { uploading: saving, statuses: savingStatuses, forceExit }, @@ -112,6 +115,7 @@ function mapStateToProps(state: CombinedState): StateToProps { frameStep, frameSpeed, frameDelay, + frameFetching, playing, canvasIsReady, saving, @@ -484,13 +488,14 @@ class AnnotationTopBarContainer extends React.PureComponent { frameSpeed, frameNumber, frameDelay, + frameFetching, playing, canvasIsReady, onSwitchPlay, onChangeFrame, } = this.props; - if (playing && canvasIsReady) { + if (playing && canvasIsReady && !frameFetching) { if (frameNumber < jobInstance.stopFrame) { let framesSkipped = 0; if (frameSpeed === FrameSpeed.Fast && frameNumber + 1 < jobInstance.stopFrame) { From 7485ab08d3c87949edc2da7fc6d537d765d4f7a5 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Mon, 17 Jan 2022 10:35:16 +0300 Subject: [PATCH 2/2] Updated versions and changelog --- CHANGELOG.md | 1 + cvat-core/package-lock.json | 4 ++-- cvat-core/package.json | 2 +- cvat-ui/package-lock.json | 4 ++-- cvat-ui/package.json | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b4fb4ad17ac..5724285782f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Email in org invitations is case sensitive () - Bug: canvas is busy when start playing, start resizing a shape and do not release the mouse cursor () - Fixed tus upload error over https () +- Bug: could not receive frame N. TypeError: Cannot read properties of undefined (reding "filename") () ### Security - Updated ELK to 6.8.22 which uses log4j 2.17.0 () diff --git a/cvat-core/package-lock.json b/cvat-core/package-lock.json index 04aef69db26b..11a967273d19 100644 --- a/cvat-core/package-lock.json +++ b/cvat-core/package-lock.json @@ -1,12 +1,12 @@ { "name": "cvat-core", - "version": "4.1.0", + "version": "4.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cvat-core", - "version": "4.1.0", + "version": "4.1.1", "license": "MIT", "dependencies": { "axios": "^0.21.4", diff --git a/cvat-core/package.json b/cvat-core/package.json index 2f9c6d62ca27..c6985e152049 100644 --- a/cvat-core/package.json +++ b/cvat-core/package.json @@ -1,6 +1,6 @@ { "name": "cvat-core", - "version": "4.1.0", + "version": "4.1.1", "description": "Part of Computer Vision Tool which presents an interface for client-side integration", "main": "babel.config.js", "scripts": { diff --git a/cvat-ui/package-lock.json b/cvat-ui/package-lock.json index 141bc22c2e71..e37867502cf1 100644 --- a/cvat-ui/package-lock.json +++ b/cvat-ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "cvat-ui", - "version": "1.33.1", + "version": "1.33.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cvat-ui", - "version": "1.33.1", + "version": "1.33.2", "license": "MIT", "dependencies": { "@ant-design/icons": "^4.6.3", diff --git a/cvat-ui/package.json b/cvat-ui/package.json index 0cf3930af599..02e2f6b9caa5 100644 --- a/cvat-ui/package.json +++ b/cvat-ui/package.json @@ -1,6 +1,6 @@ { "name": "cvat-ui", - "version": "1.33.1", + "version": "1.33.2", "description": "CVAT single-page application", "main": "src/index.tsx", "scripts": {