Как сохранить видео, записанное с помощью MediaRecorder, в файл в Asp. NET Core? - PullRequest
0 голосов
/ 09 марта 2020

Кстати, пожалуйста, не размещайте ссылки на другие подобные вопросы, потому что я их все видел, и они не помогают. Я работаю над этим в течение 7 часов.

Итак, я пытаюсь захватить видео с веб-камеры (с помощью MediaRecorder) и сохранить его в файл (в wwwroot или базе данных) через контроллер. У меня работает часть захвата видео, но я не уверен, как превратить записанные blob в файл или записываемый объект.

Вот как это работает. Я использую этот скрипт для записи. Это из демо-версии, и она работает отлично, за исключением того факта, что у него есть только возможность загрузки. Часть скрипта, ответственная за загрузку, закомментирована, и под ней я реализовал часть, чтобы попытаться загрузить это видео и сохранить его в папке.

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);
});

Это посылает капли рекордера (что, по-видимому, как эти видео сохраняются) на контроллере, который выглядит следующим образом:

[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");
}

Я могу получить доступ к fileName и массиву BLOB-объектов, но я понятия не имею, что делать, чтобы сохранить его в файл. Ваша помощь будет принята с благодарностью.

...