Skip to content

Commit

Permalink
Merge pull request #2 from ygnn123/yg/mbranch
Browse files Browse the repository at this point in the history
Yg/mbranch
  • Loading branch information
ygnn123 authored Nov 5, 2019
2 parents 69aa8a5 + 5b8cc0b commit a5791a4
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 20,062 deletions.
15 changes: 9 additions & 6 deletions cvat-core/src/frames.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
const { provider } = frameDataCache[this.tid];
const { chunkSize } = frameDataCache[this.tid];

const frame = provider.frame(this.number);
const frame = await provider.frame(this.number);
if (frame === null || frame === 'loading') {
onServerRequest();
const start = parseInt(this.number / chunkSize, 10) * chunkSize;
Expand All @@ -108,11 +108,14 @@
let chunk = null;

if (frame === null) {
chunk = await serverProxy.frames.getData(this.tid, chunkNumber);
}

provider.requestDecodeBlock(chunk, start, stop, onDecode.bind(this, provider), rejectRequest.bind(this));

if (!provider.is_chunk_cached(start, stop)){
serverProxy.frames.getData(this.tid, chunkNumber).then(chunk =>{
provider.requestDecodeBlock(chunk, start, stop, onDecode.bind(this, provider), rejectRequest.bind(this));
});
} else {
provider.requestDecodeBlock(null, start, stop, onDecode.bind(this, provider), rejectRequest.bind(this));
}
}
} else {
if (this.number % chunkSize > 1){
if (!provider.isNextChunkExists(this.number)){
Expand Down
122 changes: 91 additions & 31 deletions cvat-data/src/js/cvat-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,27 @@ const BlockType = Object.freeze({
ARCHIVE: 'archive',
});


class Mutex {
constructor() {
this._lock = Promise.resolve();
}
_acquire() {
var release;
const lock = this._lock = new Promise(resolve => {
release = resolve;
});
return release;
}
acquireQueued() {
const q = this._lock.then(() => release);
const release = this._acquire();
return q;
}
};



class FrameProvider {
constructor(memory, blockType, blockSize) {
this._frames = {};
Expand All @@ -28,26 +49,36 @@ class FrameProvider {
this._decodingBlocks = {};
this._decodeThreadCount = 0;
this._timerId = setTimeout(this._worker.bind(this), 100);
this._mutex = new Mutex();
};

_worker()
async _worker()
{
if (this._requestedBlockDecode != null &&
this._decodeThreadCount < 3)
this._decodeThreadCount < 2)
{
this.startDecode();
await this.startDecode();
}
this._timerId = setTimeout(this._worker.bind(this), 100);
}

is_chunk_cached(start, end)
{
return (`${start}:${end}` in this._blocks_ranges);
}


/* This method removes extra data from a cache when memory overflow */
_cleanup() {
async _cleanup() {
if (this._blocks_ranges.length > this._memory) {
const shifted = this._blocks_ranges.shift(); // get the oldest block
const [start, end] = shifted.split(':').map((el) => +el);
delete this._blocks[start / this._blockSize];
for (let i = start; i <= end; i++){
delete this._frames[i];
}
}

// delete frames whose are not in areas of current frame
for (let i = 0; i < this._blocks_ranges.length; i++)
{
Expand All @@ -71,19 +102,30 @@ class FrameProvider {
}
}

requestDecodeBlock(block, start, end, resolveCallback, rejectCallback){
if (this._requestedBlockDecode != null)
{
async requestDecodeBlock(block, start, end, resolveCallback, rejectCallback){
const release = await this._mutex.acquireQueued();
if (this._requestedBlockDecode != null) {
this._requestedBlockDecode.rejectCallback();
}

this._requestedBlockDecode = {
block : block,
start : start,
end : end,
resolveCallback : resolveCallback,
rejectCallback : rejectCallback,
if (! (`${start}:${end}` in this._decodingBlocks)) {
if (block === null)
{
block = this._blocks[Math.floor((start+1) / chunkSize)];
}
this._requestedBlockDecode = {
block : block,
start : start,
end : end,
resolveCallback : resolveCallback,
rejectCallback : rejectCallback,
}
}
release();
}

isRequestExist()
{
return this._requestedBlockDecode != null;
}

setRenderSize(width, height){
Expand All @@ -92,7 +134,7 @@ class FrameProvider {
}

/* Method returns frame from collection. Else method returns 0 */
frame(frameNumber) {
async frame(frameNumber) {
if (frameNumber in this._frames) {
this._currFrame = frameNumber;
return this._frames[frameNumber];
Expand Down Expand Up @@ -123,23 +165,24 @@ class FrameProvider {
this._blocks[chunkNumber] = "loading";
}

startDecode() {
async startDecode() {
if (this._blockType === BlockType.TSVIDEO){



const release = await this._mutex.acquireQueued();
let start = this._requestedBlockDecode.start;
let end = this._requestedBlockDecode.end;
let block = this._requestedBlockDecode.block;

console.log("start decoding " + start + " to " + end + " frames");
this._blocks_ranges.push(`${start}:${end}`);
this._decodingBlocks[`${start}:${end}`] = this._requestedBlockDecode;
this._requestedBlockDecode = null;
this._requestedBlockDecode = null;

for (let i = start; i < end; i++){
this._frames[i] = 'loading';
}

this._blocks[Math.floor((start+1)/ this._blockSize)] = block;
this._blocks_ranges.push(`${start}:${end}`);

this._cleanup();

const worker = new Worker('/static/engine/js/decode_video.js');
Expand All @@ -148,7 +191,8 @@ class FrameProvider {
console.log(['ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message].join(''));
worker.terminate();
this._decodeThreadCount--;
console.log(this._decodeThreadCount);
// console.log(this._decodeThreadCount);
this._decodingBlocks[`${start}:${end}`].rejectCallback();
delete this._decodingBlocks[`${start}:${end}`];
}).bind(this);

Expand All @@ -158,24 +202,36 @@ class FrameProvider {
width : this._width,
height : this._height});
this._decodeThreadCount++;
console.log(this._decodeThreadCount);
// console.log(this._decodeThreadCount);

worker.onmessage = (function (event){
// console.log("Decoded " + event.data.index + "frame");
this._frames[event.data.index] = event.data.data;
this._decodingBlocks[`${start}:${end}`].resolveCallback(event.data.index);
this._decodingBlocks[`${event.data.start}:${event.data.end}`].resolveCallback(event.data.index);
if (event.data.isEnd) {
console.log("stop decoding " + start + " to " + end + " frames");
this._decodeThreadCount--;
console.log(this._decodeThreadCount);
delete this._decodingBlocks[`${start}:${end}`];
// console.log("stop decoding " + event.data.start + " to " + event.data.end + " frames");
// console.log(this._decodeThreadCount);
delete this._decodingBlocks[`${event.data.start}:${event.data.end}`];
}
}).bind(this);
release();

} else {

const release = await this._mutex.acquireQueued();
let start = this._requestedBlockDecode.start;
let end = this._requestedBlockDecode.end;
let block = this._requestedBlockDecode.block;
this._blocks_ranges.push(`${start}:${end}`);
this._decodingBlocks[`${start}:${end}`] = this._requestedBlockDecode;
this._requestedBlockDecode = null;

const worker = new Worker('/static/engine/js/unzip_imgs.js');

worker.onerror = (function (e) {
console.log(['ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message].join(''));
this._decodingBlocks[`${start}:${end}`].rejectCallback();
this._decodeThreadCount--;
});

Expand All @@ -185,11 +241,15 @@ class FrameProvider {
this._decodeThreadCount++;

worker.onmessage = (function (event){
this._frames[event.data.index] = event.data.data;
if (event.data.isEnd)
this._frames[event.data.index] = event.data.data;
this._decodingBlocks[`${start}:${end}`].resolveCallback(event.data.index);
if (event.data.isEnd){
delete this._decodingBlocks[`${start}:${end}`];
this._decodeThreadCount--;
callback(event.data.index);
}
}).bind(this);

release();
}
}

Expand Down
5 changes: 3 additions & 2 deletions cvat-data/src/js/decode_video.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ self.onmessage = function (e) {
const start = e.data.start;
const end = e.data.end;

videoDecoder = new JSMpeg.Decoder.MPEG1Video({decodeFirstFrame : false});
videoDecoder = new JSMpeg.Decoder.MPEG1Video({decodeFirstFrame : false, videoBufferSize : block.length});
demuxer = new JSMpeg.Demuxer.TS({});
demuxer.connect(JSMpeg.Demuxer.TS.STREAM.VIDEO_1, videoDecoder);
demuxer.write(block);
Expand All @@ -88,6 +88,7 @@ self.onmessage = function (e) {
var t_decode = performance.now();
// console.log("decode " + i + " frame took " + (t_decode - t0) + " milliseconds.");
if (!Array.isArray(result)) {
// console.log("frame: " + i + " block: " + block);
const message = 'Result must be an array.'
+ `Got ${result}. Possible reasons: `
+ 'bad video file, unpached jsmpeg';
Expand All @@ -96,7 +97,7 @@ self.onmessage = function (e) {
}


postMessage({fileName : null, index : i, data : YCbCrToRGBA(...result, e.data.width, e.data.height), isEnd : i === end});
postMessage({start : start, end : end, fileName : null, index : i, data : YCbCrToRGBA(...result, e.data.width, e.data.height), isEnd : i === end});
}

self.close();
Expand Down
3 changes: 1 addition & 2 deletions cvat-data/src/js/unzip_imgs.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const JSZip = require('jszip');

self.onmessage = function (e) {

// frames = {};
const zip = new JSZip();
const start = e.data.start;
const end = e.data.end;
Expand All @@ -26,7 +25,7 @@ self.onmessage = function (e) {
_zip.file(relativePath).async('blob').then((fileData) => {
const reader = new FileReader();
reader.onload = (function(i, event){
postMessage({fileName : relativePath, index : fileIndex, data: reader.result});
postMessage({fileName : relativePath, index : fileIndex, data: reader.result, isEnd : i === inverseUnzippedFilesCount < start});
inverseUnzippedFilesCount --;
if (inverseUnzippedFilesCount < start){
self.close();
Expand Down
3 changes: 1 addition & 2 deletions cvat/apps/engine/media_extractors.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,14 +233,13 @@ def save_image(self, k, dest_path):
def save_as_chunks(self, chunk_size, task, progress_callback=None):
if not self._source_path:
raise Exception('No data to compress')

for i in range(math.ceil(len(self._source_path) / chunk_size)):
start_frame = i * chunk_size
input_images = os.path.join(self._tmp_dir, self._imagename_pattern)
input_options = '-f image2 -framerate 25 -start_number {}'.format(start_frame)
output_chunk = task.get_chunk_path(i)
self.prepare_dirs(output_chunk)
output_options = '-vframes {} -codec:v mpeg1video -q:v 0'.format(chunk_size)
output_options = '-vframes {} -f mpegts -c:a none -codec:v mpeg1video -bf 0 -b:v 800k'.format(chunk_size)

ff = FFmpeg(
inputs = {input_images: input_options},
Expand Down
Loading

0 comments on commit a5791a4

Please sign in to comment.