Inconsistent crop and overflay ffmpeg result with drawImage canvas - javascript

i try to encode the video block frame to specific pattern order, then in front-end it decode back to normal. I test it in back-end by decode back with same function, it back to normal. but in front-end with canvas the order of block not in right position. if you look into front-end function. it have same pattern. i try to check output from for generate, it equal to for in backend overlay builder command.
whats wrong with this?
ffmpeg config
const { spawn } = require('child_process');
function hflip(width) {
const sizeBlock = 16;
let filterCommands = '';
const length = Math.floor(width / sizeBlock);
for (let i=0; i < length; i++) {
filterCommands += `[0]crop=${sizeBlock}:480:${(i*sizeBlock)}:0[c${i}];`;
}
for (let i=0; i < length; i++) {
if (i == 0) filterCommands += '[0]';
if (i != 0) filterCommands += `[o${i}]`;
filterCommands += `[c${i}]overlay=x=${(width - sizeBlock)-(i*sizeBlock)}:y=0`;
if (i != (length - 1)) filterCommands += `[o${i+1}];`;
}
return filterCommands;
}
const crops = spawn('ffmpeg', [
'-i',
'C:/Software Development/project/blackpink.mp4',
'-filter_complex',
hflip(854),
'-c:a',
'copy',
'-c:v',
'libx264',
'-crf',
'30',
'-preset',
'ultrafast',
'-pix_fmt',
'yuv420p',
'C:/Software Development/project/hflip.mp4',
'-y'
], {
cwd: 'C:/Software Development/ffmpeg'
})
front-end
<!DOCTYPE html>
<html>
<head></head>
<body>
<button onclick="play()">play</button>
<script>
const canvas = document.createElement('canvas');
document.body.appendChild(canvas)
const context = canvas.getContext('2d');
const video = document.createElement('video');
video.src = 'https://drive.google.com/uc?export=download&id=1Z0aFg_N3kP0SUO_xOFB0UBjTRH6_mSmb&confirm=t'
function hflip(video) {
const widthBlock = 16;
const heightBlock = 480;
const length = Math.floor(video.videoWidth / widthBlock);
for (let i=0; i < length; i++) {
console.log({
cX: (i*widthBlock),
oX: (video.videoWidth - widthBlock) - (i*widthBlock)
});
context.drawImage(video, (i*widthBlock), 0, widthBlock, heightBlock, (video.videoWidth - widthBlock) - (i*widthBlock), 0, widthBlock, heightBlock)
}
}
video.onloadedmetadata = () => {
context.canvas.width = video.videoWidth;
context.canvas.height = video.videoHeight;
}
video.onplay = () => {
const updateCanvas = () => {
hflip(video);
video.requestVideoFrameCallback(updateCanvas);
}
updateCanvas();
}
function play() { video.play() }
</script>
</body>
</html>

Related

Scroll Sequence with .png image work weird

So I working on my project and I want to make some section kind of Apple Scroll Sequence.
But when I convert the image sequence to .PNG, it's awful :(
So, here's the image lookalike when I scroll the section. It's like shadowing / emm I don't know what it is haha.
Here's my codes:
<div class="intermezo-sequence">
<div class="sticky-element">
<div class="sequence-element">
<canvas id="intermezo_canvas"></canvas>
</div>
</div>
</div>
const canvas = document.querySelector('#hero_canvas')
const ctx = canvas.getContext('2d')
const heroSequence = document.querySelector('.hero-sequence')
const images = []
var sequence1 = <?= json_encode($sequence1) ?>;
sequence1.sort();
const frameCount = sequence1.length; // biar dinamis total nya
const prepareImages = () => {
for (var i = 0; i < frameCount; i++) {
// console.log(sequence1[i]);
const image = new Image()
// image.src = `./assets/images/studycase/sequence/${i}.jpg`
canvas.width = 1928;
canvas.height = 1000;
image.src = sequence1[i];
images.push(image)
if (i === 0) {
images[i].onload = () => drawImage1(0)
}
}
}
const drawImage1 = frameIndex => {
ctx.drawImage(images[frameIndex], 0, 0)
}
prepareImages()
const heroSection = document.getElementById("heroSection");
window.addEventListener('scroll', () => {
const scrollTop = document.documentElement.scrollTop - heroSection.offsetTop
const maxScrollTop = heroSequence.scrollHeight - window.innerHeight
const scrollFraction = scrollTop / maxScrollTop
const frameIndex = Math.max(0, Math.min(frameCount - 1, Math.ceil(scrollFraction * frameCount)))
images[frameIndex].onload = () => drawImage1(frameIndex)
requestAnimationFrame(() => drawImage1(frameIndex))
})
Is there anything that I should add to the logic? Thanks!

