[Answered ]-How can you use JavaScript to send a video blob to a Django view using a Django form?

1👍

I got the approach to work. My problem was the MediaRecorder wasn’t finished doing its thing before I was attempting to create the blob. Here’s my full script so you can see how I fixed it (creating the recordingPromise and making stopCapture an async function were key (so that I could await the recordingPromise before trying to create the blob)):

JavaScript

/* ------------------- 
-------- Capture -------
------------------- */
const vidDisplay = document.querySelector("#vidDisplay");
const startRecordBtn = document.querySelector("#startRecordBtn");
const stopRecordBtn = document.querySelector("#stopRecordBtn");
const sendBtn = document.querySelector("#sendBtn");
const blobInput = document.querySelector("#id_vidBlob");
const resultDisplay = document.querySelector("#result");

/* -------------------------
--------- Variables ---------- 
--------------------------- */
// gotta have the chunks
const recordedChunks = [];

// User media constraints
const constraints = {
  audio: true,
  video: {
    width: 640,
    height: 360
  }
};
// declare stream globally
let stream;
// declare mediaRecorder globally
let mediaRecorder;
// declare recordingPromise globally
let recordingPromise;
// Recorder options
const recorderOptions = {
  mimeType: "video/webm; codecs=vp9",
  audioBitsPerSecond: 8000,
  videoBitsPerSecond: 156250,
};

/* -------------------------
--------- Functions ---------- 
--------------------------- */

// Function for starting screen capture
const startCapture = async function() {
  try {
    stream = await navigator.mediaDevices.getUserMedia(constraints);
    vidDisplay.srcObject = stream;

    // create media recorder
    mediaRecorder = new MediaRecorder(stream, recorderOptions);
    mediaRecorder.ondataavailable = handleDataAvailable;

    // start up recorder
    mediaRecorder.start();

    // Create a promise to resolve when the recording is stopped
    recordingPromise = new Promise((resolve) => {
      mediaRecorder.onstop = resolve;
    });
  } catch (err) {
    console.error(err);
  }
}

// Function for recorder
const handleDataAvailable = function(event) {
  console.log("data is available");
  if (event.data.size > 0) {
    recordedChunks.push(event.data);
  } else {
    // …
  }
}

// Function for stopping screen capture
const stopCapture = async function() {
  let tracks = vidDisplay.srcObject.getTracks();

  tracks.forEach((track) => track.stop());
  vidDisplay.srcObject = null;

  // stop ye recorder
  mediaRecorder.stop();

  await recordingPromise;

  const blob = new Blob(recordedChunks, {type: "video/webm",}); // create blob from recordedChunks

  // Convert the Blob to base64 and then JSON format to submit with form
  const reader = new FileReader();
  reader.onloadend = function () {
    try {
      const base64data = reader.result.split(',')[1];;
      console.log(base64data);

      // Create a JSON-formatted string with the base64-encoded blob data
      const jsonData = JSON.stringify({ videoBlob: base64data });
      
      // Set the value of the hidden input to the base64-encoded blob
      blobInput.value = jsonData;
    } catch (error) {
      console.error('Error during FileReader operation:', error);
    }
  };

  // read video data
  reader.readAsDataURL(blob);
}

/* -------------------------
--------- Event Listeners ---------- 
--------------------------- */

startRecordBtn.addEventListener("click", startCapture);
stopRecordBtn.addEventListener("click", stopCapture);

This made it so I could easily submit the blob in the JSONField that I created in my form, and it’s proving pretty easy to work with that in the view so that I can upload the video file to a 3rd party storage service.

Leave a comment