我一直在尝试创建一个网络应用程序,用户将视频文件拖放到浏览器中,然后使用 TensorFlow.js 对其进行一些处理并进行预测。
到目前为止,我能够:
但是,我希望能够访问所有帧并尽快循环它们(无需等待下一帧加载到视频元素中)。
我知道这通常是一个很容易解决的问题,只需在上传实际视频文件后在后端执行此操作即可。但是,我希望人们在使用该应用程序时知道他们的视频永远不会出现在某个服务器中。
如果您认为它可能有助于解释,我很乐意分享我的代码。
以下代码将允许您使用拖放方法上传文件,并将它们绘制在 p5 画布上,其中可以在每个帧上应用附加逻辑,无论是图像还是视频帧。
拖放:
有关拖放的更多信息,请检查第 5 页参考页面中的以下链接:
dragOver
- https://p5js.org/reference/#/p5.Element/dragOverdragLeave
- https://p5js.org/reference/#/p5.Element/dragLeavedrop
- https://p5js.org/reference/#/p5.Element/drop建议在
preload()
函数中实现这些,默认情况下在p5js中仅执行一次!
逻辑:
每当将一个项目或一组项目放在指定的拖放区域上时,将为每个项目执行
readFile()
功能。您可以在此处配置和/或限制特定文件格式。例如,以下代码仅接受 png
和 mp4
文件。除非另有说明,上传到此的任何其他文件都不会执行任何操作。
此外,每个上传的项目都有一个点击事件监听器,因此每当点击时,它都会将图像 src 存储在变量中
uploadedItemSrc
并定义是视频还是图像。
在画布上绘图:
在
draw()
功能中,您可以控制frameRate。在 p5.js 中,最大帧速率由运行代码的设备的性能决定。默认情况下,p5.js 将尝试尽快渲染帧,仅受硬件和浏览器功能的限制。
这将使您能够根据需要以更快的速率处理视频。最后,在绘制图像或视频帧之前或之后,您可以实现您想要的逻辑。
最终说明:
你说: “但是,我希望能够访问所有帧并尽快循环它们(无需等待下一帧加载到视频元素中)。”
在 p5JS 中,drawFunction 类似于循环。除非执行
frameRate = 0
或noLoop()
函数,否则draw()函数永远不会停止运行
const FPS = 120;
var dropzone
var elem;
let uploadedItemSrc;
var isImage = false;
var isVideo = false;
const hightlight = () => {
dropzone.style('background-color', '#4caf50')
};
const unhightlight = () => {
dropzone.style('background-color', '#fff')
};
//Play Button Info
let isPlaying = false;
let buttonWidth = 60;
let buttonHeight = 30;
let buttonX = 10;
let buttonY;
//Preload Method allow drag and drop
function preload() {
dropzone = select('#dropzone');
dropzone.dragOver(hightlight);
dropzone.dragLeave(unhightlight);
dropzone.drop(readFile, unhightlight);
}
//Create Canvas and set up play button positioning
function setup() {
var canvasParent = document.getElementById('canvasParent');
var myCanvas = createCanvas(canvasParent.offsetWidth, canvasParent.offsetHeight).parent(canvasParent);
buttonY = height - buttonHeight - 10;
}
//Draw Images (Video Frames)
function draw() {
clear();
background(0);
frameRate(FPS);
if (isImage) {
image(uploadedItemSrc, 0, 0, width, height);
}
if (isVideo) {
//Add your logic here before video frame is loaded on canvas
image(uploadedItemSrc, 0, 0, width, height);
//Add your logic here after video frame is loaded on canvas
//Draw Play Button
fill(200);
rect(buttonX, buttonY, buttonWidth, buttonHeight);
fill(0);
textAlign(CENTER, CENTER);
textSize(16);
text(isPlaying ? "Pause" : "Play", buttonX + buttonWidth / 2, buttonY + buttonHeight / 2);
}
}
function readFile(file) {
var fileExtension = file.subtype.toLowerCase();
var uploadedItems = select('#uploadedItems');
// If Image
if (fileExtension.startsWith("png")) {
let img = createImg(file.data);
img.parent(uploadedItems);
img.mouseClicked(function() {
console.log("Getting Image Information!");
loadImage(img.elt.src, function(loadedImage) {
uploadedItemSrc = loadedImage;
isImage = true;
isVideo = false;
});
});
}
// If Video
else if (fileExtension.startsWith("mp4")) {
let video = createVideo(file.data);
video.parent(uploadedItems);
video.mouseClicked(function() {
console.log("Getting Video Information!");
uploadedItemSrc = video;
isImage = false;
isVideo = true;
});
}
}
function mouseClicked() {
if (mouseX > buttonX && mouseX < buttonX + buttonWidth && mouseY > buttonY && mouseY < buttonY + buttonHeight) {
if (uploadedItemSrc && uploadedItemSrc instanceof p5.Element) {
if (uploadedItemSrc.elt.paused) {
uploadedItemSrc.elt.play();
isPlaying = true;
} else {
uploadedItemSrc.elt.pause();
isPlaying = false;
}
}
}
}
#uploadedItems img,
#uploadedItems video {
width: 100px;
height: 70px;
margin: 10px;
border: 1px solid black;
}
<!DOCTYPE html>
<html>
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/[email protected]/lib/p5.min.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-12 p-0">
<div class="text-center dropzone w-100 fs-3 border rounded-3 p-4" id="dropzone">
Drag your file here <br>
<small class="fs-6">.mp4 or .png</small>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-md-6 pl-1 pr-1">
<div id="uploadedItems" class="d-flex flex-wrap border rounded-3 border-1 p-2" style="height: 200px; overflow-y: auto;">
<!-- Uploaded items will be displayed here -->
</div>
</div>
<div class="col-md-6 p-0 border rounded-3" id="canvasParent">
</div>
</div>
</div>
</body>
</html>