如何从 Flask 检索二进制文件视频并将其保存到 Blob?

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

我对视频编码知之甚少,我遇到了一个困扰我几天的问题。

目标:

  1. 使用 VueJS 前端应用程序从笔记本电脑的网络摄像头录制视频。
  2. 通过 Axios 和 Flask 将此视频发送到后端的 Python Flask 应用。
  3. 在 Flask 应用程序中接收视频。
  4. 只需使用 Flask 响应将视频发回前端(不对视频应用任何更改)。
  5. 在前端存储和显示此视频。

代码:

  1. 默认ev元素类型为:“video/x-matroska;codecs=avc1”,我不选
// 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();
},          

blob 文件是可读的,我可以用这几行代码显示它:

let videoURL = window.URL.createObjectURL(this.blob);
let vidSave = this.$refs.webcamRecord;
vidSave.src = videoURL;
  1. 我使用密钥 'webcam' 在 formData 中发送 blob,然后使用 axios
  2. 在 Flask url 上发送它
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. 在 flask app 上,formData 已经发送和接收,我们可以在后端保存和读取视频,显示一切正常。
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')

我只是 return 将二进制对象从 Python 返回到 VueJS 前端:

  1. 视频是一个 python 字节对象,如下所示:
b'\x1aE\xdf\xa3\xa3B\x86\x81\x01B\xf7\x81\x ... '

我们只是 return 烧瓶响应中的这个字节对象:

return flask.Response(video, mimetype='video/x-matroska')
  1. 我们收到了 flask 响应并将其存储在 blob 文件中(第 2 点的响应部分)
}).then((response) => {
    let data = response.data;
    let video = new Blob([data],{'type': "video/x-matroska;codecs=avc1;"})
    state.modelVideo = video;
    resolve();
})

有一次,我们尝试按照第 1 点中的说明显示 blob,但没有任何反应:

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

真正奇怪的是,初始和新的 blob 文件大小不同,当我们从两个 blob 对象读取二进制文件时,我们有这个:

来自前端的初始 blob 二进制文件(带有 FileReader 和 readAsBinaryString 函数):

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

从后端接收到 blob 二进制文件(使用 FileReader 和 readAsBinaryString 函数):

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

意见:

我的想法是,当从后端发送回视频时,Python 和 Javascript 之间存在加密错误。我尝试在后端使用 base64 编码并在前端解码,但没有任何变化。

我从后端收到的原始数据响应是:

{
    "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": {}
}

将 responseType blob 添加到请求初始化选项:

axios.post('http://127.0.0.1:5000/', formData, { 
  headers: {
    'Content-Type': 'multipart/form-data',
  },
  responseType: 'blob' // default is "json"
})