Наш Telegram бот: @htmlweb_bot

Создание видео отзывов на JavaScript и PHP

Нажмите кнопку «Старт», чтобы начать запись видео длительностью не более 5 секунд. Вы можете остановить видео, нажав кнопку «Стоп». Кнопка «Скачать» загрузит полученные данные в несжатом виде прямо из браузера. Ниже будет показан блок с видео, загруженное на сервер.


Старт

Предпросмотр

Стоп

Запись

Скачать






<style>
    video {
        margin-top: 2px;
        border: 1px solid black;
    }
    .button {
        cursor: pointer;
        display: block;
        width: 160px;
        border: 1px solid black;
        font-size: 16px;
        text-align: center;
        padding-top: 2px;
        padding-bottom: 4px;
        color: white;
        background-color: darkgreen;
        text-decoration: none;
    }
    .block {
        margin: 10px;
        float: left;
        width: 160px;
        padding: 0;
    }
    .bottom {
        clear: both;
        padding-top: 10px;
    }
</style>
    <div class="block">
        <div id="startButton" class="button">Старт</div>
        <h2>Предпросмотр</h2>
        <video id="preview" width="160" height="120" autoplay muted></video>
    </div>
    <div class="block">
        <div id="stopButton" class="button">Стоп</div>
        <h2>Запись</h2>
        <video id="recording" width="160" height="120" controls></video>
        <a id="downloadButton" class="button"> Скачать </a>
    </div>
    <div class="bottom">
        <pre id="log"></pre>
    </div>
    <br>
    <div id="rec"></div>
    <br class="clear">

    <script>
        let preview = document.getElementById("preview");
        let recording = document.getElementById("recording");
        let startButton = document.getElementById("startButton");
        let stopButton = document.getElementById("stopButton");
        let downloadButton = document.getElementById("downloadButton");
        let logElement = document.getElementById("log");
        let recordingTimeMS = 5000; // максимальный размер видео в миллисекундах
        let recorder;

        function _log(msg) { logElement.innerHTML += msg + "\n"; }

        function wait(delayInMS) {
            return new Promise((resolve) => setTimeout(resolve, delayInMS));
        }
        function startRecording(stream, lengthInMS) {
            recorder = new MediaRecorder(stream);
            let data = [];
            recorder.ondataavailable = (event) => data.push(event.data);
            recorder.start();
            _log(recorder.state + " в пределах " + lengthInMS / 1000 + " секунд...");

            let stopped = new Promise((resolve, reject) => {
                recorder.onstop = resolve;
                recorder.onerror = (event) => reject(event.name);
            });

            let recorded = wait(lengthInMS).then( () => recorder.state === "recording" && recorder.stop() );

            return Promise.all([stopped, recorded]).then(() => data);
        }
        function stop(stream) {
            stream.getTracks().forEach((track) => track.stop());
        }

        startButton.addEventListener( "click", ()=> {
                navigator.mediaDevices
                    .getUserMedia({
                        video: true,
                        audio: true,
                    })
                    .then((stream) => {
                        preview.srcObject = stream;
                        downloadButton.href = stream;
                        preview.captureStream = preview.captureStream || preview.mozCaptureStream;
                        return new Promise((resolve) => (preview.onplaying = resolve));
                    })
                    .then(() => startRecording(preview.captureStream(), recordingTimeMS))
                    .then((recordedChunks) => {
                        let recordedBlob = new Blob(recordedChunks, { type: "video/webm" });
                        _log("Успешно записано " + Math.round(recordedBlob.size/1024) + "Kb в формате " + recordedBlob.type);
                        //stop(preview.srcObject);
                        // это блок для работы без сервера
                        recording.src = URL.createObjectURL(recordedBlob);  // todo URL.revokeObjectURL(recording.src);
                        downloadButton.href = recording.src;
                        downloadButton.download = "RecordedVideo.webm";

                        // это блок отправки видео на сервер
                        /* let fd = new FormData();
                         fd.append('voice', recordedBlob);
                         sendVoice(fd);*/
                    })
                    .catch(_log);
            },
            false,
        );
        stopButton.addEventListener( "click", ()=> { stop(preview.srcObject); }, false );

        async function sendVoice(form) {
            //fetch('video_review.php',{method: 'POST', body: data}).then(function (e) {e.json().then(function (e) { _log('Записал на сервер под именем: ', e.data);}
            let promise = await fetch('video_review.php', {
                method: 'POST',
                body: form});
            if (promise.ok) {
                let response =  await promise.json();
                _log('Записал на сервер под именем: '+response.data);
                if(response.result==='ERROR') _log('Ошибка: '+response.result.data);
                else document.getElementById('rec').insertAdjacentHTML('afterend', '<video controls="controls" style="width:200px;margin:10px;float:left">'+
                    '<source src="https://htmlweb.ru/log/tmp/'+response.data+'" type="video/webm">'+
                    '</video><br><a href="?del='+response.data+'" onclick="return confirm(this.title+\'?\')" title="Удалить"><svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#1f1f1f"><path d="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z" fill="#e34234"/></svg></a>');
            }else{

            }
        }
    </script>
Получение и удаление файла на сервере
if(!empty($_FILES['voice'])) {
    $typeFile = explode('/', $_FILES['voice']['type']);
    if(empty($typeFile[1])||!in_array($typeFile[1], ['webm','mp4']))die(json_encode(['result' => 'ERROR', 'data' => 'Неверный формат файла '.$_FILES['voice']['type']]));
    $fil=date('ymdHi') . '.' . $typeFile[1];
    $src = '/log/tmp/' . $fil;
    $uploadFile = $_SERVER['DOCUMENT_ROOT'] . $src;
    if (move_uploaded_file($_FILES['voice']['tmp_name'], $uploadFile)) {
        $response = ['result' => 'OK', 'data' => $fil];
        if(!isset($_SESSION[Image::$fieldSession]))$_SESSION[Image::$fieldSession]=[];
        $_SESSION[Image::$fieldSession][]=$fil;
    } else {
        $response = ['result' => 'ERROR', 'data' => 'Не смог сохранить' . $_FILES['voice']['tmp_name'] . ' в ' . $uploadFile];
    }
    header('Content-Type: application/json');
    die(json_encode($response));
}elseif (!empty($_REQUEST['del']) && is_file($fil=$_SERVER['DOCUMENT_ROOT'] . '/log/tmp/'.$_REQUEST['del'])){
    unlink($fil);
}



  • Исходник https://developer.mozilla.org/ru/docs/Web/API/MediaStream_Recording_API/Recording_a_media_element
  • Описание MediaRecorder https://developer.mozilla.org/ru/docs/Web/API/MediaRecorder
  • Как сделать превью видео с помощью canvas https://usefulangle.com/post/46/javascript-get-video-thumbnail-image-jpeg-png

.