Can videos be loaded in the front end through JavaScript when dragged and dropped?

I'm working on a project to create a web application that allows users to drag and drop a video file into the browser for processing using TensorFlow.js to make predictions.

So far, I've accomplished the following:

  • Loading the video file and playing it in an HTML video element
  • Reading pixel information from the current frame (and displaying it in a canvas element)
  • Controlling video playback using JavaScript with p5.js

However, my goal is to access all frames and loop through them quickly, without waiting for the next frame to load in the video element.

I know this issue can be resolved by backend processing after uploading the video file, but I want users to have confidence that their videos will never be stored on a server somewhere.

If you're interested, I'd be happy to share my code to provide more clarity on the project.

Answer №1

By utilizing the code below, you can easily upload files through a drag and drop method and display them on a p5 canvas for further customization in each frame, whether it's an image or video frame.

DRAG AND DROP:

To learn more about drag and drop functionality, refer to the links provided in the p5 Reference page:

  • dragOver -
  • dragLeave -
  • drop -

It is recommended to implement these functionalities within the preload() function as it runs only once in p5js by default!

LOGIC OF THE PROVIDED CODE:

Whenever an item or multiple items are dropped onto the designated drag and drop area, the readFile() function will process each item individually. You have the freedom to add custom logic, such as restricting file formats to specific types like png and mp4.

Moreover, every uploaded item has a click event listener attached so that clicking on the item stores the image source in a variable named uploadedItemSrc and identifies if it's a video or an image.

DRAWING ON CANVAS:

The draw() function allows you to adjust the frameRate. In p5.js, the maximum frame rate is determined by the device's performance. By default, p5.js aims to render frames as quickly as possible based on hardware and browser capabilities.

This feature enables you to manipulate video processing speed when needed. Additionally, before or after displaying the image or video frame, you can incorporate your preferred logic.

FINAL REMARKS:

Your statement:   "However, I want to be able to access all frames and loop through them as fast as possible (without waiting for the next frame to load in the video element)."

In p5JS, the drawFunction acts like a loop. The draw() function continues indefinitely unless frameRate = 0 or noLoop() is called.

Creating a Play Button using standard HTML would be simpler. Nevertheless, this example demonstrates how you can achieve the same result using p5 shapes like rect and text.

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);
    
    if(isPlaying){
        //Add your logic here after video frame is loaded on canvas
        tint(random(0,255),random(0,255),random(0,255));
    }


    //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/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="61115421504f554f50">[email protected]</a>/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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Best Practices for Installing Webpack in a Client/Server Folder Structure

Working on a React Nodejs web application and in the process of figuring out how to bundle the frontend using webpack. This is how my project's structured: Where exactly do I need to install webpack and configure webpack.config.js? I've noticed ...

Overlaying images on top of text

Is there a way to overlay an image on text, like a pattern image? Similar to applying color with a hex value in CSS: color: #ffffff; Any ideas on how this can be achieved? I want to have a pattern over text. Appreciate any help you can provide. Thanks ...

I'm having trouble pinpointing the cause of the never-ending loop in this React code that is using Material UI grid

There seems to be an issue with infinite looping in this code, and I can't figure out the cause, import React, { useEffect, useState } from 'react'; import VideoCardComponent from './VideoCard'; import Grid from '@mui/material ...

Unable to establish connection to MongoHQ using Node.js connection URL

I have successfully set up and run a Node.js app using my local development MongoDB with the following settings and code: var MongoDB = require('mongodb').Db; var Server = require('mongodb').Server; var dbPort = 27017; v ...

An issue has been identified in the bubble sort algorithm causing certain numerical lists to not be properly sorted when implemented in NodeJS

I am just beginning to learn about algorithms and have started with the bubble sort. I wrote my own implementation and it seems to work well most of the time when sorting a list of numbers from 1 to 100. However, occasionally there is one random number th ...