"Exception has occured: TypeError: Arrary.prototype.forEach called on null or undefined" in p5.js file

After trying to run some p5.js code in Visual Studio Code, I came upon this error. My HTML Code is below, and I copied and pasted it straight from the P5 editor:
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/addons/p5.sound.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
My javascript code is below, and when running in p5, no errors come up:
var numOfFood;
var foodList;
var numOfSlimes;
var slimesList;
function setup() {
createCanvas(400, 400);
numOfFood = prompt("Enter the amount of food that should be spawned: ");
numOfSlimes = prompt("Enter the amount of slimes to be spawned: ");
foodList = [];
slimesList = [];
background(220);
rect(25, 25, width - 50, height - 50);
spawnFood(numOfFood);
initializeSlimes(numOfSlimes);
}
// SLIME
Slime = function (x, y) {
this.x = x;
this.y = y;
}
Slime.prototype.draw = function () {
ellipse(this.x, this.y, 12, 12);
}
Slime.prototype.assignFood = function (index) {
this.food = foodList[index];
this.foodIndex = index;
}
// SLIME
// HAWK
Hawk = function (x, y) {
Slime.call(this, x, y);
this.type = "HAWK";
}
Hawk.prototype = Object.create(Slime.prototype);
//HAWK
// DOVE
Dove = function (x, y) {
Slime.call(this, x, y);
this.type = "DOVE";
}
Dove.prototype = Object.create(Slime.prototype);
// DOVE
// FOOD
Food = function (x, y) {
this.x = x;
this.y = y;
}
Food.prototype.draw = function () {
ellipse(this.x, this.y, 10, 10);
}
Food.prototype.assignSlime = function (firstSlime = null, secondSlime = null) {
this.firstSlime = firstSlime;
this.secondSlime = secondSlime;
}
// FOOD
spawnFood = function(food) {
fill(229, 246, 88);
var factors = []
var differences = []
for (let i = 1; i < food; i++) {
var value = food/i;
if (value != Math.floor(value)) {
continue;
}
factors.push([value, i]);
differences.push(abs(value - i));
}
var currentMinIndex = 0;
for (let i = 0; i < differences.length; i++) {
if (differences[i] < differences[currentMinIndex]) {
currentMinIndex = i;
}
}
for (let x = 50; x < 350; x += 300/factors[currentMinIndex][0]) {
for (let y = 50; y < 350; y += 300/factors[currentMinIndex][1]) {
var myFood = new Food(x, y);
foodList.push(myFood);
myFood.draw();
}
}
}
initializeSlimes = function (slimes) {
var tempx = 0;
var tempy = 0;
fill(67, 163, 235);
for (let i = 25; i < 375; i+= 375/(slimes / 4)) {
let mySlime = new Slime(i, 12.5); mySlime.draw(); slimesList.push(mySlime);
}
for (let i = 25; i < 375; i+= 375/(slimes / 4)) {
let mySlime = new Slime(i, 387.5); mySlime.draw(); slimesList.push(mySlime);
}
for (let i = 25; i < 375; i+= 375/(slimes / 4)) {
let mySlime = new Slime(12.5, i); mySlime.draw(); slimesList.push(mySlime);
}
for (let i = 25; i < 375; i+= 375/(slimes / 4)) {
let mySlime = new Slime(387.5, i); mySlime.draw(); slimesList.push(mySlime);
}
}
However, when I try to run this in VSCode, chrome opens to try and run the file, but then the window switches back to VSCode, and it shows me:
My error code (I don't have enough rep to embed a picture yet)
If anybody knew how to fix this, I would be extremely grateful. Is this a problem in my code, or is this a problem with the p5 library?
Could you show where the error appears in your javascript file rather than in the p5.js library itself?
Otherwise, I don't even see a call to Array.forEach() in your code snippit, did you make sure to paste all of the code you're running? Or since your p5.js file isn't even being loaded in your index.html, are you trying to run the p5.js file itself? That won't work, make sure you're running your index.html file.
I tried running your index.html using a copy of p5.js in the source folder and copied all of your code into a sketch.js file, and I was able to run it through VSCode. Let me know if this helps at all or if you have any other information that could help with fixing your problem!

how to make a video preview with canvas?

this is my first question here!
im trying to make a website that show videos that i make and i want my viewers can see a preview of video when they hover mouse on the a element or element .
i just do it but i have some problems and questions. lemme show you code example first and then i ask my questions.
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="thumbs" style="width:216px;height:468px;border: 5px solid blue;background-color:red;"><canvas onmouseover="getid1(this);" onmouseout="getid2(this);" id="canvas1"></canvas></div>
<script>
var thumbsList = [];
var delay = 100;
var i = 0;
var video = document.createElement("video");
var a = 0;
var m = document.getElementById("canvas1");
var mtx = m.getContext("2d");
var generate = true;
var animstop = false;
var vidFrames = 64;
m.width = 216;
m.height = 468;
video.preload = "auto";
video.src = "aaaa.mp4";
function stranim(bb){
if(generate){
animstop = false;
video.currentTime = i;
generateVid();
generate = false;
}else{
animstop = false;
startAnim();
}
}
function stpanim(bb) {
clearTimeout();
animstop = true;
mtx.drawImage(thumbsList[0], 0, 0);
}
// if i replace this section with generateVid() the code is working
/*video.addEventListener('seeked', function() {
var d = (video.duration / vidFrames) * 2;
generateThumbnail();
i += video.duration / vidFrames;
if (i <= video.duration) {
video.currentTime = i;
generateVid()
if(d == i){
startAnim();
}
}
});*/
function generateVid() {
var d = (video.duration / vidFrames) * 2;
generateThumbnail();
i += video.duration / vidFrames;
if (i <= video.duration) {
video.currentTime = i;
generateVid();
if(d == i){
startAnim();
}
}
}
function generateFirstThumbnail() {
var c = document.createElement("canvas");
var ctx = c.getContext("2d");
c.width = 216;
c.height = 468;
ctx.drawImage(video, 0, 0, 216, 468);
thumbsList.push(c);
thumbs.appendChild(m);
mtx.drawImage(thumbsList[0], 0, 0);
i += video.duration / vidFrames;
}
function generateThumbnail() {
var c = document.createElement("canvas");
var ctx = c.getContext("2d");
c.width = 216;
c.height = 468;
ctx.drawImage(video, 0, 0, 216, 468);
thumbsList.push(c);
}
function startAnim() {
var currentFrame = 0;
function anim() {
if(currentFrame != (vidFrames - 1) && animstop == false){
currentFrame = (currentFrame + 1) % thumbsList.length;
mtx.drawImage(thumbsList[currentFrame], 0, 0);
setTimeout(anim, delay);
}
}
anim();
}
function getid1(obj) {
stranim(obj.id)
}
function getid2(obj) {
stpanim(obj.id)
}
window.onload = function(){
generateFirstThumbnail();
};
</script>
</body>
</html>
the questions are :
1- why my generatevid() function is not working? this function is just like that eventlistener.
2- i want to add this code on a class to use it on multiple videos but idk how and i think this cant be done with js classes.( i search so many sites for it)
3-i can use 2d arrays for saving my video previews but is it dont make my site lower on load speed or it dont fill the ram of user?
4-there is any way that i make this code better and easyer?(i dont want to use jquery for no reason).
For a pure js approach you can check this not mine btw: https://codepen.io/tepexic/pen/BazYgJe
html:
<input type="file" accept="video/*" id="input-tag"/>
<hr>
<video controls id="video-tag">
<source id="video-source" src="splashVideo">
Your browser does not support the video tag.
</video>
JS
const videoSrc = document.querySelector("#video-source");
const videoTag = document.querySelector("#video-tag");
const inputTag = document.querySelector("#input-tag");
inputTag.addEventListener('change', readVideo)
function readVideo(event) {
console.log(event.target.files)
if (event.target.files && event.target.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
console.log('loaded')
videoSrc.src = e.target.result
videoTag.load()
}.bind(this)
reader.readAsDataURL(event.target.files[0]);
}
}
But for other approach i would probably use http://ffmpeg.org/ library to generate a preview video (e.g 10 seconds video) and https://videojs.com library for video player so you have a control when user hover the player.
I just did some test on your code, your video is getting seeked only once. No event is raised after that, which means your thumbnail will remain same.
Here is how I was able to fix it
function generateVid() {
var d = (video.duration / vidFrames) * 2;
generateThumbnail();
i += video.duration / vidFrames;
if (i <= video.duration) {
video.currentTime = i;
console.log("starting seeking");
if(d == i){
startAnim();
}
}
}
video.onseeked = (event) => {
if (animstop == false)
{
setTimeout(generateVid, delay);
}
console.log("seeked");
};

