From bc4ff49bf0fb429c38ccafff15a9a78b08e6a8db Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Tue, 18 Jan 2022 13:52:40 +0300 Subject: [PATCH] Fixed: Could not receive frame N. TypeError: Cannot read properties of undefined (#4187) * Fixed issue with async frames fetching * Updated versions and changelog --- CHANGELOG.md | 2 +- cvat-core/package-lock.json | 4 +- cvat-core/package.json | 2 +- cvat-core/src/frames.js | 59 ++++++++++++------- .../annotation-page/top-bar/top-bar.tsx | 11 +++- 5 files changed, 49 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c90b3611..84c657e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,10 +56,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added intelligent function when paste labels to another task () - Uncaught TypeError: this.el.node.getScreenCTM() is null in Firefox () - Bug: canvas is busy when start playing, start resizing a shape and do not release the mouse cursor () +- Bug: could not receive frame N. TypeError: Cannot read properties of undefined (reding "filename") () - Fixed tus upload error over https () - Auth token key is not returned when registering without email verification () - ### 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 04aef69d..11a96727 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 2f9c6d62..c6985e15 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-core/src/frames.js b/cvat-core/src/frames.js index f62af19f..f9c5b2e4 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 b09c82fd..a01578f0 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) {