In a nutshell
如何使用JavaScript通过Django表单将视频数据blob获取到Django视图?
背景
我正在构建一个录制网络摄像头视频的功能。我已经成功地解决了这一部分。我可以使用JavaScript来流式传输用户的摄像头和麦克风,记录流,将其转换为blob,然后我能够将blob转换为文件。然而,我不想要文件,因为我需要用户的视频简单地发送到我的后端,我不希望用户与视频文件进行交互(我刚刚了解到,由于安全原因,您不能以编程方式将<input type='file'>
元素分配给文件)。* 这就是为什么我希望只发送二进制数据。*
What I've Tried(and what the result was)(我尝试了什么,结果是什么)
- 就像我说的,我尝试在Django表单中使用FileField(但由于固有的Web安全限制,没有工作)。让用户自己下载和上传文件不符合项目要求。
- 我试过在Django表单中使用JSONField并提交JSON格式的二进制文件。也许这仍然可以工作,但我无法将二进制数据转换为JSON格式。到目前为止,我尝试的所有方法都是,JSON中应该包含blob的值最终要么是空字符串
undefined
,要么是这样的字符串->"data:"
。
代码
JavaScript
// This function is what MediaRecorder uses to give data to "recordedChunks"
const handleDataAvailable = function(event) {
if (event.data.size > 0) {
recordedChunks.push(event.data);
} else {
// …
}
}
字符串
问题在于下一步(停止记录,生成blob,并将blob获取到input
元素)。我将展示此函数的每个变体,并提前解释base64data
的值最终是什么:
console.log(base64data);
= undefined
const stopCapture = function() {
mediaRecorder.stop();
const blob = new Blob(recordedChunks, {type: "video/webm",});
// Convert the Blob to base64 and then JSON format to submit with form
const reader = new FileReader();
reader.onload = function () {
const base64data = reader.result.split(',')[1];
console.log(base64data);
const jsonData = JSON.stringify({ videoBlob: base64data });
// Set the value of the input element to the base64-encoded blob
jsonInput.value = jsonData;
};
reader.readAsDataURL(blob);
}
型
console.log(base64data);
= data:
将const base64data = reader.result.split(',')[1];
更改为const base64data = reader.result;
。
console.log(base64data);
=空字符串
//...after blob is created
// Convert the Blob to base64 and then JSON format to submit with form
const reader = new FileReader();
reader.onload = function () {
const arrayBuffer = reader.result;
// Convert array buffer to base64
const base64data = arrayBufferToBase64(arrayBuffer);
// 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 JSON representation
blobInput.value = jsonData;
};
reader.readAsArrayBuffer(blob);
}
// Function to convert array buffer to base64
function arrayBufferToBase64(arrayBuffer) {
const uint8Array = new Uint8Array(arrayBuffer);
const binaryString = uint8Array.reduce((acc, byte) => acc + String.fromCharCode(byte), '');
return btoa(binaryString);
}
型
其他想法
- 也许最好不要使用Django表单?如果我这样做,那么我会通过JavaScript本身将表单数据提交到Django中的一个单独视图(使用
formData()
和fetch()
)。然而,我宁愿不这样做,因为我喜欢Django表单提供的内置安全性。 - 也许最好先把数据发送到我的Django后端(一个单独的视图)*,然后再把它变成一个blob?
Django表单和视图代码
包括这一点,以防万一有关于我的整体工作流程的建议,因为我的最终目标是从用户录制视频到我的后端发送视频到第三方存储服务。
forms.py
from django import forms
class VidFileUploadForm(forms.Form):
vidBlob = forms.JSONField(widget=forms.HiddenInput)
name = forms.CharField(required=True)
descrip = forms.CharField(required=True)
型
views.py
class VidDemoTwoView(FormMixin, TemplateView, ProcessFormView):
"""View class for experimental video recording view"""
template_name = 'evaluations/vid_demo2.html'
form_class = VidFileUploadForm
success_url = reverse_lazy('view-vid-demo')
def form_valid(self, form):
vidBlob = form.cleaned_data['vidBlob']
name = form.cleaned_data['name']
description = form.cleaned_data['descrip']
#logic to turn video blob into video file and then upload to 3rd party storage service
return super().form_valid(form)
型
1条答案
按热度按时间qni6mghb1#
我得到了工作的方法。我的问题是MediaRecorder在我尝试创建blob之前没有完成它的工作。这里是我的完整脚本,所以你可以看到我是如何修复它的(创建
recordingPromise
并使stopCapture成为async
函数是关键(这样我就可以在尝试创建blob之前await
recordingPromise)):JavaScript
字符串
这使得我可以很容易地提交我在表单中创建的JSONField中的blob,并且证明在视图中使用它非常容易,这样我就可以将视频文件上传到第三方存储服务。