Alan H.
Alan H.

Reputation: 16568

How can I measure the actual framerate of video using JavaScript?

Assume a video is playing in an HTML5 page using the <video> tag. How can I measure the actual framerate? I do not just want to read the framerate of the video file (e.g., but what the browser is able to manage in practice.

(I’m guessing it will be possible to hack something together involving requestAnimationFrame, but I vaguely worry that on some systems, video playback will be decoupled from the rest of the page, leading to an incorrect result; additionally I hope there might be a more direct metric.)

Upvotes: 1

Views: 825

Answers (1)

VC.One
VC.One

Reputation: 15881

You could try exploring VideoPlaybackQuality, maybe the metrics it gives out can be useful to you.
More specifically the dropped frames or total frames presented values.

Maybe involving those results along with other options like requestAnimationFrame?

I'm not sure what your exact end-goal of your project is. For example "How can I measure the actual framerate?" I personally can interpret that as either:

(1) Speed of the video decoder per frame (for given video type).
For example the decoding speed of each single frame @ 720p vs maybe 4K resolution.

(2) Number of frames dropped per second.
Where you minus the FPS number against the dropped frames to know how many were presented.

Here is a quick/basic example usage of VideoPlaybackQuality:

<!DOCTYPE html>
<html>
<body>

<video id="myvid" width="320" height="240" controls>
<source src="movie.mp4" type="video/mp4">
</video>

<br><br>
<text id="mytxt"> </text>

</body>

<script>

var mytxt = document.getElementById("mytxt");
var myvid = document.getElementById("myvid");

var fps = 30; //# use real FPS of input video
var vid_data; //# an Object for VideoPlaybackQuality 
var myInterval; //# to check Quaity statistics every second

var vidPaused = false;

myvid.addEventListener('play', onVidEvents);
myvid.addEventListener('pause', onVidEvents);
myvid.addEventListener('ended', onVidEvents);
 
function onVidEvents()
{
    if (event.type == "play")
    {
        vidPaused = false; 
        myInterval = setInterval(check_framesQuality, 1000); 
    }

    if (event.type == "seeked")
    { vid_data = myvid.getVideoPlaybackQuality(); update_text(); }

    if (event.type == "pause")
    { vidPaused = true; clearInterval(myInterval); }

    if (event.type == "ended")
    { clearInterval(myInterval); vidPaused = true;}
}

function check_framesQuality()
{
    if( vidPaused == false ) 
    { 
        vid_data = myvid.getVideoPlaybackQuality();
        update_text();
    }
}

function update_text()
{
    mytxt.innerText = "Total Decoded Frames : " + vid_data.totalVideoFrames 
    + "\n" + "Dropped Frames : " + vid_data.droppedVideoFrames
    + "\n" + "===================="
    + "\n" + "Video Time (secs) : " + Math.round( myvid.currentTime )
    + "\n" + "Expected Frames : " + Math.round( fps * myvid.currentTime  )
    
    //# received frames == ( expectedFrames - DroppedFrames )
    + "\n" + "Received Frames : " + ( Math.round( fps * myvid.currentTime) - vid_data.droppedVideoFrames)

}

</script>
</html>

Upvotes: 1

Related Questions