Ways to transfer data from JavaScript to Wicket framework

My Javascript method executes business logic on the client side and returns a value. I now want to access this value in my Wicket page. What is the most effective approach for achieving this? P.S. I am currently using Wicket 7. ...

Error encountered: Difficulty rendering Vue 3 components within Google Apps Script

Currently delving into Vue and Vue 3 while coding an application on Google Apps Script. Following tutorials from Vue Mastery and stumbled upon a remarkable example by @brucemcpherson of a Vue 2 app functioning on GAS, which proved to be too challenging in ...

Incorporating External JavaScript and CSS specifically for a single component

In my Angular 4 application, I have a specific component that requires the use of a js and css file. While most guidelines suggest placing these files in the Index.html file, I prefer to only load them when this particular component is accessed, not on e ...

Modify the CSS of a single element when a class is applied to a different element

I need to apply a specific CSS attribute to my submit button on the comments form when a user is logged in to Wordpress! When the .comment-form class contains p class="logged-in-as" instead of the standard p class="comment-notes", I want the p.form-submit ...

Execute a JavaScript function on a Node server following a click event in an HTML document

Hello everyone, I am currently working on a project using node.js in a Windows environment. With the help of the express module, I am trying to create a static page that includes a Submit form. When someone clicks the "Submit" button, I intend to execute a ...

Leveraging req.files for uploading multiple files at once

When it comes to handling a multiple file upload on the client side, I have encountered an issue with my HTML code. Here is what it looks like: form(method='post', enctype='multipart/form-data')#createReportForm input(type='file ...

What is the default way to toggle content in rows using Material UI?

Currently, I am utilizing Muitables and have a query regarding how to set the expanded rows to be displayed by default, similar to the illustration below: Upon initial page load, it is preferred for the content in that row to automatically expand (arrow d ...

Utilize JavaScript to extract an image from an external URL by specifying its attributes (id, class)

Is it possible to fetch an image from an external website by using its CSS id or class in conjunction with JavaScript/jQuery's get methods? If so, could someone provide guidance on how to achieve this task? ...

Tips for executing a callback function when triggering a "click" event in jQuery?

Having trouble triggering a custom event in the callback of a trigger call. Attempted solutions: var $input = $( ".ui-popup-container" ).find( "input" ).eq(2); function runtests () { console.log("clicked the input"); }; $input.trigger('click&ap ...

Into the depths we delve, extending beyond to an array of objects?

I have a question about the possibility of extending an array of objects like this: Imagine I have : myObj = [ {"name" : "one", "test" : ["1","2"]}, {"name" : "two", "test" : ["1","2"]} ] And I want to add to it something like - {"name" : ...

Is it possible to reposition the vertical scrollbar to a location that is not on the left or right side?

Whenever I resize my modal on small screens, a horizontal scrollbar appears, causing the vertical scrollbar to disappear as it gets stuck on the right side. I am looking for a solution to keep the vertical scrollbar on the right side of the modal while scr ...

executing ajax request to call a function, encountering partial success and encountering partial failure

Apologies for the lack of clarity in the title. I currently have a search engine that utilizes an ajax function. At present, when I type "t" in the search box, only the tags containing the word "t" are displayed (for example, if I type "t", then "test" sho ...

Extending a type by adding properties from separate files using TypeScript

I am faced with a situation where I have a file containing either a type or interface variable (all of which are exported), and I need to add new properties to this variable from different files without using extends. Essentially, making changes to the sam ...

Tips for adding an asterisk to the label of a Material-UI switch component

I am trying to include an asterisk symbol in the label by passing a required prop with a property, but it doesn't seem to be functioning correctly. <FormControlLabel control={ <Switch onChange={event => ...

Avoid API calls by using connect-history-api-fallback

I have implemented the connect-history-api-fallback along with the page.js router. page('/', index); page('/about', about); page(); function index() { console.log("viewing index"); } function about() { console.log("viewing ...