Firefox extension not able to select all images may be due to Canvas fuction getImageData()

In the below code I have imported my machine learning model through function model_startup(). model_startup() is working fine. But after that, I am getting into function blockk(), through this function I am trying to select all images on website by document.getElementsByTagName('img') and do prediction through that image with the help of an imported model. But my problem is that my second function is not selecting all images on website and selecting only some number of starting images and after prediction on that some number of images it get stopped.
I am new to javascript and trying to implement it as a firefox extension. Please help me in this problem
console.log('STARTING UP')
const MODEL_PATH = 'mdl/model.json'
const IMAGE_SIZE = 64;
let model;
async function model_startup()
{
console.log('Launching TF.js!');
tf.ENV.set('WEBGL_PACK',false);
await tf.ready();
console.log('TensorflowJS backend is: '+tf.getBackend());
let url = browser.runtime.getURL(MODEL_PATH);
console.log('Loading model... '+url);
try
{
model = await tf.loadLayersModel(url);
}
catch(e)
{
console.log('Failed to load model! '+e);
}
console.log('Model: ' + model);
console.log('Warming up...');
let dummy_data = tf.zeros([1, IMAGE_SIZE, IMAGE_SIZE, 3]);
// dummy_data.print();
let warmup_result = model.predict(dummy_data);
console.log("finding type : $$$$$$$$ " + typeof warmup_result)
warmup_result.print();
warmup_result.dispose();
console.log('Ready to go!');
// blockk();
};
model_startup().then(blockk);
function blockk() {
const x = document.getElementsByTagName('img');
console.log("wn ############################## " + x.length);
let inferenceCanvas = document.createElement('canvas');
inferenceCanvas.width = 64;
inferenceCanvas.height = 64;
let inferenceCtx = inferenceCanvas.getContext('2d', { alpha: false});
inferenceCtx.imageSmoothingEnabled = true;
for(var i = 0; i < x.length; i++)
{
console.log('pixel kmvsl lsvn');
let img = x[i];
inferenceCtx.drawImage(img, 0, 0, img.width, img.height, 0, 0, 64, 64);
const rightSizeImageData = inferenceCtx.getImageData(0, 0, 64, 64); //write promise. It may work.
const rightSizeImageDataTF = tf.browser.fromPixels(rightSizeImageData);
const floatImg = rightSizeImageDataTF.toFloat();
console.log('predicting...');
let scaled = floatImg.div(tf.scalar(255));
let batched = tf.stack([scaled]);
let result = model.predict(batched);
const val = result.dataSync()[0];
console.log(val);
if (val > 0.4)
{
console.log("blocking" + i);
let h = img.height
let w = img.width
pth = img.src
x[i].setAttribute("src", "https://indianonlineseller.com/wp-content/uploads/2017/05/blocked-listing.png");
// x[i].setAttribute("onclick", ` this.src = '${pth}' `);
x[i].setAttribute("data-src", "https://indianonlineseller.com/wp-content/uploads/2017/05/blocked-listing.png");
x[i].height = h;
x[i].width = w;
console.log('blocked');
}
console.log("co ########################### " + x.length)
}
};
The line in my code which is causing problem is
const rightSizeImageData = inferenceCtx.getImageData(0, 0, 64, 64);
If I remove this code and other code related to this line and I run it then my code is able to select all the images on webpage. Can you tell me why this may be happening?

