【问题标题】:How can I save a video recorded using MediaRecorder to a file in Asp.NET Core?如何将使用 MediaRecorder 录制的视频保存到 Asp.NET Core 中的文件中?
【发布时间】:2020-06-21 01:46:27
【问题描述】:

顺便说一句,请不要发布指向其他类似问题的链接,因为我已经看到了所有这些问题,但它们没有帮助。我已经为此工作了 7 个小时。

所以,我正在尝试从网络摄像头(使用 MediaRecorder)捕获视频,并通过控制器将其保存到文件(在 wwwroot 或数据库中)。 我有视频捕获部分工作,但我不确定如何将记录的blobs 转换为文件或可写对象。

这是它的工作原理。我使用此脚本进行录制。这是一个演示,它运行良好,除了它只有一个下载选项。脚本中负责下载的部分被注释掉了,下面是我实现的部分,用于尝试上传此视频并将其保存在文件夹中。

const mediaSource = new MediaSource();
mediaSource.addEventListener('sourceopen', handleSourceOpen, false);
let mediaRecorder;
let recordedBlobs;
let sourceBuffer;

const errorMsgElement = document.querySelector('span#errorMsg');
const recordedVideo = document.querySelector('video#recorded');
const recordButton = document.querySelector('button#record');
recordButton.addEventListener('click', () => {
    if (recordButton.textContent === 'Start Recording') {
        startRecording();
    } else {
        stopRecording();
        recordButton.textContent = 'Start Recording';
        playButton.disabled = false;
        downloadButton.disabled = false;
    }
});

const playButton = document.querySelector('button#play');
playButton.addEventListener('click', () => {
    const superBuffer = new Blob(recordedBlobs, { type: 'video/webm' });
    recordedVideo.src = null;
    recordedVideo.srcObject = null;
    recordedVideo.src = window.URL.createObjectURL(superBuffer);
    recordedVideo.controls = true;
    recordedVideo.play();
});

const downloadButton = document.querySelector('button#download');
downloadButton.addEventListener('click', () => {
    const blob = new Blob(recordedBlobs, { type: 'video/webm' });
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = url;
    a.download = 'test.webm';
    document.body.appendChild(a);
    a.click();
    setTimeout(() => {
        document.body.removeChild(a);
        window.URL.revokeObjectURL(url);
    }, 100);
});

downloadButton.addEventListener('click', () => {
    var formData = new FormData();
    formData.append('video-filename', fileName);
    formData.append('video-blob', recordedBlobs);
    var xhr = new XMLHttpRequest();
    xhr.open('POST', '/page/upload');
    xhr.send(formData);
});

function handleSourceOpen(event) {
    console.log('MediaSource opened');
    sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vp8"');
    console.log('Source buffer: ', sourceBuffer);
}

function handleDataAvailable(event) {
    console.log('handleDataAvailable', event);
    if (event.data && event.data.size > 0) {
        recordedBlobs.push(event.data);
    }
}

function startRecording() {
    recordedBlobs = [];
    let options = { mimeType: 'video/webm;codecs=vp9' };
    if (!MediaRecorder.isTypeSupported(options.mimeType)) {
        console.error(`${options.mimeType} is not Supported`);
        errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
        options = { mimeType: 'video/webm;codecs=vp8' };
        if (!MediaRecorder.isTypeSupported(options.mimeType)) {
            console.error(`${options.mimeType} is not Supported`);
            errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
            options = { mimeType: 'video/webm' };
            if (!MediaRecorder.isTypeSupported(options.mimeType)) {
                console.error(`${options.mimeType} is not Supported`);
                errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
                options = { mimeType: '' };
            }
        }
    }

    try {
        mediaRecorder = new MediaRecorder(window.stream, options);
    } catch (e) {
        console.error('Exception while creating MediaRecorder:', e);
        errorMsgElement.innerHTML = `Exception while creating MediaRecorder: ${JSON.stringify(e)}`;
        return;
    }

    console.log('Created MediaRecorder', mediaRecorder, 'with options', options);
    recordButton.textContent = 'Stop Recording';
    playButton.disabled = true;
    downloadButton.disabled = true;
    mediaRecorder.onstop = (event) => {
        console.log('Recorder stopped: ', event);
        console.log('Recorded Blobs: ', recordedBlobs);
    };
    mediaRecorder.ondataavailable = handleDataAvailable;
    mediaRecorder.start(10); // collect 10ms of data
    console.log('MediaRecorder started', mediaRecorder);
}

function stopRecording() {
    mediaRecorder.stop();
}

function handleSuccess(stream) {
    recordButton.disabled = false;
    console.log('getUserMedia() got stream:', stream);
    window.stream = stream;

    const gumVideo = document.querySelector('video#gum');
    gumVideo.srcObject = stream;
}

async function init(constraints) {
    try {
        const stream = await navigator.mediaDevices.getUserMedia(constraints);
        handleSuccess(stream);
    } catch (e) {
        console.error('navigator.getUserMedia error:', e);
        errorMsgElement.innerHTML = `navigator.getUserMedia error:${e.toString()}`;
    }
}

document.querySelector('button#start').addEventListener('click', async () => {
    const hasEchoCancellation = false;
    const constraints = {
        audio: {
            echoCancellation: { exact: hasEchoCancellation }
        },
        video: {
            width: 1280, height: 720
        }
    };
    console.log('Using media constraints:', constraints);
    await init(constraints);
});

