如何使用Nodejs将视频帧直接读入内存? [英] how to read video Frames directly into memory with Nodejs?

查看:34
本文介绍了如何使用Nodejs将视频帧直接读入内存?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要做的是拍摄视频并将其转换为帧并将此帧传递给模型以检测每一帧中的对象但问题是提取过程花费了太多时间而我不需要帧在我的磁盘上.

What i am trying to do is taking a video and diving it to frames and passing this frames to a Model to detect objects in each frame but the problem is the extraction process cost so much time and i don't need the frames on my disk.

推荐答案

fmpeg-stream 提供流功能.所以不需要写入文件.

fmpeg-stream offers stream capabilities. So there is no need to write to a file.

也可以直接使用 ffmpegspawn 一个新的子进程.它的 .stdout 属性是一个可读流.在event数据上,可以读取chunk.

It is also possible to use directly ffmpeg and spawn a new child process. Its .stdout property is a readable stream. On the event data, the chunk can be read.

const fs = require("fs");
const tf = require("@tensorflow/tfjs-node")

const logStream = fs.createWriteStream('./logFile.log');


const spawnProcess = require('child_process').spawn,
    ffmpeg = spawnProcess('ffmpeg', [
        '-i', 'videfile.mp4',
        '-vcodec', 'png',
        '-f', 'rawvideo',
        '-s', 'h*w', // size of one frame
        'pipe:1'
    ]);

ffmpeg.stderr.pipe(logStream); // for debugging

let i = 0

ffmpeg.stdout.on('data', (data) => {
    try {
        console.log(tf.node.decodeImage(data).shape)
        console.log(`${++i} frames read`)
        // dispose all tensors
    } catch(e) {
        console.log(e)
    } 
})


ffmpeg.on('close', function (code) {
    console.log('child process exited with code ' + code);
});

解码图像在 try catch 块中,以防止在块与帧不匹配时引发错误.

Decoding the image is in a try catch block to prevent error raised when the chunk does not match a frame.

防止解码与图像不对应的块的更强大的代码如下:

A more robust code to prevent decoding chunks that do not correspond to images will be the following:

const { Transform } = require("stream")

class ExtractFrames extends Transform {
    constructor(delimiter) {
        super({ readableObjectMode: true })
        this.delimiter = Buffer.from(delimiter, "hex")
        this.buffer = Buffer.alloc(0)
    }

    _transform(data, enc, cb) {
        // Add new data to buffer
        this.buffer = Buffer.concat([this.buffer, data])
        const start = this.buffer.indexOf(this.delimiter)
        if (start < 0) return // there's no frame data at all
        const end = this.buffer.indexOf(
            this.delimiter,
            start + this.delimiter.length,
        )
        if (end < 0) return // we haven't got the whole frame yet
        this.push(this.buffer.slice(start, end)) // emit a frame
        this.buffer = this.buffer.slice(end) // remove frame data from buffer

        if (start > 0) console.error(`Discarded ${start} bytes of invalid data`)
        cb()
    }
    _flush(callback) {
        // push remaining buffer to readable stream
        callback(null, this.buffer);
    }
}

const fs = require("fs");
const tf = require("@tensorflow/tfjs-node")

const logStream = fs.createWriteStream('./logFile.log');


const spawnProcess = require('child_process').spawn,
    ffmpeg = spawnProcess('ffmpeg', [
        '-i', 'generique.mp4',
        '-vcodec', 'mjpeg',
        '-f', 'rawvideo',
        '-s', '420x360', // size of one frame
        'pipe:1'
    ]);

ffmpeg.stderr.pipe(logStream); // for debugging

let i = 0

ffmpeg.stdout
.pipe(new ExtractFrames("FFD8FF")).on('data', (data) => {
    try {
        console.log(tf.node.decodeImage(data).shape)
        console.log(`${++i} frames read`)
        // dispose all tensors
    } catch(e) {
        console.log(e)
    } 
})


ffmpeg.on('close', function (code) {
    console.log('child process exited with code ' + code);
});

虽然上面的代码有效,但它仍然会很快填满内存.将帧提取与数据处理本身分开会有所帮助.

Though, the above code works, it will still fill up quickly the memory. Separating the frame extraction from the data processing itself will help.

async function* frames() {
        let resolve;
        let promise = new Promise(r => resolve = r);
        let bool = true;
        ls.stdout.pipe(new ExtractFrames("FFD8FF")).on('data', data => {
            resolve(data); 

            promise = new Promise(r => resolve = r); 
        });

        ls.on('close', function (code) {
            bool = false
            console.log('code')
        });

        while (bool) {
            const data = await promise; 
            yield data;
        }
}

(async() => {
     // data processing
     // possibly create tf.dataset for training
     for await (const data of stream()) {
         console.log(tf.node.decodeImage(data).shape)
         console.log(data);
    }
})()

这篇关于如何使用Nodejs将视频帧直接读入内存?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