Skip to content
Advertisement

How to retrieve and save to Blob a binary file video from Flask?

I know few things about video encoding and I encountered an issue that is blocking me for few days.

Goal:

  1. Record a video from my laptop’s webcam with a VueJS front end application.
  2. Send this video to a Python flask app in the backend within a FormData through Axios and Flask.
  3. Receive the video in the Flask app.
  4. Simply send back the video to the frontend with a Flask response (without applying any changes to the video).
  5. Store and display this video on front end side.

Code:

  1. By default, ev element type is: “video/x-matroska;codecs=avc1”, I do not choose it.
// Start webcam stream
startCameraStream() {
    const windowConstraints = (window.constraints = {
        audio: false,
        video: true
    });
    navigator.mediaDevices
        .getUserMedia(windowConstraints)
        .then(stream => {
            this.$refs.webcamStream.srcObject = stream;
        }).catch(error => {
            alert("Browse doesn't support or there is some errors." + error);
        });
},

// Stop webcam stream
stopCameraStream() {
    let tracks = this.$refs.webcamStream.srcObject.getTracks();
    tracks.forEach(track => {
        track.stop();
    });
},

// Start to record webcam and save it into chunks array and create a blob object
startRecordCameraStream(stream) {
    this.mediaRecorder = new MediaRecorder(stream);

    this.mediaRecorder.ondataavailable = (ev) => {
        this.chunks.push(ev.data);
    };

    this.mediaRecorder.onstop = () => {
        this.blob = new Blob(this.chunks, {
            'type': "video/x-matroska;codecs=avc1"
        });
        this.chunks = [];
    };
    this.mediaRecorder.start();
},

// Stop to record webcam 
stopRecordCameraStream() {
    this.mediaRecorder.stop();
},          

The blob file is readable and I am able to display it with these few coding lines:

let videoURL = window.URL.createObjectURL(this.blob);
let vidSave = this.$refs.webcamRecord;
vidSave.src = videoURL;
  1. I send the blob within a formData with the key ‘webcam’ and send it on Flask url with axios
submitVideo(state, blob) {
    let formData = new FormData();
    formData.append('webcam', blob);
    return new Promise((resolve, reject) => {
        try {
            axios.post('http://127.0.0.1:5000/', formData, { 
                headers: {
                'Content-Type': 'multipart/form-data',
                }
            }).then((response) => {
                // TOO SEE IN STEP 5
                resolve();
            }).catch((error) => {
                console.log(error);
            })
        } catch (error) {
            reject(error)
        }
    });

}
  1. On the flask app, the formData has been sent and received and we are able to save and read the video on the backend side showing that everything is working well.
from flask import Flask, request
from flask_cors import CORS
import flask

#Instance of Flask class
app = Flask(__name__)
cors = CORS(app, resources={r"/*": {"origins": "*"}})

#Route function
@app.route('/', methods=["POST","GET"])
def model():
    if request.method == "POST":
        video = request.files['webcam'].stream.read()
        return flask.Response(video, mimetype='video/x-matroska')

I simply return back the binary object from Python to the VueJS frontend:

  1. video is a python bytes object which looks like this:
b'x1aExdfxa3xa3Bx86x81x01Bxf7x81x ... '

We simply return this bytes object in a flask response:

return flask.Response(video, mimetype='video/x-matroska')
  1. We received the flask response and store it in a blob file (response part from point 2)
}).then((response) => {
    let data = response.data;
    let video = new Blob([data],{'type': "video/x-matroska;codecs=avc1;"})
    state.modelVideo = video;
    resolve();
})

Once, we try to display the blob as explain in point 1, nothing happens:

let videoURL = window.URL.createObjectURL(this.modelVideo);
let vidSave = this.$refs.webcamRecord;
vidSave.src = videoURL;

Something really strange is that the initial and new blob files do not have the same size and when we read binary from both blob object we have this:

Initial blob binary from frontend (with a FileReader and readAsBinaryString function) :

"u001aEߣ£B†u0001B÷u0001Bòu..."

Received blob binary from backend (with a FileReader and readAsBinaryString function):

"u001aEߣ�B��u0001B��..."

Opinion:

My thought is that when sending back video from backend side, there is an encryption misunderstanding between Python and Javascript. I tried to encode in base64 on backend side and decode on frontend side but nothing changes.

The raw data response I received from backend is:

{
    "data": "u001aEߣ�B��u0001B��u0001B��..."
    "status": 200,
    "statusText": "OK",
    "headers": {
        "content-length": "15661",
        "content-type": "video/x-matroska"
    },
    "config": {
        "url": "http://127.0.0.1:5000/",
        "method": "post",
        "data": {},
        "headers": {
            "Accept": "application/json, text/plain, */*"
        },
        "transformRequest": [
            null
        ],
        "transformResponse": [
            null
        ],
        "timeout": 0,
        "xsrfCookieName": "XSRF-TOKEN",
        "xsrfHeaderName": "X-XSRF-TOKEN",
        "maxContentLength": -1,
        "maxBodyLength": -1
    },
    "request": {}
}

Advertisement

Answer

add responseType blob to request init option:

axios.post('http://127.0.0.1:5000/', formData, { 
  headers: {
    'Content-Type': 'multipart/form-data',
  },
  responseType: 'blob' // default is "json"
})
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement