How can I control the playback rate of a video player in the Vision System toolbox in Matlab? Specifically, I want to slow video down. For instance, here is the simple example of how to load and display a movie from the documentation:
videoFReader = vision.VideoFileReader('viplanedeparture.mp4');
videoPlayer = vision.VideoPlayer;
while ~isDone(videoFReader)
videoFrame = step(videoFReader);
step(videoPlayer, videoFrame);
end
release(videoPlayer);
release(videoFReader);
I searched the User's Guide for how to change the frame rate in a simple way in such examples, but found nothing.
You're displaying images as fast as they can be retrieved and displayed with your current code. If you want a particular framerate I would use a timer
that calls your update methods based upon the frame rate that you want. Here is a brief example that should be pretty robust.
videoFReader = vision.VideoFileReader('viplanedeparture.mp4');
videoPlayer = vision.VideoPlayer;
framerate = 10; % in frames/second
t = timer('ExecutionMode', 'fixedRate', ...
'Period', 1 / framerate, ...
'TimerFcn', @(tmr,evnt)timerfcn(tmr, videoFReader, videoPlayer), ...
'ErrorFcn', @(tmr,evnt)cleanup(tmr, videoFReader, videoPlayer));
show(videoPlayer);
start(t)
function timerfcn(tmr, reader, player)
% While we have more to read, read and display it.
if ~isDone(reader) && isOpen(player)
step(player, step(reader));
else
cleanup(tmr, reader, player)
end
end
function cleanup(tmr, reader, player)
% Callback to ensure proper cleanup of objects
if isvalid(tmr) && strcmpi(tmr.Running, 'on')
stop(tmr);
delete(tmr)
end
release(player);
release(reader);
end
Thanks to horchler's comments for improving the robustness of the solution.
The alternative is to place a pause(1/framerate)
statement at the bottom of your while
loop, but that won't take into account any time required to actually do the loading/displaying so the frame rate isn't going to be guaranteed to be very consistent.
The comments made below by @neuronet got me thinking about why this may not be a feature of either VideoFileReader
or VideoPlayer
.
VideoFileReader
As @neuronet states, if the frame rate is specified within the video file that is being read using VideoFileReader
, couldn't that be used automatically?
The answer is, yes if could be used but there is good reason to not use it. Since new frames are fetched with VideoFileReader.step()
it woud have to be implemented as some sort of a rate limiter on step()
.
In this particular case, the video is being used for display purposes; however, that is not always the case. A lot of times, you may want to load a video frame by frame to do some analysis (tracking an object, etc.). Now imagine for a second that the frame rate of my video file is set to 1 frame per second (fps). And let's say that I want to load this video into MATLAB, track people in the frame, and report back to the user how many people passed through the field of view during the course of the video.
If VideoFileReader.step()
was written so that it returned images only at the frame rate specified in the file, this means that the fastest I could do my processing would be at one frame per second. If this were the case, the end user would just watch the video themselves and we would be out of a job!
Another important consideration is that if you actually want to process the video frame before displaying it to the VideoPlayer object, you need to somehow account for that processing time (which obviously the VideoFileReader
has no clue about).
VideoPlayer
The other option would be to have a FrameRate
property for the VideoPlayer
object itself.
While this too could be done, the way that it is currently implemented it is not possible. Currently to display a new frame, you have to explicitly call the VideoPlayer.step()
method. It runs into the same situation as the VideoFileReader
. It would have to be implemented as a rate limiter on the step()
method.
One possible way that The Mathworks could make this work would be to have an alternative to using step()
to update the image. For example, a NextImageFcn
callback or something. Then VideoPlayer
could internally setup a timer based on a specified frame rate and execute the callback when necessary (similar to our timer callback).
The other alternative could be to have VideoPlayer
accept a VideoFileReader
object as an input. It could then use this object to get information about the video (frame rate, etc.) and display the images at the appropriate speed.
The main issue here though, is that this serves a very small group of users. This is because the primary goal of MATLAB (and the computer vision toolbox) isn't to be a video playback system, but rather it is intended to do analysis on videos and the VideoPlayer
object is intended to streamline the display of the results.
Maybe this functionality will be implemented in the future, but for now those are my thoughts on why it doesn't exist.