Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Smooth FPS #11

Open
matijagaspar opened this issue Dec 2, 2019 · 2 comments
Open

Smooth FPS #11

matijagaspar opened this issue Dec 2, 2019 · 2 comments

Comments

@matijagaspar
Copy link
Owner

matijagaspar commented Dec 2, 2019

@waclaw66 Suggested a enhancement for smooth rendering of frames following the predefined "frames per second" configuration.

Rough example bellow. It works quite fluently. Precise rendering could be optional and fps could be passed as a parameter together with init message payload.

var wsavc = new WSAvcPlayer.default({useWorker: false});
document.getElementById('webcam_box').appendChild(wsavc.AvcPlayer.canvas);
wsavc.AvcPlayer.render = false;
var frames = [];
var fps = 20;
var renderStarted = false;
var nexttime = null;

function render(now) {
	if (!nexttime) {
		nexttime = now;
	}
	if (now >= nexttime)
	{
		frame = frames.shift();
		if (frame) {
			wsavc.AvcPlayer.renderFrame(frame);
			nexttime += 1000 / fps;
		}
	}
	if (renderStarted) {
		requestAnimationFrame(render);
	}
}

wsavc.AvcPlayer.onPictureDecoded = function (buffer, width, height, infos) {
	frames.push({
		canvasObj: this.canvasObj,
		data: Uint8Array.from(buffer),
		width: width,
		height: height,
	});
	if (!renderStarted) {
		renderStarted = true;
		nexttime = null;
		requestAnimationFrame(render);
	}
}

wsavc.connect("wss://example.com");

Originally posted by @waclaw66 in #9 (comment)

This could be added to the player provided it is optional. The playback will be smoother but it can induce slight delay.

@waclaw66
Copy link

waclaw66 commented Dec 3, 2019

I have tested it on some less stable networks and added a little enhancement with automatic buffer. Playback could be delayed up to maxbuffertime, but the smoothness worth for it in some scenarios.

var frametime = 1000 / fps;
var buffertime = 0;
var maxbuffertime = 1000;

function render(now) {
    if (!nexttime) {
        nexttime = now + buffertime;
    }
    if (now >= nexttime)
    {
        frame = frames.shift();
        if (frame) {
            wsavc.AvcPlayer.renderFrame(frame);
            nexttime += frametime;
        } else {
            if (buffertime < maxbuffertime) {
                buffertime += frametime;
                nexttime += frametime;
            }
        }
    }
    if (renderStarted) {
        requestAnimationFrame(render);
    }
}

@matijagaspar
Copy link
Owner Author

matijagaspar commented Dec 3, 2019

Great work, however after thinking some more, about it. I think it should be modified a bit, so instead of having a fixed framerate defined on the client, server would collect a timestamp for each frame and add it to the packet. Than use that timestamp for accurate timing. There are 2 reasons for this approach:

  • The timing is embeded in the stream, so it will be simpler to handle different frame rates on the client
  • It will be a good starting point for implementing audio-video sync like is done on WebRTC's Lip sync

Enabling/disabling the feature could be done on ws connect, since some sort of handshake will be inevitable anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants