Reputation: 1019
my question is pretty simple, I think. And it's more about math than coding. I receive 15 frames per second from web-cam. But I have to drop some of these. For example, if client is requesting 8 fps - I do drop each second frame and it's ok. But how should I drop if 12 fps or 6 fps are requested?
I think there's some common algo for values distribution. Thanks a lot!
Upvotes: 0
Views: 1572
Reputation:
Basically what you need is to drill a bit deeper into FPS concept.
A FPS of X means a frame is presented to display every 1/X sec and it remains visible on the display for 1/X sec. Typically the frames are updated on the display at every vertical sync of the display device.
Now with this information, frame rate conversion can be visualized as decoder decoding to temporary display at input FPS and a sampler displaying frames on final display at output FPS. The sampler samples frame from the temporary display on which decoder is updating frames. This logic should ensure synchronization between decoder and sampler such that sampler does not end up sampling partially updated frames.
This logic work for both decreasing or increasing FPS.
This can be implemented as single buffer with synchronized access. Now let decoder write to this buffer at input FPS and sampler pick frame from this buffer and display at output fps.
This will ensure screen updates are uniform and latest available frame is displayed at vertical sync.
Upvotes: 3
Reputation: 1019
What can you say about such solution:
I have 15 static const byte arrays with 0s and 1s. 1 - show frame, 0 - no. When I receive frame I increment counter cnt = [0..15] and look where does it point - zero or one. That's how I decide whether to show or drop frame.
I think this solution is easier and faster then implementing new thread.
Upvotes: 0
Reputation: 16486
Have a ring buffer large enough to hold 1 full second of video.
Into this buffer write each video frame. Update a variable pointing to that was written to.
In a seperate thread use a timer to delay a period of 1000 / desired_fps (84ms for 12fps) and pick the last frame written to and send that.
Upvotes: 1
Reputation: 64273
By dropping every 2nd frame for 8 fps, if you are having 15 fps, you are introducing an error.
This is a very simple algorithm, that would work in all cases :
#include <iostream>
double t = 0.0;
const double fps1 = 15.0;
const double fps2 = 12.0;
const double t1 = 1.0 / fps1;
const double t2 = 1.0 / fps2;
// true - drop the frame
// false - do NOT drop the frame
bool NextTick()
{
t += t1;
if ( t > t2 )
{
t -= t2;
return false;
}
return true;
}
int main()
{
for ( unsigned int i =0;i<20;++i)
{
if ( NextTick() )
{
std::cout<<"dropping the frame"<<std::endl;
}
else
{
std::cout<<"display the frame"<<std::endl;
}
}
}
Upvotes: 2
Reputation: 746
The way I've seen this done (e.g. in gstreamer) is to have two asynchronous loops, one receiving the frames from the camera and one sending the frames to the client. The latter loop only has the most recently captured frame from the camera available to it and so frames that aren't "picked up" by the client are automatically dropped as they're overwritten by the next incoming frame.
You need to do a little bit of synchronising to make sure you don't read half captured frames but other than that it's a straight forward solution and allows both sides of the interchange to operate at different speeds in either direction.
Upvotes: 3