Search code examples
javascripthtmlhtml5-videomediarecorder

Is it possible to use the MediaRecorder API with html5 video?


I would like to record the video tag so that I can stream the blob data to a websocket server, however, when I attempt to start the mediaRecorder I get the following error:

The MediaRecorder failed to start because there are no audio or video tracks available.

Is it possible to add the audio/video tracks from the html5 video tag to the media stream?

<script>
var video = document.getElementById('video');
var mediaStream = video.captureStream(30);
var mediaRecorder = new MediaRecorder(
            mediaStream,
            {
                mimeType: 'video/webm;codecs=h264',
                videoBitsPerSecond: 3000000
            }
        );

fileElem.onchange = function () {
            var file = fileElem.files[0],
                canplay = !!video.canPlayType(file.type).replace("no", ""),
                isaudio = file.type.indexOf("audio/") === 0 && file.type !== "audio/mpegurl";
            video.src = URL.createObjectURL(file);
            video.play();
            mediaRecorder.start(1000); // Start recording, and dump data every second
        };
</script>

<p id="choice" class="info"><input type="file" id="file"> File type: <span id="ftype"></span></p>
<video width="640" height="360" id="video" src="" controls="false"></video>

Solution

  • Is it possible to use the MediaRecorder API with html5 video?

    Yes, however you need to initialize MediaRecorder after the HTMLVideoElement.readyState has metadata.

    Here is a sample, but it only works if the video source is from the same origin (since captureStream cannot capture from element with cross-origin data)

    Note: In this sample, I use onloadedmetadata to initialize MediaRecorder after the video got metadata.

    var mainVideo = document.getElementById("mainVideo"),
      displayVideo = document.getElementById("displayVideo"),
      videoData = [],
      mediaRecorder;
    
    var btnStart = document.getElementById("btnStart"),
      btnStop = document.getElementById("btnStop"),
      btnResult = document.getElementById("btnResult");
    
    var initMediaRecorder = function() {
      // Record with 25 fps
      mediaRecorder = new MediaRecorder(mainVideo.captureStream(25));
    
      mediaRecorder.ondataavailable = function(e) {
        videoData.push(e.data);
      };
    }
    
    function startCapture() {
      videoData = [];
      mediaRecorder.start();
    
      // Buttons 'disabled' state
      btnStart.setAttribute('disabled', 'disabled');
      btnStop.removeAttribute('disabled');
      btnResult.setAttribute('disabled', 'disabled');
    };
    
    function endCapture() {
      mediaRecorder.stop();
    
      // Buttons 'disabled' state
      btnStart.removeAttribute('disabled');
      btnStop.setAttribute('disabled', 'disabled');
      btnResult.removeAttribute('disabled');
    };
    
    function showCapture() {
      return new Promise(resolve => {
        setTimeout(() => {
          // Wrapping this in setTimeout, so its processed in the next RAF
          var blob = new Blob(videoData, {
              'type': 'video/mp4'
            }),
            videoUrl = window.URL.createObjectURL(blob);
    
          displayVideo.src = videoUrl;
          resolve();
        }, 0);
      });
    };
    video {
      max-width: 300px;
      max-height: 300px;
      display: block;
      margin: 10px 0;
    }
    <video id="mainVideo" playsinline="" webkit-playsinline="1" controls="1" onloadedmetadata="initMediaRecorder()">
        <source src="sampleVideo.mp4" type="video/mp4">
      </video>
    
    <button id="btnStart" onclick="startCapture()"> Start </button>
    <button id="btnStop" disabled='disabled' onclick="endCapture()"> Stop </button>
    <button id="btnResult" disabled='disabled' onclick="showCapture()"> Show Result </button>
    
    <video id="displayVideo" playsinline="" webkit-playsinline="1" controls="1"></video>