summaryrefslogtreecommitdiffstats
path: root/client_examples
diff options
context:
space:
mode:
authorSlávek Banko <slavek.banko@axis.cz>2019-02-06 16:56:55 +0100
committerSlávek Banko <slavek.banko@axis.cz>2019-02-06 16:56:55 +0100
commitf3f392caec43b4095bc1d84b315ed7972c13c144 (patch)
tree5c4ba8b5d38f1ae33de71507c5634a15a0b35bfe /client_examples
parent8c081c8888bccbf5adfe0fc4ec518e2cbfba9871 (diff)
parent0a70095271d845d16a3ed17354841b01f33963ad (diff)
downloadlibtdevnc-f3f392caec43b4095bc1d84b315ed7972c13c144.tar.gz
libtdevnc-f3f392caec43b4095bc1d84b315ed7972c13c144.zip
Merge tag 'LibVNCServer-0.9.12'
Signed-off-by: Slávek Banko <slavek.banko@axis.cz>
Diffstat (limited to 'client_examples')
-rw-r--r--client_examples/Makefile.am38
-rw-r--r--client_examples/SDLvncviewer.c431
-rw-r--r--client_examples/backchannel.c4
-rw-r--r--client_examples/ppmtest.c15
-rw-r--r--client_examples/scrap.c558
-rw-r--r--client_examples/scrap.h18
-rw-r--r--client_examples/vnc2mpg.c688
7 files changed, 582 insertions, 1170 deletions
diff --git a/client_examples/Makefile.am b/client_examples/Makefile.am
deleted file mode 100644
index 9cb2c32..0000000
--- a/client_examples/Makefile.am
+++ /dev/null
@@ -1,38 +0,0 @@
-AM_CPPFLAGS = -I$(top_srcdir)
-LDADD = ../libvncclient/libvncclient.la @WSOCKLIB@
-
-if WITH_FFMPEG
-FFMPEG_HOME=@with_ffmpeg@
-
-if HAVE_MP3LAME
-MP3LAME_LIB=-lmp3lame
-endif
-
-vnc2mpg_CFLAGS=-I$(FFMPEG_HOME)/libavformat -I$(FFMPEG_HOME)/libavcodec -I$(FFMPEG_HOME)/libavutil
-vnc2mpg_LDADD=$(LDADD) $(FFMPEG_HOME)/libavformat/libavformat.a $(FFMPEG_HOME)/libavcodec/libavcodec.a $(MP3LAME_LIB) -lm
-
-FFMPEG_CLIENT=vnc2mpg
-endif
-
-if HAVE_LIBSDL
-SDLVIEWER=SDLvncviewer
-
-SDLvncviewer_CFLAGS=$(SDL_CFLAGS)
-SDLvncviewer_SOURCES=SDLvncviewer.c scrap.c scrap.h
-
-# thanks to autoconf, this looks ugly
-SDLvncviewer_LDADD=$(LDADD) $(SDL_LIBS)
-endif
-
-if HAVE_LIBGTK
-GTKVIEWER=gtkvncviewer
-gtkvncviewer_SOURCES=gtkvncviewer.c
-gtkvncviewer_CFLAGS=$(GTK_CFLAGS)
-gtkvncviewer_LDADD=$(LDADD) $(GTK_LIBS)
-endif
-
-
-noinst_PROGRAMS=ppmtest $(SDLVIEWER) $(GTKVIEWER) $(FFMPEG_CLIENT) backchannel
-
-
-
diff --git a/client_examples/SDLvncviewer.c b/client_examples/SDLvncviewer.c
index 8fe6f57..d17b74e 100644
--- a/client_examples/SDLvncviewer.c
+++ b/client_examples/SDLvncviewer.c
@@ -5,7 +5,6 @@
#include <SDL.h>
#include <signal.h>
#include <rfb/rfbclient.h>
-#include "scrap.h"
struct { int sdl; int rfb; } buttonMapping[]={
{1, rfbButton1Mask},
@@ -16,14 +15,22 @@ struct { int sdl; int rfb; } buttonMapping[]={
{0,0}
};
+struct { char mask; int bits_stored; } utf8Mapping[]= {
+ {0b00111111, 6},
+ {0b01111111, 7},
+ {0b00011111, 5},
+ {0b00001111, 4},
+ {0b00000111, 3},
+ {0,0}
+};
+
static int enableResizable = 1, viewOnly, listenLoop, buttonMask;
-#ifdef SDL_ASYNCBLIT
- int sdlFlags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
-#else
- int sdlFlags = SDL_HWSURFACE | SDL_HWACCEL;
-#endif
-static int realWidth, realHeight, bytesPerPixel, rowStride;
-static char *sdlPixels;
+int sdlFlags;
+SDL_Texture *sdlTexture;
+SDL_Renderer *sdlRenderer;
+SDL_Window *sdlWindow;
+/* client's pointer position */
+int x,y;
static int rightAltKeyDown, leftAltKeyDown;
@@ -32,53 +39,72 @@ static rfbBool resize(rfbClient* client) {
depth=client->format.bitsPerPixel;
if (enableResizable)
- sdlFlags |= SDL_RESIZABLE;
+ sdlFlags |= SDL_WINDOW_RESIZABLE;
client->updateRect.x = client->updateRect.y = 0;
client->updateRect.w = width; client->updateRect.h = height;
- rfbBool okay=SDL_VideoModeOK(width,height,depth,sdlFlags);
- if(!okay)
- for(depth=24;!okay && depth>4;depth/=2)
- okay=SDL_VideoModeOK(width,height,depth,sdlFlags);
- if(okay) {
- SDL_Surface* sdl=SDL_SetVideoMode(width,height,depth,sdlFlags);
- rfbClientSetClientData(client, SDL_Init, sdl);
- client->width = sdl->pitch / (depth / 8);
- if (sdlPixels) {
- free(client->frameBuffer);
- sdlPixels = NULL;
- }
- client->frameBuffer=sdl->pixels;
-
- client->format.bitsPerPixel=depth;
- client->format.redShift=sdl->format->Rshift;
- client->format.greenShift=sdl->format->Gshift;
- client->format.blueShift=sdl->format->Bshift;
- client->format.redMax=sdl->format->Rmask>>client->format.redShift;
- client->format.greenMax=sdl->format->Gmask>>client->format.greenShift;
- client->format.blueMax=sdl->format->Bmask>>client->format.blueShift;
- SetFormatAndEncodings(client);
+ /* (re)create the surface used as the client's framebuffer */
+ SDL_FreeSurface(rfbClientGetClientData(client, SDL_Init));
+ SDL_Surface* sdl=SDL_CreateRGBSurface(0,
+ width,
+ height,
+ depth,
+ 0,0,0,0);
+ if(!sdl)
+ rfbClientErr("resize: error creating surface: %s\n", SDL_GetError());
+
+ rfbClientSetClientData(client, SDL_Init, sdl);
+ client->width = sdl->pitch / (depth / 8);
+ client->frameBuffer=sdl->pixels;
+
+ client->format.bitsPerPixel=depth;
+ client->format.redShift=sdl->format->Rshift;
+ client->format.greenShift=sdl->format->Gshift;
+ client->format.blueShift=sdl->format->Bshift;
+ client->format.redMax=sdl->format->Rmask>>client->format.redShift;
+ client->format.greenMax=sdl->format->Gmask>>client->format.greenShift;
+ client->format.blueMax=sdl->format->Bmask>>client->format.blueShift;
+ SetFormatAndEncodings(client);
+
+ /* create or resize the window */
+ if(!sdlWindow) {
+ sdlWindow = SDL_CreateWindow(client->desktopName,
+ SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED,
+ width,
+ height,
+ sdlFlags);
+ if(!sdlWindow)
+ rfbClientErr("resize: error creating window: %s\n", SDL_GetError());
} else {
- SDL_Surface* sdl=rfbClientGetClientData(client, SDL_Init);
- rfbClientLog("Could not set resolution %dx%d!\n",
- client->width,client->height);
- if(sdl) {
- client->width=sdl->pitch / (depth / 8);
- client->height=sdl->h;
- } else {
- client->width=0;
- client->height=0;
- }
- return FALSE;
+ SDL_SetWindowSize(sdlWindow, width, height);
+ }
+
+ /* create the renderer if it does not already exist */
+ if(!sdlRenderer) {
+ sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0);
+ if(!sdlRenderer)
+ rfbClientErr("resize: error creating renderer: %s\n", SDL_GetError());
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); /* make the scaled rendering look smoother. */
}
- SDL_WM_SetCaption(client->desktopName, "SDL");
+ SDL_RenderSetLogicalSize(sdlRenderer, width, height); /* this is a departure from the SDL1.2-based version, but more in the sense of a VNC viewer in keeeping aspect ratio */
+
+ /* (re)create the texture that sits in between the surface->pixels and the renderer */
+ if(sdlTexture)
+ SDL_DestroyTexture(sdlTexture);
+ sdlTexture = SDL_CreateTexture(sdlRenderer,
+ SDL_PIXELFORMAT_ARGB8888,
+ SDL_TEXTUREACCESS_STREAMING,
+ width, height);
+ if(!sdlTexture)
+ rfbClientErr("resize: error creating texture: %s\n", SDL_GetError());
return TRUE;
}
static rfbKeySym SDL_key2rfbKeySym(SDL_KeyboardEvent* e) {
rfbKeySym k = 0;
- SDLKey sym = e->keysym.sym;
+ SDL_Keycode sym = e->keysym.sym;
switch (sym) {
case SDLK_BACKSPACE: k = XK_BackSpace; break;
@@ -87,18 +113,17 @@ static rfbKeySym SDL_key2rfbKeySym(SDL_KeyboardEvent* e) {
case SDLK_RETURN: k = XK_Return; break;
case SDLK_PAUSE: k = XK_Pause; break;
case SDLK_ESCAPE: k = XK_Escape; break;
- case SDLK_SPACE: k = XK_space; break;
case SDLK_DELETE: k = XK_Delete; break;
- case SDLK_KP0: k = XK_KP_0; break;
- case SDLK_KP1: k = XK_KP_1; break;
- case SDLK_KP2: k = XK_KP_2; break;
- case SDLK_KP3: k = XK_KP_3; break;
- case SDLK_KP4: k = XK_KP_4; break;
- case SDLK_KP5: k = XK_KP_5; break;
- case SDLK_KP6: k = XK_KP_6; break;
- case SDLK_KP7: k = XK_KP_7; break;
- case SDLK_KP8: k = XK_KP_8; break;
- case SDLK_KP9: k = XK_KP_9; break;
+ case SDLK_KP_0: k = XK_KP_0; break;
+ case SDLK_KP_1: k = XK_KP_1; break;
+ case SDLK_KP_2: k = XK_KP_2; break;
+ case SDLK_KP_3: k = XK_KP_3; break;
+ case SDLK_KP_4: k = XK_KP_4; break;
+ case SDLK_KP_5: k = XK_KP_5; break;
+ case SDLK_KP_6: k = XK_KP_6; break;
+ case SDLK_KP_7: k = XK_KP_7; break;
+ case SDLK_KP_8: k = XK_KP_8; break;
+ case SDLK_KP_9: k = XK_KP_9; break;
case SDLK_KP_PERIOD: k = XK_KP_Decimal; break;
case SDLK_KP_DIVIDE: k = XK_KP_Divide; break;
case SDLK_KP_MULTIPLY: k = XK_KP_Multiply; break;
@@ -130,165 +155,58 @@ static rfbKeySym SDL_key2rfbKeySym(SDL_KeyboardEvent* e) {
case SDLK_F13: k = XK_F13; break;
case SDLK_F14: k = XK_F14; break;
case SDLK_F15: k = XK_F15; break;
- case SDLK_NUMLOCK: k = XK_Num_Lock; break;
+ case SDLK_NUMLOCKCLEAR: k = XK_Num_Lock; break;
case SDLK_CAPSLOCK: k = XK_Caps_Lock; break;
- case SDLK_SCROLLOCK: k = XK_Scroll_Lock; break;
+ case SDLK_SCROLLLOCK: k = XK_Scroll_Lock; break;
case SDLK_RSHIFT: k = XK_Shift_R; break;
case SDLK_LSHIFT: k = XK_Shift_L; break;
case SDLK_RCTRL: k = XK_Control_R; break;
case SDLK_LCTRL: k = XK_Control_L; break;
case SDLK_RALT: k = XK_Alt_R; break;
case SDLK_LALT: k = XK_Alt_L; break;
- case SDLK_RMETA: k = XK_Meta_R; break;
- case SDLK_LMETA: k = XK_Meta_L; break;
- case SDLK_LSUPER: k = XK_Super_L; break;
- case SDLK_RSUPER: k = XK_Super_R; break;
+ case SDLK_LGUI: k = XK_Super_L; break;
+ case SDLK_RGUI: k = XK_Super_R; break;
#if 0
case SDLK_COMPOSE: k = XK_Compose; break;
#endif
case SDLK_MODE: k = XK_Mode_switch; break;
case SDLK_HELP: k = XK_Help; break;
- case SDLK_PRINT: k = XK_Print; break;
+ case SDLK_PRINTSCREEN: k = XK_Print; break;
case SDLK_SYSREQ: k = XK_Sys_Req; break;
- case SDLK_BREAK: k = XK_Break; break;
default: break;
}
- /* both SDL and X11 keysyms match ASCII in the range 0x01-0x7f */
- if (k == 0 && sym > 0x0 && sym < 0x100) {
- k = sym;
- if (e->keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT)) {
- if (k >= '1' && k <= '9')
- k &= ~0x10;
- else if (k >= 'a' && k <= 'f')
- k &= ~0x20;
- }
- }
- if (k == 0) {
- if (e->keysym.unicode < 0x100)
- k = e->keysym.unicode;
- else
- rfbClientLog("Unknown keysym: %d\n", sym);
- }
+ /* SDL_TEXTINPUT does not generate characters if ctrl is down, so handle those here */
+ if (k == 0 && sym > 0x0 && sym < 0x100 && e->keysym.mod & KMOD_CTRL)
+ k = sym;
return k;
}
-static uint32_t get(rfbClient *cl, int x, int y)
-{
- switch (bytesPerPixel) {
- case 1: return ((uint8_t *)cl->frameBuffer)[x + y * cl->width];
- case 2: return ((uint16_t *)cl->frameBuffer)[x + y * cl->width];
- case 4: return ((uint32_t *)cl->frameBuffer)[x + y * cl->width];
- default:
- rfbClientErr("Unknown bytes/pixel: %d", bytesPerPixel);
- exit(1);
+/* UTF-8 decoding is from https://rosettacode.org/wiki/UTF-8_encode_and_decode which is under GFDL 1.2 */
+static rfbKeySym utf8char2rfbKeySym(const char chr[4]) {
+ int bytes = strlen(chr);
+ int shift = utf8Mapping[0].bits_stored * (bytes - 1);
+ rfbKeySym codep = (*chr++ & utf8Mapping[bytes].mask) << shift;
+ int i;
+ for(i = 1; i < bytes; ++i, ++chr) {
+ shift -= utf8Mapping[0].bits_stored;
+ codep |= ((char)*chr & utf8Mapping[0].mask) << shift;
}
-}
-
-static void put(int x, int y, uint32_t v)
-{
- switch (bytesPerPixel) {
- case 1: ((uint8_t *)sdlPixels)[x + y * rowStride] = v; break;
- case 2: ((uint16_t *)sdlPixels)[x + y * rowStride] = v; break;
- case 4: ((uint32_t *)sdlPixels)[x + y * rowStride] = v; break;
- default:
- rfbClientErr("Unknown bytes/pixel: %d", bytesPerPixel);
- exit(1);
- }
-}
-
-static void resizeRectangleToReal(rfbClient *cl, int x, int y, int w, int h)
-{
- int i0 = x * realWidth / cl->width;
- int i1 = ((x + w) * realWidth - 1) / cl->width + 1;
- int j0 = y * realHeight / cl->height;
- int j1 = ((y + h) * realHeight - 1) / cl->height + 1;
- int i, j;
-
- for (j = j0; j < j1; j++)
- for (i = i0; i < i1; i++) {
- int x0 = i * cl->width / realWidth;
- int x1 = ((i + 1) * cl->width - 1) / realWidth + 1;
- int y0 = j * cl->height / realHeight;
- int y1 = ((j + 1) * cl->height - 1) / realHeight + 1;
- uint32_t r = 0, g = 0, b = 0;
-
- for (y = y0; y < y1; y++)
- for (x = x0; x < x1; x++) {
- uint32_t v = get(cl, x, y);
-#define REDSHIFT cl->format.redShift
-#define REDMAX cl->format.redMax
-#define GREENSHIFT cl->format.greenShift
-#define GREENMAX cl->format.greenMax
-#define BLUESHIFT cl->format.blueShift
-#define BLUEMAX cl->format.blueMax
- r += (v >> REDSHIFT) & REDMAX;
- g += (v >> GREENSHIFT) & GREENMAX;
- b += (v >> BLUESHIFT) & BLUEMAX;
- }
- r /= (x1 - x0) * (y1 - y0);
- g /= (x1 - x0) * (y1 - y0);
- b /= (x1 - x0) * (y1 - y0);
-
- put(i, j, (r << REDSHIFT) | (g << GREENSHIFT) |
- (b << BLUESHIFT));
- }
+ return codep;
}
static void update(rfbClient* cl,int x,int y,int w,int h) {
- if (sdlPixels) {
- resizeRectangleToReal(cl, x, y, w, h);
- w = ((x + w) * realWidth - 1) / cl->width + 1;
- h = ((y + h) * realHeight - 1) / cl->height + 1;
- x = x * realWidth / cl->width;
- y = y * realHeight / cl->height;
- w -= x;
- h -= y;
- }
- SDL_UpdateRect(rfbClientGetClientData(cl, SDL_Init), x, y, w, h);
-}
-
-static void setRealDimension(rfbClient *client, int w, int h)
-{
- SDL_Surface* sdl;
-
- if (w < 0) {
- const SDL_VideoInfo *info = SDL_GetVideoInfo();
- w = info->current_h;
- h = info->current_w;
- }
-
- if (w == realWidth && h == realHeight)
- return;
-
- if (!sdlPixels) {
- int size;
-
- sdlPixels = (char *)client->frameBuffer;
- rowStride = client->width;
-
- bytesPerPixel = client->format.bitsPerPixel / 8;
- size = client->width * bytesPerPixel * client->height;
- client->frameBuffer = malloc(size);
- if (!client->frameBuffer) {
- rfbClientErr("Could not allocate %d bytes", size);
- exit(1);
- }
- memcpy(client->frameBuffer, sdlPixels, size);
- }
-
- sdl = rfbClientGetClientData(client, SDL_Init);
- if (sdl->w != w || sdl->h != h) {
- int depth = sdl->format->BitsPerPixel;
- sdl = SDL_SetVideoMode(w, h, depth, sdlFlags);
- rfbClientSetClientData(client, SDL_Init, sdl);
- sdlPixels = sdl->pixels;
- rowStride = sdl->pitch / (depth / 8);
- }
-
- realWidth = w;
- realHeight = h;
- update(client, 0, 0, client->width, client->height);
+ SDL_Surface *sdl = rfbClientGetClientData(cl, SDL_Init);
+ /* update texture from surface->pixels */
+ SDL_Rect r = {x,y,w,h};
+ if(SDL_UpdateTexture(sdlTexture, &r, sdl->pixels + y*sdl->pitch + x*4, sdl->pitch) < 0)
+ rfbClientErr("update: failed to update texture: %s\n", SDL_GetError());
+ /* copy texture to renderer and show */
+ if(SDL_RenderClear(sdlRenderer) < 0)
+ rfbClientErr("update: failed to clear renderer: %s\n", SDL_GetError());
+ if(SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL) < 0)
+ rfbClientErr("update: failed to copy texture to renderer: %s\n", SDL_GetError());
+ SDL_RenderPresent(sdlRenderer);
}
static void kbd_leds(rfbClient* cl, int value, int pad) {
@@ -374,17 +292,69 @@ static void cleanup(rfbClient* cl)
static rfbBool handleSDLEvent(rfbClient *cl, SDL_Event *e)
{
switch(e->type) {
-#if SDL_MAJOR_VERSION > 1 || SDL_MINOR_VERSION >= 2
- case SDL_VIDEOEXPOSE:
+ case SDL_WINDOWEVENT:
+ switch (e->window.event) {
+ case SDL_WINDOWEVENT_EXPOSED:
SendFramebufferUpdateRequest(cl, 0, 0,
cl->width, cl->height, FALSE);
break;
-#endif
+ case SDL_WINDOWEVENT_FOCUS_GAINED:
+ if (SDL_HasClipboardText()) {
+ char *text = SDL_GetClipboardText();
+ if(text) {
+ rfbClientLog("sending clipboard text '%s'\n", text);
+ SendClientCutText(cl, text, strlen(text));
+ }
+ }
+
+ break;
+ case SDL_WINDOWEVENT_FOCUS_LOST:
+ if (rightAltKeyDown) {
+ SendKeyEvent(cl, XK_Alt_R, FALSE);
+ rightAltKeyDown = FALSE;
+ rfbClientLog("released right Alt key\n");
+ }
+ if (leftAltKeyDown) {
+ SendKeyEvent(cl, XK_Alt_L, FALSE);
+ leftAltKeyDown = FALSE;
+ rfbClientLog("released left Alt key\n");
+ }
+ break;
+ }
+ break;
+ case SDL_MOUSEWHEEL:
+ {
+ int steps;
+ if (viewOnly)
+ break;
+
+ if(e->wheel.y > 0)
+ for(steps = 0; steps < e->wheel.y; ++steps) {
+ SendPointerEvent(cl, x, y, rfbButton4Mask);
+ SendPointerEvent(cl, x, y, 0);
+ }
+ if(e->wheel.y < 0)
+ for(steps = 0; steps > e->wheel.y; --steps) {
+ SendPointerEvent(cl, x, y, rfbButton5Mask);
+ SendPointerEvent(cl, x, y, 0);
+ }
+ if(e->wheel.x > 0)
+ for(steps = 0; steps < e->wheel.x; ++steps) {
+ SendPointerEvent(cl, x, y, 0b01000000);
+ SendPointerEvent(cl, x, y, 0);
+ }
+ if(e->wheel.x < 0)
+ for(steps = 0; steps > e->wheel.x; --steps) {
+ SendPointerEvent(cl, x, y, 0b00100000);
+ SendPointerEvent(cl, x, y, 0);
+ }
+ break;
+ }
case SDL_MOUSEBUTTONUP:
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEMOTION:
{
- int x, y, state, i;
+ int state, i;
if (viewOnly)
break;
@@ -407,10 +377,6 @@ static rfbBool handleSDLEvent(rfbClient *cl, SDL_Event *e)
break;
}
}
- if (sdlPixels) {
- x = x * cl->width / realWidth;
- y = y * cl->height / realHeight;
- }
SendPointerEvent(cl, x, y, buttonMask);
buttonMask &= ~(rfbButton4Mask | rfbButton5Mask);
break;
@@ -426,6 +392,13 @@ static rfbBool handleSDLEvent(rfbClient *cl, SDL_Event *e)
if (e->key.keysym.sym == SDLK_LALT)
leftAltKeyDown = e->type == SDL_KEYDOWN;
break;
+ case SDL_TEXTINPUT:
+ if (viewOnly)
+ break;
+ rfbKeySym sym = utf8char2rfbKeySym(e->text.text);
+ SendKeyEvent(cl, sym, TRUE);
+ SendKeyEvent(cl, sym, FALSE);
+ break;
case SDL_QUIT:
if(listenLoop)
{
@@ -437,32 +410,6 @@ static rfbBool handleSDLEvent(rfbClient *cl, SDL_Event *e)
rfbClientCleanup(cl);
exit(0);
}
- case SDL_ACTIVEEVENT:
- if (!e->active.gain && rightAltKeyDown) {
- SendKeyEvent(cl, XK_Alt_R, FALSE);
- rightAltKeyDown = FALSE;
- rfbClientLog("released right Alt key\n");
- }
- if (!e->active.gain && leftAltKeyDown) {
- SendKeyEvent(cl, XK_Alt_L, FALSE);
- leftAltKeyDown = FALSE;
- rfbClientLog("released left Alt key\n");
- }
-
- if (e->active.gain && lost_scrap()) {
- static char *data = NULL;
- static int len = 0;
- get_scrap(T('T', 'E', 'X', 'T'), &len, &data);
- if (len)
- SendClientCutText(cl, data, len);
- }
- break;
- case SDL_SYSWMEVENT:
- clipboard_filter(e);
- break;
- case SDL_VIDEORESIZE:
- setRealDimension(cl, e->resize.w, e->resize.h);
- break;
default:
rfbClientLog("ignore SDL event: 0x%x\n", e->type);
}
@@ -471,7 +418,33 @@ static rfbBool handleSDLEvent(rfbClient *cl, SDL_Event *e)
static void got_selection(rfbClient *cl, const char *text, int len)
{
- put_scrap(T('T', 'E', 'X', 'T'), len, text);
+ rfbClientLog("received clipboard text '%s'\n", text);
+ if(SDL_SetClipboardText(text) != 0)
+ rfbClientErr("could not set received clipboard text: %s\n", SDL_GetError());
+}
+
+
+static rfbCredential* get_credential(rfbClient* cl, int credentialType){
+ rfbCredential *c = malloc(sizeof(rfbCredential));
+ c->userCredential.username = malloc(RFB_BUF_SIZE);
+ c->userCredential.password = malloc(RFB_BUF_SIZE);
+
+ if(credentialType != rfbCredentialTypeUser) {
+ rfbClientErr("something else than username and password required for authentication\n");
+ return NULL;
+ }
+
+ rfbClientLog("username and password required for authentication!\n");
+ printf("user: ");
+ fgets(c->userCredential.username, RFB_BUF_SIZE, stdin);
+ printf("pass: ");
+ fgets(c->userCredential.password, RFB_BUF_SIZE, stdin);
+
+ /* remove trailing newlines */
+ c->userCredential.username[strcspn(c->userCredential.username, "\n")] = 0;
+ c->userCredential.password[strcspn(c->userCredential.password, "\n")] = 0;
+
+ return c;
}
@@ -508,9 +481,6 @@ int main(int argc,char** argv) {
argc = j;
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
- SDL_EnableUNICODE(1);
- SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,
- SDL_DEFAULT_REPEAT_INTERVAL);
atexit(SDL_Quit);
signal(SIGINT, exit);
@@ -523,6 +493,7 @@ int main(int argc,char** argv) {
cl->HandleKeyboardLedState=kbd_leds;
cl->HandleTextChat=text_chat;
cl->GotXCutText = got_selection;
+ cl->GetCredential = get_credential;
cl->listenPort = LISTEN_PORT_OFFSET;
cl->listen6Port = LISTEN_PORT_OFFSET;
if(!rfbInitClient(cl,&argc,argv))
@@ -532,8 +503,6 @@ int main(int argc,char** argv) {
break;
}
- init_scrap();
-
while(1) {
if(SDL_PollEvent(&e)) {
/*
diff --git a/client_examples/backchannel.c b/client_examples/backchannel.c
index 04d154e..a7db9a0 100644
--- a/client_examples/backchannel.c
+++ b/client_examples/backchannel.c
@@ -71,7 +71,9 @@ static rfbClientProtocolExtension backChannel = {
backChannelEncodings, /* encodings */
NULL, /* handleEncoding */
handleBackChannelMessage, /* handleMessage */
- NULL /* next extension */
+ NULL, /* next extension */
+ NULL, /* securityTypes */
+ NULL /* handleAuthentication */
};
int
diff --git a/client_examples/ppmtest.c b/client_examples/ppmtest.c
index b8602f0..99ee595 100644
--- a/client_examples/ppmtest.c
+++ b/client_examples/ppmtest.c
@@ -58,12 +58,27 @@ static void SaveFramebufferAsPPM(rfbClient* client, int x, int y, int w, int h)
fclose(f);
}
+char * getuser(rfbClient *client)
+{
+return strdup("testuser@test");
+}
+
+char * getpassword(rfbClient *client)
+{
+return strdup("Password");
+}
+
int
main(int argc, char **argv)
{
rfbClient* client = rfbGetClient(8,3,4);
time_t t=time(NULL);
+#ifdef LIBVNCSERVER_HAVE_SASL
+ client->GetUser = getuser;
+ client->GetPassword = getpassword;
+#endif
+
if(argc>1 && !strcmp("-print",argv[1])) {
client->GotFrameBufferUpdate = PrintRect;
argv[1]=argv[0]; argv++; argc--;
diff --git a/client_examples/scrap.c b/client_examples/scrap.c
deleted file mode 100644
index c28800c..0000000
--- a/client_examples/scrap.c
+++ /dev/null
@@ -1,558 +0,0 @@
-/* Handle clipboard text and data in arbitrary formats */
-
-#include <stdio.h>
-#include <limits.h>
-
-#ifdef WIN32
-#include <SDL.h>
-#include <SDL_syswm.h>
-#else
-#include <SDL/SDL.h>
-#include <SDL/SDL_syswm.h>
-#endif
-#include "scrap.h"
-#include "rfb/rfbconfig.h"
-
-/* Determine what type of clipboard we are using */
-#if defined(__unix__) && !defined(__QNXNTO__) && defined(LIBVNCSERVER_HAVE_X11)
-#define X11_SCRAP
-#elif defined(__WIN32__)
-#define WIN_SCRAP
-#elif defined(__QNXNTO__)
-#define QNX_SCRAP
-#else
-#warning Unknown window manager for clipboard handling
-#endif /* scrap type */
-
-/* System dependent data types */
-#if defined(X11_SCRAP)
-typedef Atom scrap_type;
-static Atom XA_TARGETS, XA_TEXT, XA_COMPOUND_TEXT, XA_UTF8_STRING;
-#elif defined(WIN_SCRAP)
-typedef UINT scrap_type;
-#elif defined(QNX_SCRAP)
-typedef uint32_t scrap_type;
-#define Ph_CL_TEXT T('T', 'E', 'X', 'T')
-#else
-typedef int scrap_type;
-#endif /* scrap type */
-
-/* System dependent variables */
-#if defined(X11_SCRAP)
-static Display *SDL_Display;
-static Window SDL_Window;
-static void (*Lock_Display)(void);
-static void (*Unlock_Display)(void);
-static Atom XA_UTF8_STRING;
-#elif defined(WIN_SCRAP)
-static HWND SDL_Window;
-#elif defined(QNX_SCRAP)
-static unsigned short InputGroup;
-#endif /* scrap type */
-
-#define FORMAT_PREFIX "SDL_scrap_0x"
-
-static scrap_type convert_format(int type)
-{
- switch (type) {
- case T('T', 'E', 'X', 'T'):
-#if defined(X11_SCRAP)
- return XA_UTF8_STRING ? XA_UTF8_STRING : XA_STRING;
-#elif defined(WIN_SCRAP)
- return CF_TEXT;
-#elif defined(QNX_SCRAP)
- return Ph_CL_TEXT;
-#endif /* scrap type */
- default:
- {
- char format[sizeof(FORMAT_PREFIX)+8+1];
-
- sprintf(format, "%s%08lx", FORMAT_PREFIX,
- (unsigned long)type);
-#if defined(X11_SCRAP)
- return XInternAtom(SDL_Display, format, False);
-#elif defined(WIN_SCRAP)
- return RegisterClipboardFormat(format);
-#endif /* scrap type */
- }
- }
-}
-
-/* Convert internal data to scrap format */
-static int convert_data(int type, char *dst, const char *src, int srclen)
-{
- int dstlen;
-
- dstlen = 0;
- switch (type) {
- case T('T', 'E', 'X', 'T'):
- if (dst) {
- while (--srclen >= 0) {
-#if defined(__unix__)
- if (*src == '\r') {
- *dst++ = '\n';
- ++dstlen;
- }
- else
-#elif defined(__WIN32__)
- if (*src == '\r') {
- *dst++ = '\r';
- ++dstlen;
- *dst++ = '\n';
- ++dstlen;
- }
- else
-#endif
- {
- *dst++ = *src;
- ++dstlen;
- }
- ++src;
- }
- *dst = '\0';
- ++dstlen;
- }
- else {
- while (--srclen >= 0) {
-#if defined(__unix__)
- if (*src == '\r')
- ++dstlen;
- else
-#elif defined(__WIN32__)
- if (*src == '\r') {
- ++dstlen;
- ++dstlen;
- }
- else
-#endif
- {
- ++dstlen;
- }
- ++src;
- }
- ++dstlen;
- }
- break;
- default:
- if (dst) {
- *(int *)dst = srclen;
- dst += sizeof(int);
- memcpy(dst, src, srclen);
- }
- dstlen = sizeof(int)+srclen;
- break;
- }
- return(dstlen);
-}
-
-/* Convert scrap data to internal format */
-static int convert_scrap(int type, char *dst, char *src, int srclen)
-{
- int dstlen;
-
- dstlen = 0;
- switch (type) {
- case T('T', 'E', 'X', 'T'):
- {
- if (srclen == 0)
- srclen = strlen(src);
- if (dst) {
- while (--srclen >= 0) {
-#if defined(__WIN32__)
- if (*src == '\r')
- /* drop extraneous '\r' */;
- else
-#endif
- if (*src == '\n') {
- *dst++ = '\r';
- ++dstlen;
- }
- else {
- *dst++ = *src;
- ++dstlen;
- }
- ++src;
- }
- *dst = '\0';
- ++dstlen;
- }
- else {
- while (--srclen >= 0) {
-#if defined(__WIN32__)
- /* drop extraneous '\r' */;
- if (*src != '\r')
-#endif
- ++dstlen;
- ++src;
- }
- ++dstlen;
- }
- break;
- }
- default:
- dstlen = *(int *)src;
- if (dst)
- memcpy(dst, src + sizeof(int),
- srclen ? srclen - sizeof(int) : dstlen);
- break;
- }
- return dstlen;
-}
-
-int init_scrap(void)
-{
- SDL_SysWMinfo info;
- int retval;
-
- /* Grab the window manager specific information */
- retval = -1;
- SDL_SetError("SDL is not running on known window manager");
-
- SDL_VERSION(&info.version);
- if (SDL_GetWMInfo(&info)) {
- /* Save the information for later use */
-#if defined(X11_SCRAP)
- if (info.subsystem == SDL_SYSWM_X11) {
- SDL_Display = info.info.x11.display;
- SDL_Window = info.info.x11.window;
- Lock_Display = info.info.x11.lock_func;
- Unlock_Display = info.info.x11.unlock_func;
-
- /* Enable the special window hook events */
- SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
- SDL_SetEventFilter(clipboard_filter);
-
- XA_TARGETS = XInternAtom(SDL_Display, "TARGETS", False);
- XA_TEXT = XInternAtom(SDL_Display, "TEXT", False);
- XA_COMPOUND_TEXT = XInternAtom(SDL_Display,
- "COMPOUND_TEXT", False);
- XA_UTF8_STRING = XInternAtom(SDL_Display,
- "UTF8_STRING", False);
-
- retval = 0;
- }
- else
- SDL_SetError("SDL is not running on X11");
-#elif defined(WIN_SCRAP)
- SDL_Window = info.window;
- retval = 0;
-#elif defined(QNX_SCRAP)
- InputGroup = PhInputGroup(NULL);
- retval = 0;
-#endif /* scrap type */
- }
- return(retval);
-}
-
-int lost_scrap(void)
-{
- int retval;
-
-#if defined(X11_SCRAP)
- if (Lock_Display)
- Lock_Display();
- retval = (XGetSelectionOwner(SDL_Display, XA_PRIMARY) != SDL_Window);
- if (Unlock_Display)
- Unlock_Display();
-#elif defined(WIN_SCRAP)
- retval = (GetClipboardOwner() != SDL_Window);
-#elif defined(QNX_SCRAP)
- retval = (PhInputGroup(NULL) != InputGroup);
-#endif /* scrap type */
-
- return(retval);
-}
-
-void put_scrap(int type, int srclen, const char *src)
-{
- scrap_type format;
- int dstlen;
- char *dst;
-
- format = convert_format(type);
- dstlen = convert_data(type, NULL, src, srclen);
-
-#if defined(X11_SCRAP)
- dst = (char *)malloc(dstlen);
- if (dst != NULL) {
- if (Lock_Display)
- Lock_Display();
- convert_data(type, dst, src, srclen);
- XChangeProperty(SDL_Display, DefaultRootWindow(SDL_Display),
- XA_CUT_BUFFER0, format, 8, PropModeReplace,
- (unsigned char *)dst, dstlen);
- free(dst);
- if (lost_scrap())
- XSetSelectionOwner(SDL_Display, XA_PRIMARY,
- SDL_Window, CurrentTime);
- if (Unlock_Display)
- Unlock_Display();
- }
-#elif defined(WIN_SCRAP)
- if (OpenClipboard(SDL_Window)) {
- HANDLE hMem;
-
- hMem = GlobalAlloc((GMEM_MOVEABLE|GMEM_DDESHARE), dstlen);
- if (hMem != NULL) {
- dst = (char *)GlobalLock(hMem);
- convert_data(type, dst, src, srclen);
- GlobalUnlock(hMem);
- EmptyClipboard();
- SetClipboardData(format, hMem);
- }
- CloseClipboard();
- }
-#elif defined(QNX_SCRAP)
-#if (_NTO_VERSION < 620) /* before 6.2.0 releases */
-#define PhClipboardHdr PhClipHeader
-#endif
- {
- PhClipboardHdr clheader = { Ph_CLIPBOARD_TYPE_TEXT, 0, NULL };
- int* cldata;
- int status;
-
- dst = (char *)malloc(dstlen+4);
- if (dst != NULL) {
- cldata = (int*)dst;
- *cldata = type;
- convert_data(type, dst+4, src, srclen);
- clheader.data = dst;
-#if (_NTO_VERSION < 620) /* before 6.2.0 releases */
- if (dstlen > 65535)
- /* maximum photon clipboard size :(*/
- clheader.length = 65535;
- else
-#endif
- clheader.length = dstlen+4;
- status = PhClipboardCopy(InputGroup, 1, &clheader);
- if (status == -1)
- fprintf(stderr,
- "Photon: copy to clipboard failed!\n");
- free(dst);
- }
- }
-#endif /* scrap type */
-}
-
-void get_scrap(int type, int *dstlen, char **dst)
-{
- scrap_type format;
-
- *dstlen = 0;
- format = convert_format(type);
-
-#if defined(X11_SCRAP)
- {
- Window owner;
- Atom selection;
- Atom seln_type;
- int seln_format;
- unsigned long nbytes;
- unsigned long overflow;
- char *src;
-
- if (Lock_Display)
- Lock_Display();
- owner = XGetSelectionOwner(SDL_Display, XA_PRIMARY);
- if (Unlock_Display)
- Unlock_Display();
- if ((owner == None) || (owner == SDL_Window)) {
- owner = DefaultRootWindow(SDL_Display);
- selection = XA_CUT_BUFFER0;
- }
- else {
- int selection_response = 0;
- SDL_Event event;
-
- owner = SDL_Window;
- if (Lock_Display)
- Lock_Display();
- selection = XInternAtom(SDL_Display, "SDL_SELECTION",
- False);
- XConvertSelection(SDL_Display, XA_PRIMARY, format,
- selection, owner, CurrentTime);
- if (Unlock_Display)
- Unlock_Display();
- while (!selection_response) {
- SDL_WaitEvent(&event);
- if (event.type == SDL_SYSWMEVENT) {
- XEvent xevent =
- event.syswm.msg->event.xevent;
-
- if ((xevent.type == SelectionNotify) &&
- (xevent.xselection.requestor
- == owner))
- selection_response = 1;
- }
- }
- }
- if (Lock_Display)
- Lock_Display();
- if (XGetWindowProperty(SDL_Display, owner, selection,
- 0, INT_MAX/4, False, format, &seln_type,
- &seln_format, &nbytes, &overflow,
- (unsigned char **)&src) == Success) {
- if (seln_type == format) {
- *dstlen = convert_scrap(type, NULL,
- src, nbytes);
- *dst = (char *)realloc(*dst, *dstlen);
- if (*dst == NULL)
- *dstlen = 0;
- else
- convert_scrap(type, *dst, src, nbytes);
- }
- XFree(src);
- }
- }
- if (Unlock_Display)
- Unlock_Display();
-#elif defined(WIN_SCRAP)
- if (IsClipboardFormatAvailable(format) && OpenClipboard(SDL_Window)) {
- HANDLE hMem;
- char *src;
-
- hMem = GetClipboardData(format);
- if (hMem != NULL) {
- src = (char *)GlobalLock(hMem);
- *dstlen = convert_scrap(type, NULL, src, 0);
- *dst = (char *)realloc(*dst, *dstlen);
- if (*dst == NULL)
- *dstlen = 0;
- else
- convert_scrap(type, *dst, src, 0);
- GlobalUnlock(hMem);
- }
- CloseClipboard();
- }
-#elif defined(QNX_SCRAP)
-#if (_NTO_VERSION < 620) /* before 6.2.0 releases */
- {
- void* clhandle;
- PhClipHeader* clheader;
- int* cldata;
-
- clhandle = PhClipboardPasteStart(InputGroup);
- if (clhandle != NULL) {
- clheader = PhClipboardPasteType(clhandle,
- Ph_CLIPBOARD_TYPE_TEXT);
- if (clheader != NULL) {
- cldata = clheader->data;
- if ((clheader->length>4) && (*cldata == type)) {
- *dstlen = convert_scrap(type, NULL,
- (char*)clheader->data+4,
- clheader->length-4);
- *dst = (char *)realloc(*dst, *dstlen);
- if (*dst == NULL)
- *dstlen = 0;
- else
- convert_scrap(type, *dst,
- (char*)clheader->data+4,
- clheader->length-4);
- }
- }
- PhClipboardPasteFinish(clhandle);
- }
- }
-#else /* 6.2.0 and 6.2.1 and future releases */
- {
- void* clhandle;
- PhClipboardHdr* clheader;
- int* cldata;
-
- clheader=PhClipboardRead(InputGroup, Ph_CLIPBOARD_TYPE_TEXT);
- if (clheader!=NULL) {
- cldata=clheader->data;
- if ((clheader->length>4) && (*cldata==type)) {
- *dstlen = convert_scrap(type, NULL,
- (char*)clheader->data+4,
- clheader->length-4);
- *dst = (char *)realloc(*dst, *dstlen);
- if (*dst == NULL)
- *dstlen = 0;
- else
- convert_scrap(type, *dst,
- (char*)clheader->data+4,
- clheader->length-4);
- }
- }
- }
-#endif
-#endif /* scrap type */
-}
-
-int clipboard_filter(const SDL_Event *event)
-{
-#if defined(X11_SCRAP)
- /* Post all non-window manager specific events */
- if (event->type != SDL_SYSWMEVENT)
- return(1);
-
- /* Handle window-manager specific clipboard events */
- switch (event->syswm.msg->event.xevent.type) {
- /* Copy the selection from XA_CUT_BUFFER0 to the requested property */
- case SelectionRequest: {
- XSelectionRequestEvent *req;
- XEvent sevent;
- int seln_format;
- unsigned long nbytes;
- unsigned long overflow;
- unsigned char *seln_data;
-
- req = &event->syswm.msg->event.xevent.xselectionrequest;
- if (req->target == XA_TARGETS) {
- Atom supported[] = {
- XA_TEXT, XA_COMPOUND_TEXT, XA_UTF8_STRING,
- XA_TARGETS, XA_STRING
- };
- XEvent response;
-
- XChangeProperty(SDL_Display, req->requestor,
- req->property, req->target, 32, PropModeReplace,
- (unsigned char*)supported,
- sizeof(supported) / sizeof(supported[0]));
- response.xselection.property=None;
- response.xselection.type= SelectionNotify;
- response.xselection.display= req->display;
- response.xselection.requestor= req->requestor;
- response.xselection.selection=req->selection;
- response.xselection.target= req->target;
- response.xselection.time = req->time;
- XSendEvent (SDL_Display, req->requestor,0,0,&response);
- XFlush (SDL_Display);
- return 1;
- }
-
- sevent.xselection.type = SelectionNotify;
- sevent.xselection.display = req->display;
- sevent.xselection.selection = req->selection;
- sevent.xselection.target = None;
- sevent.xselection.property = req->property;
- sevent.xselection.requestor = req->requestor;
- sevent.xselection.time = req->time;
- if (XGetWindowProperty(SDL_Display,
- DefaultRootWindow(SDL_Display), XA_CUT_BUFFER0,
- 0, INT_MAX/4, False, req->target,
- &sevent.xselection.target, &seln_format,
- &nbytes, &overflow, &seln_data) == Success) {
- if (sevent.xselection.target == req->target) {
- if (sevent.xselection.target == XA_STRING &&
- nbytes > 0 &&
- seln_data[nbytes-1] == '\0')
- --nbytes;
- XChangeProperty(SDL_Display, req->requestor,
- req->property, sevent.xselection.target,
- seln_format, PropModeReplace,
- seln_data, nbytes);
- sevent.xselection.property = req->property;
- }
- XFree(seln_data);
- }
- XSendEvent(SDL_Display,req->requestor,False,0,&sevent);
- XSync(SDL_Display, False);
- break;
- }
- }
- /* Post the event for X11 clipboard reading above */
-#endif /* X11_SCRAP */
- return(1);
-}
diff --git a/client_examples/scrap.h b/client_examples/scrap.h
deleted file mode 100644
index 647bd74..0000000
--- a/client_examples/scrap.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Handle clipboard text and data in arbitrary formats */
-
-/* Miscellaneous defines */
-#define T(A, B, C, D) (int)((A<<24)|(B<<16)|(C<<8)|(D<<0))
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-extern int init_scrap(void);
-extern int lost_scrap(void);
-extern void put_scrap(int type, int srclen, const char *src);
-extern void get_scrap(int type, int *dstlen, char **dst);
-extern int clipboard_filter(const SDL_Event *event);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
diff --git a/client_examples/vnc2mpg.c b/client_examples/vnc2mpg.c
index af4a73a..a7438af 100644
--- a/client_examples/vnc2mpg.c
+++ b/client_examples/vnc2mpg.c
@@ -3,6 +3,7 @@
* Simple movie writer for vnc; based on Libavformat API example from FFMPEG
*
* Copyright (c) 2003 Fabrice Bellard, 2004 Johannes E. Schindelin
+ * Updates copyright (c) 2017 Tyrel M. McQueen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,412 +26,451 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <signal.h>
#include <math.h>
-
-#ifndef M_PI
-#define M_PI 3.1415926535897931
-#endif
-
-#include "avformat.h"
+#include <signal.h>
+#include <sys/time.h>
+#include <libavformat/avformat.h>
+#include <libswscale/swscale.h>
#include <rfb/rfbclient.h>
-#define STREAM_FRAME_RATE 25 /* 25 images/s */
+#define VNC_PIX_FMT AV_PIX_FMT_RGB565 /* pixel format generated by VNC client */
+#define OUTPUT_PIX_FMT AV_PIX_FMT_YUV420P /* default pix_fmt */
-/**************************************************************/
-/* video output */
+static int write_packet(AVFormatContext *oc, const AVRational *time_base, AVStream *st, AVPacket *pkt)
+{
+ /* rescale output packet timestamp values from codec to stream timebase */
+ av_packet_rescale_ts(pkt, *time_base, st->time_base);
+ pkt->stream_index = st->index;
+ /* Write the compressed frame to the media file. */
+ return av_interleaved_write_frame(oc, pkt);
+}
-AVFrame *picture, *tmp_picture;
-uint8_t *video_outbuf;
-int frame_count, video_outbuf_size;
+/*************************************************/
+/* video functions */
-/* add a video output stream */
-AVStream *add_video_stream(AVFormatContext *oc, int codec_id, int w, int h)
-{
- AVCodecContext *c;
+/* a wrapper around a single output video stream */
+typedef struct {
AVStream *st;
+ AVCodec *codec;
+ AVCodecContext *enc;
+ int64_t pts;
+ AVFrame *frame;
+ AVFrame *tmp_frame;
+ struct SwsContext *sws;
+} VideoOutputStream;
+
+/* Add an output video stream. */
+int add_video_stream(VideoOutputStream *ost, AVFormatContext *oc,
+ enum AVCodecID codec_id, int64_t br, int sr, int w, int h)
+{
+ int i;
- st = av_new_stream(oc, 0);
- if (!st) {
- fprintf(stderr, "Could not alloc stream\n");
- exit(1);
- }
-
-#if LIBAVFORMAT_BUILD<4629
- c = &st->codec;
-#else
- c = st->codec;
-#endif
- c->codec_id = codec_id;
- c->codec_type = CODEC_TYPE_VIDEO;
-
- /* put sample parameters */
- c->bit_rate = 800000;
- /* resolution must be a multiple of two */
- c->width = w;
- c->height = h;
- /* frames per second */
-#if LIBAVCODEC_BUILD<4754
- c->frame_rate = STREAM_FRAME_RATE;
- c->frame_rate_base = 1;
-#else
- c->time_base.den = STREAM_FRAME_RATE;
- c->time_base.num = 1;
- c->pix_fmt = PIX_FMT_YUV420P;
-#endif
- c->gop_size = 12; /* emit one intra frame every twelve frames at most */
- if (c->codec_id == CODEC_ID_MPEG2VIDEO) {
- /* just for testing, we also add B frames */
- c->max_b_frames = 2;
+ /* find the encoder */
+ ost->codec = avcodec_find_encoder(codec_id);
+ if (!(ost->codec)) {
+ fprintf(stderr, "Could not find encoder for '%s'\n",
+ avcodec_get_name(codec_id));
+ return -1;
+ } // no extra memory allocation from this call
+ if (ost->codec->type != AVMEDIA_TYPE_VIDEO) {
+ fprintf(stderr, "Encoder for '%s' does not seem to be for video.\n",
+ avcodec_get_name(codec_id));
+ return -2;
}
- if (c->codec_id == CODEC_ID_MPEG1VIDEO){
- /* needed to avoid using macroblocks in which some coeffs overflow
- this doesn't happen with normal video, it just happens here as the
- motion of the chroma plane doesn't match the luma plane */
- c->mb_decision=2;
+ ost->enc = avcodec_alloc_context3(ost->codec);
+ if (!(ost->enc)) {
+ fprintf(stderr, "Could not alloc an encoding context\n");
+ return -3;
+ } // from now on need to call avcodec_free_context(&(ost->enc)) on error
+
+ /* Set codec parameters */
+ ost->enc->codec_id = codec_id;
+ ost->enc->bit_rate = br;
+ /* Resolution must be a multiple of two (round up to avoid buffer overflow). */
+ ost->enc->width = w + (w % 2);
+ ost->enc->height = h + (h % 2);
+ /* timebase: This is the fundamental unit of time (in seconds) in terms
+ * of which frame timestamps are represented. For fixed-fps content,
+ * timebase should be 1/framerate and timestamp increments should be
+ * identical to 1. */
+ ost->enc->time_base = (AVRational){ 1, sr };
+ ost->enc->gop_size = 12; /* emit one intra frame every twelve frames at most */
+ ost->enc->pix_fmt = OUTPUT_PIX_FMT;
+ if (ost->enc->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
+ /* Needed to avoid using macroblocks in which some coeffs overflow.
+ * This does not happen with normal video, it just happens here as
+ * the motion of the chroma plane does not match the luma plane. */
+ ost->enc->mb_decision = 2;
}
- /* some formats want stream headers to be separate */
- if(!strcmp(oc->oformat->name, "mp4") || !strcmp(oc->oformat->name, "mov") || !strcmp(oc->oformat->name, "3gp"))
- c->flags |= CODEC_FLAG_GLOBAL_HEADER;
-
- return st;
+
+ ost->st = avformat_new_stream(oc, ost->codec);
+ if (!ost->st) {
+ fprintf(stderr, "Could not allocate stream\n");
+ avcodec_free_context(&(ost->enc));
+ return -4;
+ } // stream memory cleared up when oc is freed, so no need to do so later in this function on error
+ ost->st->id = oc->nb_streams-1;
+ ost->st->time_base = ost->enc->time_base;
+ ost->pts = 0;
+
+ /* Some formats want stream headers to be separate. */
+ if (oc->oformat->flags & AVFMT_GLOBALHEADER)
+ ost->enc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
+
+ // must wait to allocate frame buffers until codec is opened (in case codec changes the PIX_FMT)
+ return 0;
}
-AVFrame *alloc_picture(int pix_fmt, int width, int height)
+AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, int width, int height)
{
AVFrame *picture;
- uint8_t *picture_buf;
- int size;
-
- picture = avcodec_alloc_frame();
+ int ret;
+ picture = av_frame_alloc();
if (!picture)
return NULL;
- size = avpicture_get_size(pix_fmt, width, height);
- picture_buf = malloc(size);
- if (!picture_buf) {
- av_free(picture);
+ // from now on need to call av_frame_free(&picture) on error
+ picture->format = pix_fmt;
+ picture->width = width;
+ picture->height = height;
+ /* allocate the buffers for the frame data */
+ ret = av_frame_get_buffer(picture, 64);
+ if (ret < 0) {
+ fprintf(stderr, "Could not allocate frame data.\n");
+ av_frame_free(&picture);
return NULL;
}
- avpicture_fill((AVPicture *)picture, picture_buf,
- pix_fmt, width, height);
return picture;
-}
-
-void open_video(AVFormatContext *oc, AVStream *st)
-{
- AVCodec *codec;
- AVCodecContext *c;
-
-#if LIBAVFORMAT_BUILD<4629
- c = &st->codec;
-#else
- c = st->codec;
-#endif
-
- /* find the video encoder */
- codec = avcodec_find_encoder(c->codec_id);
- if (!codec) {
- fprintf(stderr, "codec not found\n");
- exit(1);
- }
+} // use av_frame_free(&picture) to free memory from this call
+int open_video(AVFormatContext *oc, VideoOutputStream *ost)
+{
+ int ret;
/* open the codec */
- if (avcodec_open(c, codec) < 0) {
- fprintf(stderr, "could not open codec\n");
- exit(1);
+ ret = avcodec_open2(ost->enc, ost->codec, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Could not open video codec: %s\n", av_err2str(ret));
+ return ret;
+ } // memory from this call freed when oc is freed, no need to do it on error in this call
+ /* copy the stream parameters to the muxer */
+ ret = avcodec_parameters_from_context(ost->st->codecpar, ost->enc);
+ if (ret < 0) {
+ fprintf(stderr, "Could not copy the stream parameters.\n");
+ return ret;
+ } // memory from this call is freed when oc (parent of ost->st) is freed, no need to do it on error in this call
+ /* allocate and init a re-usable frame */
+ ost->frame = alloc_picture(ost->enc->pix_fmt, ost->enc->width, ost->enc->height);
+ if (!(ost->frame)) {
+ fprintf(stderr, "Could not allocate video frame\n");
+ return -1;
+ } // from now on need to call av_frame_free(&(ost->frame)) on error
+ /* If the output format is not the same as the VNC format, then a temporary VNC format
+ * picture is needed too. It is then converted to the required
+ * output format. */
+ ost->tmp_frame = NULL;
+ ost->sws = NULL;
+ if (ost->enc->pix_fmt != VNC_PIX_FMT) {
+ ost->tmp_frame = alloc_picture(VNC_PIX_FMT, ost->enc->width, ost->enc->height);
+ if (!(ost->tmp_frame)) {
+ fprintf(stderr, "Could not allocate temporary picture\n");
+ av_frame_free(&(ost->frame));
+ return -2;
+ } // from now on need to call av_frame_free(&(ost->tmp_frame)) on error
+ ost->sws = sws_getCachedContext(ost->sws, ost->enc->width, ost->enc->height, VNC_PIX_FMT, ost->enc->width, ost->enc->height, ost->enc->pix_fmt, 0, NULL, NULL, NULL);
+ if (!(ost->sws)) {
+ fprintf(stderr, "Could not get sws context\n");
+ av_frame_free(&(ost->frame));
+ av_frame_free(&(ost->tmp_frame));
+ return -3;
+ } // from now on need to call sws_freeContext(ost->sws); ost->sws = NULL; on error
}
- video_outbuf = NULL;
- if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) {
- /* allocate output buffer */
- /* XXX: API change will be done */
- video_outbuf_size = 200000;
- video_outbuf = malloc(video_outbuf_size);
- }
+ return 0;
+}
- /* allocate the encoded raw picture */
- picture = alloc_picture(c->pix_fmt, c->width, c->height);
- if (!picture) {
- fprintf(stderr, "Could not allocate picture\n");
- exit(1);
+/*
+ * encode current video frame and send it to the muxer
+ * return 0 on success, negative on error
+ */
+int write_video_frame(AVFormatContext *oc, VideoOutputStream *ost, int64_t pts)
+{
+ int ret, ret2;
+ AVPacket pkt = { 0 };
+ if (pts <= ost->pts) return 0; // nothing to do
+ /* convert format if needed */
+ if (ost->tmp_frame) {
+ sws_scale(ost->sws, (const uint8_t * const *)ost->tmp_frame->data,
+ ost->tmp_frame->linesize, 0, ost->enc->height, ost->frame->data, ost->frame->linesize);
}
- /* if the output format is not RGB565, then a temporary RGB565
- picture is needed too. It is then converted to the required
- output format */
- tmp_picture = NULL;
- if (c->pix_fmt != PIX_FMT_RGB565) {
- tmp_picture = alloc_picture(PIX_FMT_RGB565, c->width, c->height);
- if (!tmp_picture) {
- fprintf(stderr, "Could not allocate temporary picture\n");
- exit(1);
+ /* send the imager to encoder */
+ ost->pts = pts;
+ ost->frame->pts = ost->pts;
+ ret = avcodec_send_frame(ost->enc, ost->frame);
+ if (ret < 0) {
+ fprintf(stderr, "Error sending video frame to encoder: %s\n", av_err2str(ret));
+ return ret;
+ }
+ /* read all available packets */
+ ret2 = 0;
+ for (ret = avcodec_receive_packet(ost->enc, &pkt); ret == 0; ret = avcodec_receive_packet(ost->enc, &pkt)) {
+ ret2 = write_packet(oc, &(ost->enc->time_base), ost->st, &pkt);
+ if (ret2 < 0) {
+ fprintf(stderr, "Error while writing video frame: %s\n", av_err2str(ret2));
+ /* continue on this error to not gum up encoder */
}
}
+ if (ret2 < 0) return ret2;
+ if (!(ret == AVERROR(EAGAIN))) return ret; // if AVERROR(EAGAIN), means all available packets output, need more frames (i.e. success)
+ return 0;
}
-void write_video_frame(AVFormatContext *oc, AVStream *st)
+/*
+ * Write final video frame (i.e. drain codec).
+ */
+int write_final_video_frame(AVFormatContext *oc, VideoOutputStream *ost)
{
- int out_size, ret;
- AVCodecContext *c;
- AVFrame *picture_ptr;
-
-#if LIBAVFORMAT_BUILD<4629
- c = &st->codec;
-#else
- c = st->codec;
-#endif
-
- if (c->pix_fmt != PIX_FMT_RGB565) {
- /* as we only generate a RGB565 picture, we must convert it
- to the codec pixel format if needed */
- img_convert((AVPicture *)picture, c->pix_fmt,
- (AVPicture *)tmp_picture, PIX_FMT_RGB565,
- c->width, c->height);
- }
- picture_ptr = picture;
-
-
- if (oc->oformat->flags & AVFMT_RAWPICTURE) {
- /* raw video case. The API will change slightly in the near
- futur for that */
- AVPacket pkt;
- av_init_packet(&pkt);
-
- pkt.flags |= PKT_FLAG_KEY;
- pkt.stream_index= st->index;
- pkt.data= (uint8_t *)picture_ptr;
- pkt.size= sizeof(AVPicture);
-
- ret = av_write_frame(oc, &pkt);
- } else {
- /* encode the image */
- out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size, picture_ptr);
- /* if zero size, it means the image was buffered */
- if (out_size != 0) {
- AVPacket pkt;
- av_init_packet(&pkt);
-
- pkt.pts= c->coded_frame->pts;
- if(c->coded_frame->key_frame)
- pkt.flags |= PKT_FLAG_KEY;
- pkt.stream_index= st->index;
- pkt.data= video_outbuf;
- pkt.size= out_size;
-
- /* write the compressed frame in the media file */
- ret = av_write_frame(oc, &pkt);
- } else {
- ret = 0;
- }
+ int ret, ret2;
+ AVPacket pkt = { 0 };
+
+ /* send NULL image to encoder */
+ ret = avcodec_send_frame(ost->enc, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Error sending final video frame to encoder: %s\n", av_err2str(ret));
+ return ret;
}
- if (ret != 0) {
- fprintf(stderr, "Error while writing video frame\n");
- exit(1);
+ /* read all available packets */
+ ret2 = 0;
+ for (ret = avcodec_receive_packet(ost->enc, &pkt); ret == 0; ret = avcodec_receive_packet(ost->enc, &pkt)) {
+ ret2 = write_packet(oc, &(ost->enc->time_base), ost->st, &pkt);
+ if (ret2 < 0) {
+ fprintf(stderr, "Error while writing final video frame: %s\n", av_err2str(ret2));
+ /* continue on this error to not gum up encoder */
+ }
}
- frame_count++;
+ if (ret2 < 0) return ret2;
+ if (!(ret == AVERROR(EOF))) return ret;
+ return 0;
}
-void close_video(AVFormatContext *oc, AVStream *st)
+void close_video_stream(VideoOutputStream *ost)
{
- avcodec_close(st->codec);
- av_free(picture->data[0]);
- av_free(picture);
- if (tmp_picture) {
- av_free(tmp_picture->data[0]);
- av_free(tmp_picture);
- }
- av_free(video_outbuf);
+ avcodec_free_context(&(ost->enc));
+ av_frame_free(&(ost->frame));
+ av_frame_free(&(ost->tmp_frame));
+ sws_freeContext(ost->sws); ost->sws = NULL;
+ ost->codec = NULL; /* codec not an allocated item */
+ ost->st = NULL; /* freeing parent oc will free this memory */
}
-static const char *filename;
-static AVOutputFormat *fmt;
-static AVFormatContext *oc;
-static AVStream *video_st;
-static double video_pts;
-
-static int movie_open(int w, int h) {
- if (fmt->video_codec != CODEC_ID_NONE) {
- video_st = add_video_stream(oc, fmt->video_codec, w, h);
- } else
- return 1;
-
- /* set the output parameters (must be done even if no
- parameters). */
- if (av_set_parameters(oc, NULL) < 0) {
- fprintf(stderr, "Invalid output format parameters\n");
- return 2;
+/**************************************************************/
+/* Output movie handling */
+AVFormatContext *movie_open(char *filename, VideoOutputStream *video_st, int br, int fr, int w, int h) {
+ int ret;
+ AVFormatContext *oc;
+
+ /* allocate the output media context. */
+ ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename);
+ if (ret < 0) {
+ fprintf(stderr, "Warning: Could not deduce output format from file extension: using MP4.\n");
+ ret = avformat_alloc_output_context2(&oc, NULL, "mp4", filename);
}
+ if (ret < 0) {
+ fprintf(stderr, "Error: Could not allocate media context: %s.\n", av_err2str(ret));
+ return NULL;
+ } // from now on, need to call avformat_free_context(oc); oc=NULL; to free memory on error
- dump_format(oc, 0, filename, 1);
-
- /* now that all the parameters are set, we can open the audio and
- video codecs and allocate the necessary encode buffers */
- if (video_st)
- open_video(oc, video_st);
+ /* Add the video stream using the default format codec and initialize the codec. */
+ if (oc->oformat->video_codec != AV_CODEC_ID_NONE) {
+ ret = add_video_stream(video_st, oc, oc->oformat->video_codec, br, fr, w, h);
+ } else {
+ ret = -1;
+ }
+ if (ret < 0) {
+ fprintf(stderr, "Error: chosen output format does not have a video codec, or error %i\n", ret);
+ avformat_free_context(oc); oc = NULL;
+ return NULL;
+ } // from now on, need to call close_video_stream(video_st) to free memory on error
+
+ /* Now that all the parameters are set, we can open the codecs and allocate the necessary encode buffers. */
+ ret = open_video(oc, video_st);
+ if (ret < 0) {
+ fprintf(stderr, "Error: error opening video codec, error %i\n", ret);
+ close_video_stream(video_st);
+ avformat_free_context(oc); oc = NULL;
+ return NULL;
+ } // no additional calls required to free memory, as close_video_stream(video_st) will do it
/* open the output file, if needed */
- if (!(fmt->flags & AVFMT_NOFILE)) {
- if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0) {
- fprintf(stderr, "Could not open '%s'\n", filename);
- return 3;
+ if (!(oc->oformat->flags & AVFMT_NOFILE)) {
+ ret = avio_open(&oc->pb, filename, AVIO_FLAG_WRITE);
+ if (ret < 0) {
+ fprintf(stderr, "Could not open '%s': %s\n", filename,
+ av_err2str(ret));
+ close_video_stream(video_st);
+ avformat_free_context(oc); oc = NULL;
+ return NULL;
}
- }
-
- /* write the stream header, if any */
- av_write_header(oc);
-
- return 0;
+ } // will need to call avio_closep(&oc->pb) to free file handle on error
+
+ /* Write the stream header, if any. */
+ ret = avformat_write_header(oc, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Error occurred when writing to output file: %s\n",
+ av_err2str(ret));
+ if (!(oc->oformat->flags & AVFMT_NOFILE))
+ avio_closep(&oc->pb);
+ close_video_stream(video_st);
+ avformat_free_context(oc); oc = NULL;
+ } // no additional items to free
+
+ return oc;
}
-static int movie_close() {
- int i;
+void movie_close(AVFormatContext **ocp, VideoOutputStream *video_st) {
+ AVFormatContext *oc = *ocp;
+ /* Write the trailer, if any. The trailer must be written before you
+ * close the CodecContexts open when you wrote the header; otherwise
+ * av_write_trailer() may try to use memory that was freed on
+ * av_codec_close(). */
+ if (oc) {
+ if (video_st)
+ write_final_video_frame(oc, video_st);
- /* close each codec */
- close_video(oc, video_st);
+ av_write_trailer(oc);
- /* write the trailer, if any */
- av_write_trailer(oc);
-
- /* free the streams */
- for(i = 0; i < oc->nb_streams; i++) {
- av_freep(&oc->streams[i]);
- }
+ /* Close the video codec. */
+ close_video_stream(video_st);
- if (!(fmt->flags & AVFMT_NOFILE)) {
- /* close the output file */
- url_fclose(&oc->pb);
- }
+ if (!(oc->oformat->flags & AVFMT_NOFILE))
+ /* Close the output file. */
+ avio_closep(&oc->pb);
- /* free the stream */
- av_free(oc);
+ /* free the stream */
+ avformat_free_context(oc);
+ ocp = NULL;
+ }
+}
+/**************************************************************/
+/* VNC globals */
+VideoOutputStream video_st = { 0 };
+rfbClient *client = NULL;
+rfbBool quit = FALSE;
+char *filename = NULL;
+AVFormatContext *oc = NULL;
+int bitrate = 1000000;
+int framerate = 5;
+long max_time = 0;
+struct timespec start_time, cur_time;
+
+/* Signal handling */
+void signal_handler(int signal) {
+ quit=TRUE;
}
-static rfbBool quit=FALSE;
-static void signal_handler(int signal) {
- fprintf(stderr,"Cleaning up.\n");
- quit=TRUE;
+/* returns time since start in pts units */
+int64_t time_to_pts(int framerate, struct timespec *start_time, struct timespec *cur_time) {
+ time_t ds = cur_time->tv_sec - start_time->tv_sec;
+ long dns = cur_time->tv_nsec - start_time->tv_nsec;
+ /* use usecs */
+ int64_t dt = (int64_t)ds*(int64_t)1000000+(int64_t)dns/(int64_t)1000;
+ /* compute rv in units of frame number (rounding to nearest, not truncating) */
+ int64_t rv = (((int64_t)framerate)*dt + (int64_t)500000) / (int64_t)(1000000);
+
+ return rv;
}
-/**************************************************************/
/* VNC callback functions */
-static rfbBool resize(rfbClient* client) {
- static rfbBool first=TRUE;
- if(!first) {
- movie_close();
- perror("I don't know yet how to change resolutions!\n");
- }
- movie_open(client->width, client->height);
- signal(SIGINT,signal_handler);
- if(tmp_picture)
- client->frameBuffer=tmp_picture->data[0];
- else
- client->frameBuffer=picture->data[0];
- return TRUE;
+rfbBool vnc_malloc_fb(rfbClient* client) {
+ movie_close(&oc, &video_st);
+ oc = movie_open(filename, &video_st, bitrate, framerate, client->width, client->height);
+ if (!oc)
+ return FALSE;
+ signal(SIGINT,signal_handler);
+ signal(SIGTERM,signal_handler);
+ signal(SIGQUIT,signal_handler);
+ signal(SIGABRT,signal_handler);
+ /* These assignments assumes the AVFrame buffer is contigous. This is true in current ffmpeg versions for
+ * most non-HW accelerated bits, but may not be true globally. */
+ if(video_st.tmp_frame)
+ client->frameBuffer=video_st.tmp_frame->data[0];
+ else
+ client->frameBuffer=video_st.frame->data[0];
+ return TRUE;
}
-static void update(rfbClient* client,int x,int y,int w,int h) {
+void vnc_update(rfbClient* client,int x,int y,int w,int h) {
}
/**************************************************************/
/* media file output */
-
int main(int argc, char **argv)
{
- time_t stop=0;
- rfbClient* client;
int i,j;
- /* get a vnc client structure (don't connect yet). */
+ /* Initialize vnc client structure (don't connect yet). */
client = rfbGetClient(5,3,2);
client->format.redShift=11; client->format.redMax=31;
client->format.greenShift=5; client->format.greenMax=63;
client->format.blueShift=0; client->format.blueMax=31;
- /* initialize libavcodec, and register all codecs and formats */
+ /* Initialize libavcodec, and register all codecs and formats. */
av_register_all();
-
- if(!strncmp(argv[argc-1],":",1) ||
- !strncmp(argv[argc-1],"127.0.0.1",9) ||
- !strncmp(argv[argc-1],"localhost",9))
- client->appData.encodingsString="raw";
- filename=0;
+ /* Parse command line. */
for(i=1;i<argc;i++) {
- j=i;
- if(argc>i+1 && !strcmp("-o",argv[i])) {
- filename=argv[2];
- j+=2;
- } else if(argc>i+1 && !strcmp("-t",argv[i])) {
- stop=time(0)+atoi(argv[i+1]);
- j+=2;
- }
- if(j>i) {
- argc-=j-i;
- memmove(argv+i,argv+j,(argc-i)*sizeof(char*));
- i--;
- }
+ j=i;
+ if(argc>i+1 && !strcmp("-o",argv[i])) {
+ filename=argv[i+1];
+ j+=2;
+ } else if(argc>i+1 && !strcmp("-t",argv[i])) {
+ max_time=atol(argv[i+1]);
+ if (max_time < 10 || max_time > 100000000) {
+ fprintf(stderr, "Warning: Nonsensical time-per-file %li, resetting to default.\n", max_time);
+ max_time = 0;
+ }
+ j+=2;
+ }
+ /* This is so that argc/argv are ready for passing to rfbInitClient */
+ if(j>i) {
+ argc-=j-i;
+ memmove(argv+i,argv+j,(argc-i)*sizeof(char*));
+ i--;
+ }
}
-
- /* auto detect the output format from the name. default is
- mpeg. */
- fmt = filename?guess_format(NULL, filename, NULL):0;
- if (!fmt) {
- printf("Could not deduce output format from file extension: using MPEG.\n");
- fmt = guess_format("mpeg", NULL, NULL);
- }
- if (!fmt) {
- fprintf(stderr, "Could not find suitable output format\n");
- exit(1);
+ /* default filename. */
+ if (!filename) {
+ fprintf(stderr, "Warning: No filename specified. Using output.mp4\n");
+ filename = "output.mp4";
}
-
- /* allocate the output media context */
- oc = av_alloc_format_context();
- if (!oc) {
- fprintf(stderr, "Memory error\n");
- exit(1);
- }
- oc->oformat = fmt;
- snprintf(oc->filename, sizeof(oc->filename), "%s", filename);
-
- /* add the audio and video streams using the default format codecs
- and initialize the codecs */
- video_st = NULL;
- /* open VNC connection */
- client->MallocFrameBuffer=resize;
- client->GotFrameBufferUpdate=update;
+ /* open VNC connection. */
+ client->MallocFrameBuffer=vnc_malloc_fb;
+ client->GotFrameBufferUpdate=vnc_update;
if(!rfbInitClient(client,&argc,argv)) {
- printf("usage: %s [-o output_file] [-t seconds] server:port\n"
- "Shoot a movie from a VNC server.\n", argv[0]);
- exit(1);
+ printf("usage: %s [-o output_file] [-t seconds-per-file] server:port\n", argv[0]);
+ return 1;
}
- if(client->serverPort==-1)
- client->vncRec->doNotSleep = TRUE; /* vncrec playback */
-
- /* main loop */
+ /* main loop */
+ clock_gettime(CLOCK_MONOTONIC, &start_time);
while(!quit) {
- int i=WaitForMessage(client,1000000/STREAM_FRAME_RATE);
- if(i<0) {
- movie_close();
- return 0;
+ int i=WaitForMessage(client,10000/framerate); /* useful for timeout to be no more than 10 msec per second (=10000/framerate usec) */
+ if (i>0) {
+ if(!HandleRFBServerMessage(client))
+ quit=TRUE;
+ } else if (i<0) {
+ quit=TRUE;
}
- if(i)
- if(!HandleRFBServerMessage(client))
- quit=TRUE;
- else {
- /* compute current audio and video time */
- video_pts = (double)video_st->pts.val * video_st->time_base.num / video_st->time_base.den;
-
- /* write interleaved audio and video frames */
- write_video_frame(oc, video_st);
- }
- if(stop!=0 && stop<time(0))
- quit=TRUE;
+ if (!quit) {
+ clock_gettime(CLOCK_MONOTONIC, &cur_time);
+ write_video_frame(oc, &video_st, time_to_pts(framerate, &start_time, &cur_time));
+ if ((cur_time.tv_sec - start_time.tv_sec) > max_time && max_time > 0) {
+ quit = TRUE;
+ }
+ }
}
-
- movie_close();
+ movie_close(&oc,&video_st);
return 0;
}