javascript image slider start

I'm trying to understand javascript before going to jQuery and I made a simple image slider.
I ended up with the following code working well when I manually start it on browser console, and I can't figure out how to start it and if using Promise would do, and how.
Reduced code:
/*some variable declarations and value assignations*/
function cut(p1){
for (var i = 0; i < cuts; i++){
/*canvas working with path pattern and fill*/
slice[p1][i] = new Image();
slice[p1][i].src = canvas.toDataURL();
}
}
function slider(){
/*time based image selection and canvas clear*/
for (var i = 0; i < 10; i++){
y = /*timebased calc*/;
if(y<0){y=0;}
ctx.drawImage(slice[im][i], 0, y);
}
window.requestAnimationFrame(slider);
}
img[0].onload = function() {cut(0);};
img[1].onload = function() {cut(1);};
Full code:
var height = 500, width = 707, cuts = 10, cW = Math.ceil(width/cuts);
var img = [new Image(), new Image()];
var slice = [];
for (var i = 0; i < img.length; i++){
slice[i] = [];
}
var x = [];
for (var i=0; i<cuts; i++){
x[i]=Math.ceil(((i+1)*width)/cuts);
}
function cut(p1){
for (var i = 0; i < cuts; i++){
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
var context = canvas.getContext('2d');
var pat = context.createPattern( img[p1], 'no-repeat' );
context.fillStyle = pat;
context.beginPath();
context.moveTo(x[i], 0);
context.lineTo(x[i], height);
context.lineTo(x[i]-cW, height);
context.lineTo(x[i]-cW, 0);
context.closePath();
context.fill();
slice[p1][i] = new Image();
slice[p1][i].src = canvas.toDataURL();
}
}
var canv = document.createElement('canvas');
document.body.appendChild(canv);
canv.width = width;
canv.height = height;
var ctx = canv.getContext('2d');
var sTime= 0;
function slider(){
var t = (performance.now() - sTime) % 10000;
if(t%5000 === 2000){
ctx.clear();
}
var im = 0;
if(t >= 5000){
im = 1;
} else {
im = 0;
}
for (var i = 0; i < 10; i++){
t = t%5000;
y = 2000-((t)+(i*100));
if(y<0){y=0;}
ctx.drawImage(slice[im][i], 0, y);
}
window.requestAnimationFrame(slider);
}
CanvasRenderingContext2D.prototype.clear = function () {this.clearRect(0, 0, this.canvas.width, this.canvas.height);}
img[0].onload = function() {cut(0);};
img[1].onload = function() {cut(1);};
img[0].src = 'mountain.jpg';
img[1].src = 'beach.jpg';
Haven't tested this but it might come close:
function imageLoader(imagePaths, onLoad, onFinished) {
var images = [];
var arrayLength = imagePaths.length;
function callback() {
if(--arrayLength === 0) onFinished();
}
imagePaths.forEach(function(imagePath, index) {
var image = new Image();
image.onload(onLoad(index, callback));
image.src = imagePath;
images[index] = image;
});
return images;
}
modify cut() to:
function cut(p1, cb){
//.
//.
//.
cb();
}
replace
img[0].onload = function() {cut(0);};
img[1].onload = function() {cut(1);};
img[0].src = 'mountain.jpg';
img[1].src = 'beach.jpg';
with:
img = imageLoader(['mountain.jpg', 'beach.jpg'], cut, slider);

Categories

Resources