这是原始部分:

const downloadButton = document.querySelector('button#download');
//downloadButton.addEventListener('click', () => {
//    const blob = new Blob(recordedBlobs, { type: 'video/webm' });
//    const url = window.URL.createObjectURL(blob);
//    const a = document.createElement('a');
//    a.style.display = 'none';
//    a.href = url;
//    a.download = 'test.webm';
//    document.body.appendChild(a);
//    a.click();
//    setTimeout(() => {
//        document.body.removeChild(a);
//        window.URL.revokeObjectURL(url);
//    }, 100);
//});

我的尝试:

downloadButton.addEventListener('click', () => {
    var formData = new FormData();
    formData.append('video-filename', fileName);
    formData.append('video-blob', recordedBlobs);
    var xhr = new XMLHttpRequest();
    xhr.open('POST', '/page/upload');
    xhr.send(formData);
});

这会将记录器 blob(显然是这些视频的存储方式)发送到控制器,此时看起来像这样:

[HttpPost]
public async Task<IActionResult> Upload()
{
    var form = Request.Form;
    var fileName = form["video-filename"];
    Debug.WriteLine(form.ToString());
    Debug.WriteLine(form["video-filename"]);
    Debug.WriteLine(form["video-blob"].ToString());

    //var filePath = Path.Combine(Directory.GetCurrentDirectory(), @"wwwroot\videos", fileName);
    //using (var fileStream = new FileStream(filePath, FileMode.Create))
    //{
    //    await form.CopyToAsync(fileStream);
    //}
    return View("Upload");
}

我可以访问文件名和 blob 数组,但我不知道如何将其保存到文件中。对你的帮助表示感谢。

【问题讨论】:

标签: asp.net .net asp.net-core filestream mediarecorder


【解决方案1】:

您可以向某个服务器 url 发出 ajax 发布请求,并将该视频文件保存到服务器目录中。

    this.blob = new Blob(this.blobs, { type: 'video/mp4' });
    var videoObj = new File([this.blob], "recording.mp4");
 
    var client = new Vimeo(CLIENT_ID, CLIENT_SECRET, ACCESS_TOKEN);
     var params = {
      'name': 'Vimeo API SDK test upload',
      'description': "This video was uploaded through the Vimeo API's NodeJS SDK."
    }

// making axios post request to php server to save this video
 axios.post('https://your_server_url.com/host.php', videoObj)
       .then(res => {
         console.log('upload done ')
         console.log(res.data.url)
       })

// here i am uploading video to vimeo 
   

 client.upload(
      videoObj,
      params,
      function (uri) {
        console.log('File upload completed. Your Vimeo URI is:', uri)
      },
      function (bytesUploaded, bytesTotal) {
        var percentage = (bytesUploaded / bytesTotal * 100).toFixed(2)
        console.log(bytesUploaded, bytesTotal, percentage + '%')
      },
      function (error) {
        console.log('Failed because: ' + error)
      }
    )

处理文件和保存文件的php代码

<?php   
set_time_limit(0);
header('Content-Type: application/json; charset=utf-8');    
header("Access-Control-Allow-Origin: *");   
header("Access-Control-Allow-Methods: PUT, GET, POST"); 



$response = array();    
$upload_dir = 'recordings/';    
$server_url = 'https://your_server_url';    

if($_FILES['video'])    
{   
    $video_name = $_FILES["video"]["name"]; 
    $video_tmp_name = $_FILES["video"]["tmp_name"]; 
    $orig_file_size = filesize($video_tmp_name);
    $error = $_FILES["video"]["error"]; 

    if($error > 0){ 
        $response = array(  
            "status" => "error",    
            "error" => true,    
            "message" => "Error uploading the file 1!",
            "detail"=>  $_FILES["video"]["error"],
        );  
    }else   
    {
    $target_file = 'recordings/'. $_FILES['video']['name'];
    $chunk_size = 256; // chunk in bytes
        $upload_start = 0;
        $random_name = rand(1000,1000000)."-".$video_name;  
        $upload_name = $upload_dir.strtolower($random_name);    
        $upload_name = preg_replace('/\s+/', '-', $upload_name);    
    
    $handle = fopen($video_tmp_name, "rb");
        $fp = fopen($upload_name, 'w');
        while($upload_start < $orig_file_size) {
 
        $contents = fread($handle, $chunk_size);
        fwrite($fp, $contents);
 
        $upload_start += strlen($contents);
        fseek($handle, $upload_start);
    }
 
    fclose($handle);
    fclose($fp);
    unlink($_FILES['video']['tmp_name']);
 
    //echo "File uploaded successfully.";
     $response = array(
                "status" => "success",
                "error" => false,
                "message" => "File uploaded successfully",
                "url" => $server_url."/".$upload_name
              );

      



    }

}else{  
    $response = array(  
        "status" => "error",    
        "error" => true,    
        "message" => "No file was sent!"    
    );  
}   

echo json_encode($response);    
?>

注意 这将适用于小文件。 如果要发送大文件,则还必须从客户端以块的形式发送数据。 您可以使用 resumable.js 或 WebSockets

【讨论】:

  • 你能试着解释一下你的代码,而不仅仅是发布简单的代码示例
猜你喜欢
  • 1970-01-01
  • 2013-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多