Playing Recordings

Goal

This guide describes building a web application using standard Cameramanager API and HTML5 web technology. The web application is able to play recordings in the browser.

This guide is explained how to build a web application with the following features:

  • Playing recordings
    • Play/pause
    • Rewind
    • Fast forward (Speedplay X times faster)
    • Time scrolling (seeking in video timeline)
  • Recordings Multiview

Assumptions

This guide assumes that the reader has a basic knowledge of the following technologies:

  • HTML5 browser technology and knowledge of the HTML5 video element
  • Basic CSS knowledge to change the styling of a page
  • Basic Javascript knowledge
  • The reader is familiar with getting data from a REST API

Supported browsers

Playing recordings using the MP4 API, we support the following browsers:

  • Microsoft Edge 78+
  • Mozilla Firefox 30+
  • Google Chrome 60+
  • Apple Safari 7+
    The camera footage settings should be set to h.264 encoding, cameras recording to MJPEG and MPEG4 are not supported. The audio is not supported in Firefox.

Retrieving recordings

1. Login using the REST API

http://rest.cameramanager.com/oauth/token?grant_type=password&scope=write&username=<username>&password=<password>
Headers:
Accept application/json
Authorization <TOKEN>
 
Response:
{
    "access_token": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:10003",
    "token_type": "bearer",
    "refresh_token": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:10003",
    "expires_in": 43199,
    "scope": "write"
}

2. Get cameras

https://rest.cameramanager.com/rest/v2.0/cameras/
Headers:
Authorization Bearer aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:10003
Content-Type application/json
  
Response:
[
    {
        "cameraId": 529111,
        "name": "demo cam",
        "deviceTypeId": 446,
        "zoneId": 91346,
        "accountId": 92578
    },
    {
        "cameraId": 531111,
        "name": "Panasonic WV-SPW312L (ONVIF)",
        "deviceTypeId": 176,
        "zoneId": 91346,
        "accountId": 92578
    }
]

3. Get recordings

https://rest.cameramanager.com/rest/v2.0/cameras/529111/recordings?includeUrlType=MP4HTTPS&sortByRecordingIdOrder=DESC
Headers:
Authorization Bearer aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:10003
Content-Type application/json
  
Response:
[
    {
        "cameraId": 529111,
        "recordingId": 336491,
        "startTime": "2017-11-19T16:39:35.259+0000",
        "endTime": "2017-11-20T11:22:33.503+0000",
        "urls": {
            "mp4Https": "https://ca012.cameramanager.com:1443/cameras/529119/recordings/336491.mp4"
        }
    },
    {
        "cameraId": 529111,
        "recordingId": 337119,
        "startTime": "2017-11-20T11:22:36.159+0000",
        "endTime": "2017-11-20T12:10:15.464+0000",
        "urls": {
            "mp4Https": "https://ca012.cameramanager.com:1443/cameras/529119/recordings/337119.mp4"
        }
    }
]

Playing recordings

1. Embed MP4 file in browser

Copy the mp4Https URL and paste it into the SRC tag. To retrieve the MP4 recording one must supply an access token with the mandatory parameter 'access_token'. Besides the token one can optionally add a 'from' and 'till' parameter to limit the size (in time) of the recording. The 'from' and 'till' parameters need to be supplied in ISO 8601 format. Both 'from' and 'till' parameters need to be within the start- and endtime of the recording otherwise an error will be returned.

Also add a canvas as shown on the code below, to allow you to create and save snapshots of the video footage. The styling used is to prevent the canvas from being unnecessarily displayed.

<!DOCTYPE html>
<html>
    <head>
    </head> 
    <body>
        <video id="video" src="https://www.cameramanager.com:1443/cameras/529119/recordings/336491.mp4?access_token=aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:10003" controls crossorigin="anonymous" type="video/mp4"></video>
        <canvas id="snapshotCanvas" style="position:absolute;display:none;"></canvas>
    </body>
</html>

In the browser, you will see the standard HTML5 video player. Due to the "controls" property in the element, it contains a play/pause button, time information, a slider to move forward/backward and the user can make the video fullscreen.

The HTML5 video element can be further tuned via the following attributes:

Property name Description
autoplay With the autoplay attribute, the video will start playing automatically
controls Defines whether the standard video controls are visible
width Defines the width of the video
height Defines the height of the video

2. Use custom buttons

The standard buttons are limited in terms of styling. The HTML5 video element allows you to create custom elements using Javascript and CSS. You can use standard HTML buttons for player control and style them the way you want.

Add the HTML5 buttons to the document. You can style them with CSS and if required replace them with DIV's.

