diff --git a/src/zm_libvnc_camera.cpp b/src/zm_libvnc_camera.cpp index b18ebda97..9117d85cd 100644 --- a/src/zm_libvnc_camera.cpp +++ b/src/zm_libvnc_camera.cpp @@ -1,11 +1,7 @@ #include "zm.h" #include "zm_signal.h" #include "zm_libvnc_camera.h" -extern "C" { - #include - #include - #include -} +#include "zm_swscale.h" #if HAVE_LIBVNC @@ -25,6 +21,7 @@ static char* GetPasswordCallback(rfbClient* cl){ static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){ rfbCredential *c = (rfbCredential *)malloc(sizeof(rfbCredential)); if ( credentialType != rfbCredentialTypeUser ) { + free(c); return NULL; } @@ -68,6 +65,23 @@ VncCamera::VncCamera( mPass(pass) { Debug(2, "Host:%s Port: %s User: %s Pass:%s", mHost.c_str(), mPort.c_str(), mUser.c_str(), mPass.c_str()); + + if ( colours == ZM_COLOUR_RGB32 ) { + subpixelorder = ZM_SUBPIX_ORDER_RGBA; + mImgPixFmt = AV_PIX_FMT_RGBA; + mBpp = 4; + } else if ( colours == ZM_COLOUR_RGB24 ) { + subpixelorder = ZM_SUBPIX_ORDER_RGB; + mImgPixFmt = AV_PIX_FMT_RGB24; + mBpp = 3; + } else if ( colours == ZM_COLOUR_GRAY8 ) { + subpixelorder = ZM_SUBPIX_ORDER_NONE; + mImgPixFmt = AV_PIX_FMT_GRAY8; + mBpp = 1; + } else { + Panic("Unexpected colours: %d", colours); + } + if ( capture ) Initialise(); } @@ -94,6 +108,7 @@ void VncCamera::Initialise() { mRfb->serverHost = strdup(mHost.c_str()); mRfb->serverPort = atoi(mPort.c_str()); rfbInitClient(mRfb, 0, nullptr); + scale.init(); } void VncCamera::Terminate() { @@ -102,65 +117,20 @@ void VncCamera::Terminate() { int VncCamera::PrimeCapture() { Info("Priming capture from %s", mHost.c_str()); - if ( mRfb->si.framebufferWidth != width || mRfb->si.framebufferHeight != height ) { - Info("Expected screen resolution (%dx%d) does not match the provided resolution (%dx%d), using scaling", - width, height, mRfb->si.framebufferWidth, mRfb->si.framebufferHeight); - mScale = true; - sws = sws_getContext( - mRfb->si.framebufferWidth, mRfb->si.framebufferHeight, AV_PIX_FMT_RGBA, - width, height, AV_PIX_FMT_RGBA, SWS_BICUBIC, - NULL, NULL, NULL); - if ( !sws ) { - Error("Could not scale image"); - return -1; - } - } return 0; } int VncCamera::PreCapture() { Debug(2, "PreCapture"); WaitForMessage(mRfb, 500); - Debug(2, "After Wait "); rfbBool res = HandleRFBServerMessage(mRfb); - Debug(2, "After Handle "); return res == TRUE ? 1 : -1 ; } int VncCamera::Capture(Image &image) { Debug(2, "Capturing"); - int srcLineSize[4]; - int dstLineSize[4]; - int dstSize; - - if ( mScale ) { - uint8_t* directbuffer; - - /* Request a writeable buffer of the target image */ - directbuffer = image.WriteBuffer(width, height, colours, subpixelorder); - if ( directbuffer == NULL ) { - Error("Failed requesting writeable buffer for the captured image."); - return -1; - } - - if ( av_image_fill_arrays(dstbuf, dstLineSize, directbuffer, AV_PIX_FMT_RGBA, - width, height, 16) < 0) { - Error("Could not allocate dst image. Scaling failed"); - return -1; - } - - if ( av_image_fill_arrays(srcbuf, srcLineSize, mVncData.buffer, AV_PIX_FMT_RGBA, - mRfb->si.framebufferWidth, mRfb->si.framebufferHeight, 16) < 0) { - Error("Could not allocate source image. Scaling failed"); - return -1; - } - - sws_scale(sws, (const uint8_t* const*)srcbuf, srcLineSize, 0, mRfb->si.framebufferHeight, - dstbuf, dstLineSize); - - } else { - image.Assign(width, height, colours, subpixelorder, mVncData.buffer, width * height * 4); - } + uint8_t *directbuffer = image.WriteBuffer(width, height, colours, subpixelorder); + scale.Convert(mVncData.buffer, mRfb->si.framebufferHeight * mRfb->si.framebufferWidth * 4, directbuffer, width * height * mBpp, AV_PIX_FMT_RGBA, mImgPixFmt, mRfb->si.framebufferWidth, mRfb->si.framebufferHeight, width, height); return 1; } @@ -173,15 +143,6 @@ int VncCamera::CaptureAndRecord(Image &image, timeval recording, char* event_dir } int VncCamera::Close() { -#if HAVE_LIBSWSCALE - if ( mScale ) { - av_freep(&srcbuf[0]); - av_freep(&dstbuf[0]); - sws_freeContext(sws); - sws = NULL; - } -#endif - rfbClientCleanup(mRfb); return 0; } diff --git a/src/zm_libvnc_camera.h b/src/zm_libvnc_camera.h index 9502f8330..37525f35e 100644 --- a/src/zm_libvnc_camera.h +++ b/src/zm_libvnc_camera.h @@ -5,10 +5,17 @@ #include "zm_buffer.h" #include "zm_camera.h" #include "zm_thread.h" +#include "zm_swscale.h" #if HAVE_LIBVNC #include +extern "C" { + #include + #include + #include +} + // Used by vnc callbacks struct VncPrivateData { @@ -22,11 +29,8 @@ protected: rfbClient *mRfb; VncPrivateData mVncData; int mBpp; - int mSpp; - int mBps; - bool mScale; - uint8_t *srcbuf[4], *dstbuf[4]; - struct SwsContext *sws; + SWScale scale; + AVPixelFormat mImgPixFmt; std::string mHost; std::string mPort; std::string mUser; diff --git a/src/zm_swscale.cpp b/src/zm_swscale.cpp index 1e91029ad..04c37ace7 100644 --- a/src/zm_swscale.cpp +++ b/src/zm_swscale.cpp @@ -84,7 +84,7 @@ int SWScale::SetDefaults(enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, return 0; } -int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) { +int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height, unsigned int new_width, unsigned int new_height) { /* Parameter checking */ if(in_buffer == NULL || out_buffer == NULL) { Error("NULL Input or output buffer"); @@ -94,7 +94,7 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint // Error("Invalid input or output pixel formats"); // return -2; // } - if (!width || !height) { + if (!width || !height || !new_height || !new_width) { Error("Invalid width or height"); return -3; } @@ -111,7 +111,7 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint /* Check the buffer sizes */ #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) - size_t insize = av_image_get_buffer_size(in_pf, width, height,1); + size_t insize = av_image_get_buffer_size(in_pf, width, height, 1); #else size_t insize = avpicture_get_size(in_pf, width, height); #endif @@ -120,9 +120,9 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint return -4; } #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) - size_t outsize = av_image_get_buffer_size(out_pf, width, height,1); + size_t outsize = av_image_get_buffer_size(out_pf, new_width, new_height, 1); #else - size_t outsize = avpicture_get_size(out_pf, width, height); + size_t outsize = avpicture_get_size(out_pf, new_width, new_height); #endif if(outsize < out_buffer_size) { @@ -131,7 +131,7 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint } /* Get the context */ - swscale_ctx = sws_getCachedContext( swscale_ctx, width, height, in_pf, width, height, out_pf, SWS_FAST_BILINEAR, NULL, NULL, NULL ); + swscale_ctx = sws_getCachedContext( swscale_ctx, width, height, in_pf, new_width, new_height, out_pf, SWS_FAST_BILINEAR, NULL, NULL, NULL ); if(swscale_ctx == NULL) { Error("Failed getting swscale context"); return -6; @@ -150,10 +150,10 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint } #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) if (av_image_fill_arrays(output_avframe->data, output_avframe->linesize, - out_buffer, out_pf, width, height, 1) <= 0) { + out_buffer, out_pf, new_width, new_height, 1) <= 0) { #else - if (avpicture_fill((AVPicture*) output_avframe, out_buffer, out_pf, width, - height) <= 0) { + if (avpicture_fill((AVPicture*) output_avframe, out_buffer, out_pf, new_width, + new_height) <= 0) { #endif Error("Failed filling output frame with output buffer"); return -8; @@ -168,6 +168,10 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint return 0; } +int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) { + return Convert(in_buffer, in_buffer_size, out_buffer, out_buffer_size, in_pf, out_pf, width, height, width, height); +} + int SWScale::Convert(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) { if(img->Width() != width) { Error("Source image width differs. Source: %d Output: %d",img->Width(), width); diff --git a/src/zm_swscale.h b/src/zm_swscale.h index 62f99e342..4d559b4fc 100644 --- a/src/zm_swscale.h +++ b/src/zm_swscale.h @@ -10,13 +10,14 @@ class SWScale { public: SWScale(); ~SWScale(); - bool init(); + bool init(); int SetDefaults(enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height); int ConvertDefaults(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size); int ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size); int Convert(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height); int Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height); - + int Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height, unsigned int new_width, unsigned int new_height); + protected: bool gotdefaults; struct SwsContext* swscale_ctx;