<button type="button" id="play-pause">Play</button>
<button type="button" id="full-screen">Full-Screen</button>
<button type="button" id="speed-play">2x speed play</button>
<button type="button" id="rewind">Rewind</button>
<button type="button" id="snapshot">Snapshot</button>
<input type="range" id="seek-bar" value="0">

Add the following javascript to make the HTML5 buttons work:

window.onload = function() {
    var video = document.getElementById("video");
 
    // Canvas for snapshot
    var canvas = document.getElementById("snapshotCanvas");
    var context = canvas.getContext("2d");
 
    // Buttons
    var playButton = document.getElementById("play-pause");
    var fullScreenButton = document.getElementById("full-screen");
    var seekBar = document.getElementById("seek-bar");
    var rewind = document.getElementById("rewind");
    var snapshotButton = document.getElementById("snapshot");
    var speedPlay = document.getElementById("speed-play");
     
    // PLAY/PAUSE BUTTON
    playButton.addEventListener("click", function() {
      if (video.paused == true) {
        video.play(); // Play the video             
        playButton.innerHTML = "Pause"; // Update the button text to 'Pause'
      } else {
        video.pause(); // Pause the video
        playButton.innerHTML = "Play"; // Update the button text to 'Play'
      }
    });
    // SPEED PLAY
    speedPlay.addEventListener("click", function() {
      if (video.playbackRate == 1) {
        video.playbackRate = 4; // Normal speed         
        speedPlay.innerHTML = "Normal"; // Update the button text to 'Normal'
      } else {
        video.playbackRate = 1; // Speed play
        speedPlay.innerHTML = "Speed play"; // Update the button text to 'Speedplay'
      }
    }); 
 
    // VIDEO REWIND
    rewind.addEventListener("click", function() {
        video.currentTime = 0; // Go to the beginning of the video      
    });
     
    // FULL-SCREEN BUTTON
    fullScreenButton.addEventListener("click", function() {
        if (video.requestFullscreen) {
            video.requestFullscreen();
        } else if (video.mozRequestFullScreen) {
            video.mozRequestFullScreen(); // Firefox
        } else if (video.webkitRequestFullscreen) {
            video.webkitRequestFullscreen(); // Chrome and Safari
        }
    });
 
    // SNAPSHOT BUTTON
    snapshotButton.addEventListener("click", function() {
        var ratio = video.videoWidth/video.videoHeight;
        var w = video.videoWidth-100;
        var h = parseInt(w/ratio,10);
        canvas.width = w;
        canvas.height = h;
 
        context.fillRect(0,0,w,h);
        context.drawImage(video,0,0,w,h);
 
        var dataURI = canvas.toDataURL("image/jpeg");
         
        // Function to download our snapshot
        function download(data, filename, type) {
            var file = new Blob([data], {type: type});
            if (window.navigator.msSaveOrOpenBlob)
                window.navigator.msSaveOrOpenBlob(file, filename);
            else {
                var a = document.createElement("a");
                var url = URL.createObjectURL(file);
                a.href = url;
                a.download = filename;
                document.body.appendChild(a);
                a.click();
                setTimeout(function() {
                    document.body.removeChild(a);
                    window.URL.revokeObjectURL(url);  
                }, 0); 
            }
        }
 
        download(dataURI, "Snapshot.jpg", "image/jpeg")
    });
     
    // VIDEO SEEK BAR
    seekBar.addEventListener("change", function() {
        var time = video.duration * (seekBar.value / 100); // Calculate the new time
        video.currentTime = time; // Update the video time
    });
     
    // Update the seek bar as the video plays
    video.addEventListener("timeupdate", function() {
        var value = (100 / video.duration) * video.currentTime; // Calculate the slider value
        seekBar.value = value; // Update the slider value
    });
     
    // Pause the video when the slider handle is being dragged
    seekBar.addEventListener("mousedown", function() {
        video.pause();
    });
    // Play the video when the slider handle is dropped
    seekBar.addEventListener("mouseup", function() {
        video.play();
    });
}

You can remove the standard HTML5 video controls by removing the "controls" attribute of the video element. Now when showing the page in the browser you will see the following:

Recordings multi-view

You can create a multi-view option by copying and loading the video tag multiple times. A player will appear for every video tag in the document.

<video src="<link to the mp4 file>" controls height="100px" type="video/mp4"></video>
<video src="<link to the mp4 file>" controls height="100px" type="video/mp4"></video>
 
<br />
<video src="<link to the mp4 file>" controls height="100px" type="video/mp4"></video>
<video src="<link to the mp4 file>" controls height="100px" type="video/mp4"></video>