From 00e07cb737abf48bb7b044849d88993ba2a1b4e2 Mon Sep 17 00:00:00 2001 From: Scott Date: Sat, 2 Jun 2018 10:27:30 -0700 Subject: [PATCH] moved window and monitor to public api --- include/ScreenCapture.h | 306 +++++++++++++++++++----------------- include/internal/SCCommon.h | 241 +++++++++++++--------------- 2 files changed, 270 insertions(+), 277 deletions(-) diff --git a/include/ScreenCapture.h b/include/ScreenCapture.h index dfdc05a2..af3f8eaa 100644 --- a/include/ScreenCapture.h +++ b/include/ScreenCapture.h @@ -19,150 +19,174 @@ #endif namespace SL { - namespace Screen_Capture { - struct Point; - struct Monitor; - struct Window; - struct Image; - struct ImageBGRA { - unsigned char B,G,R,A; - }; - - // index to self in the GetMonitors() function - SC_LITE_EXTERN int Index(const Monitor &mointor); - // unique identifier - SC_LITE_EXTERN int Id(const Monitor &mointor); - SC_LITE_EXTERN int Adapter(const Monitor &mointor); - SC_LITE_EXTERN int OffsetX(const Monitor &mointor); - SC_LITE_EXTERN int OffsetY(const Monitor &mointor); - SC_LITE_EXTERN void OffsetX(Monitor &mointor, int x); - SC_LITE_EXTERN void OffsetY(Monitor &mointor, int y); - SC_LITE_EXTERN int OffsetX(const Window &mointor); - SC_LITE_EXTERN int OffsetY(const Window &mointor); - SC_LITE_EXTERN void OffsetX(Window &mointor, int x); - SC_LITE_EXTERN void OffsetY(Window &mointor, int y); - SC_LITE_EXTERN const char *Name(const Monitor &mointor); - SC_LITE_EXTERN const char *Name(const Window &mointor); - SC_LITE_EXTERN int Height(const Monitor &mointor); - SC_LITE_EXTERN int Width(const Monitor &mointor); - SC_LITE_EXTERN void Height(Monitor &mointor, int h); - SC_LITE_EXTERN void Width(Monitor &mointor, int w); - SC_LITE_EXTERN int Height(const Window &mointor); - SC_LITE_EXTERN int Width(const Window &mointor); - SC_LITE_EXTERN void Height(Window &mointor, int h); - SC_LITE_EXTERN void Width(Window &mointor, int w); - SC_LITE_EXTERN int Height(const Image &img); - SC_LITE_EXTERN int Width(const Image &img); - SC_LITE_EXTERN int X(const Point &p); - SC_LITE_EXTERN int Y(const Point &p); - - // the start of the image data, this is not guarenteed to be contiguous. - SC_LITE_EXTERN const ImageBGRA *StartSrc(const Image &img); - SC_LITE_EXTERN const ImageBGRA *GotoNextRow(const Image &img, const ImageBGRA* current); - SC_LITE_EXTERN bool isDataContiguous(const Image &img); - /* - this is the ONLY funcion for pulling data out of the Image object and is layed out here in the header so that - users can see how to extra data and convert it to their own needed format. Initially, I included custom extract functions - but this is beyond the scope of this library. You must copy the image data if you want to use it as the library owns the Image Data. - */ - inline void Extract(const Image &img, unsigned char *dst, size_t dst_size) - { - assert(dst_size >= static_cast(Width(img) * Height(img) * sizeof(ImageBGRA))); - auto startdst = dst; - auto startsrc = StartSrc(img); - if (isDataContiguous(img)) { // no padding, the entire copy can be a single memcpy call - memcpy(startdst, startsrc, Width(img) * Height(img) * sizeof(ImageBGRA)); - } - else { - for (auto i = 0; i < Height(img); i++) { - memcpy(startdst, startsrc, sizeof(ImageBGRA) * Width(img)); - startdst += sizeof(ImageBGRA) * Width(img); // advance to the next row - startsrc = GotoNextRow(img, startsrc); // advance to the next row - } +namespace Screen_Capture { + struct SC_LITE_EXTERN Point { + int x; + int y; + }; + struct SC_LITE_EXTERN Window { + size_t Handle; + Point Position; + + Point Size; + // Name will always be lower case. It is converted to lower case internally by the library for comparisons + char Name[128] = {0}; + }; + struct SC_LITE_EXTERN Monitor { + int Id = INT32_MAX; + int Index = INT32_MAX; + int Adapter = INT32_MAX; + int Height = 0; + int Width = 0; + int OriginalHeight = 0; + int OriginalWidth = 0; + // Offsets are the number of pixels that a monitor can be from the origin. For example, users can shuffle their + // monitors around so this affects their offset. + int OffsetX = 0; + int OffsetY = 0; + int OriginalOffsetX = 0; + int OriginalOffsetY = 0; + char Name[128] = {0}; + float Scaling = 1.0f; + }; + + struct Image; + struct ImageBGRA { + unsigned char B, G, R, A; + }; + + // index to self in the GetMonitors() function + SC_LITE_EXTERN int Index(const Monitor &mointor); + // unique identifier + SC_LITE_EXTERN int Id(const Monitor &mointor); + SC_LITE_EXTERN int Adapter(const Monitor &mointor); + SC_LITE_EXTERN int OffsetX(const Monitor &mointor); + SC_LITE_EXTERN int OffsetY(const Monitor &mointor); + SC_LITE_EXTERN void OffsetX(Monitor &mointor, int x); + SC_LITE_EXTERN void OffsetY(Monitor &mointor, int y); + SC_LITE_EXTERN int OffsetX(const Window &mointor); + SC_LITE_EXTERN int OffsetY(const Window &mointor); + SC_LITE_EXTERN void OffsetX(Window &mointor, int x); + SC_LITE_EXTERN void OffsetY(Window &mointor, int y); + SC_LITE_EXTERN const char *Name(const Monitor &mointor); + SC_LITE_EXTERN const char *Name(const Window &mointor); + SC_LITE_EXTERN int Height(const Monitor &mointor); + SC_LITE_EXTERN int Width(const Monitor &mointor); + SC_LITE_EXTERN void Height(Monitor &mointor, int h); + SC_LITE_EXTERN void Width(Monitor &mointor, int w); + SC_LITE_EXTERN int Height(const Window &mointor); + SC_LITE_EXTERN int Width(const Window &mointor); + SC_LITE_EXTERN void Height(Window &mointor, int h); + SC_LITE_EXTERN void Width(Window &mointor, int w); + SC_LITE_EXTERN int Height(const Image &img); + SC_LITE_EXTERN int Width(const Image &img); + SC_LITE_EXTERN int X(const Point &p); + SC_LITE_EXTERN int Y(const Point &p); + + // the start of the image data, this is not guarenteed to be contiguous. + SC_LITE_EXTERN const ImageBGRA *StartSrc(const Image &img); + SC_LITE_EXTERN const ImageBGRA *GotoNextRow(const Image &img, const ImageBGRA *current); + SC_LITE_EXTERN bool isDataContiguous(const Image &img); + /* + this is the ONLY funcion for pulling data out of the Image object and is layed out here in the header so that + users can see how to extra data and convert it to their own needed format. Initially, I included custom extract functions + but this is beyond the scope of this library. You must copy the image data if you want to use it as the library owns the Image Data. + */ + inline void Extract(const Image &img, unsigned char *dst, size_t dst_size) + { + assert(dst_size >= static_cast(Width(img) * Height(img) * sizeof(ImageBGRA))); + auto startdst = dst; + auto startsrc = StartSrc(img); + if (isDataContiguous(img)) { // no padding, the entire copy can be a single memcpy call + memcpy(startdst, startsrc, Width(img) * Height(img) * sizeof(ImageBGRA)); + } + else { + for (auto i = 0; i < Height(img); i++) { + memcpy(startdst, startsrc, sizeof(ImageBGRA) * Width(img)); + startdst += sizeof(ImageBGRA) * Width(img); // advance to the next row + startsrc = GotoNextRow(img, startsrc); // advance to the next row } } + } - class Timer { - using Clock = std::conditional< - std::chrono::high_resolution_clock::is_steady, - std::chrono::high_resolution_clock, - std::chrono::steady_clock - >::type; - - std::chrono::microseconds Duration; - Clock::time_point Deadline; - - public: - template - Timer(const std::chrono::duration &duration) - : Duration(std::chrono::duration_cast(duration)) - , Deadline(Clock::now() + Duration) - {} - void start() { Deadline = Clock::now() + Duration; } - void wait() - { - const auto now = Clock::now(); - if (now < Deadline) { - std::this_thread::sleep_for(Deadline - now); - } - } - std::chrono::microseconds duration() const { return Duration;} - }; - // will return all attached monitors - SC_LITE_EXTERN std::vector GetMonitors(); - // will return all windows - SC_LITE_EXTERN std::vector GetWindows(); - - typedef std::function WindowCaptureCallback; - typedef std::function ScreenCaptureCallback; - typedef std::function MouseCallback; - typedef std::function()> MonitorCallback; - typedef std::function()> WindowCallback; - - class SC_LITE_EXTERN IScreenCaptureManager { - public: - virtual ~IScreenCaptureManager() {} - - // Used by the library to determine the callback frequency - template void setFrameChangeInterval(const std::chrono::duration &rel_time) - { - setFrameChangeInterval(std::make_shared(rel_time)); - } - // Used by the library to determine the callback frequency - template void setMouseChangeInterval(const std::chrono::duration &rel_time) - { - setMouseChangeInterval(std::make_shared(rel_time)); + class Timer { + using Clock = + std::conditional::type; + + std::chrono::microseconds Duration; + Clock::time_point Deadline; + + public: + template + Timer(const std::chrono::duration &duration) + : Duration(std::chrono::duration_cast(duration)), Deadline(Clock::now() + Duration) + { + } + void start() { Deadline = Clock::now() + Duration; } + void wait() + { + const auto now = Clock::now(); + if (now < Deadline) { + std::this_thread::sleep_for(Deadline - now); } + } + std::chrono::microseconds duration() const { return Duration; } + }; + // will return all attached monitors + SC_LITE_EXTERN std::vector GetMonitors(); + // will return all windows + SC_LITE_EXTERN std::vector GetWindows(); + + typedef std::function WindowCaptureCallback; + typedef std::function ScreenCaptureCallback; + typedef std::function MouseCallback; + typedef std::function()> MonitorCallback; + typedef std::function()> WindowCallback; + + class SC_LITE_EXTERN IScreenCaptureManager { + public: + virtual ~IScreenCaptureManager() {} + + // Used by the library to determine the callback frequency + template void setFrameChangeInterval(const std::chrono::duration &rel_time) + { + setFrameChangeInterval(std::make_shared(rel_time)); + } + // Used by the library to determine the callback frequency + template void setMouseChangeInterval(const std::chrono::duration &rel_time) + { + setMouseChangeInterval(std::make_shared(rel_time)); + } + + virtual void setFrameChangeInterval(const std::shared_ptr &timer) = 0; + virtual void setMouseChangeInterval(const std::shared_ptr &timer) = 0; + + // Will pause all capturing + virtual void pause() = 0; + // Will return whether the library is paused + virtual bool isPaused() const = 0; + // Will resume all capturing if paused, otherwise has no effect + virtual void resume() = 0; + }; + + template class ICaptureConfiguration { + public: + virtual ~ICaptureConfiguration() {} + // When a new frame is available the callback is invoked + virtual std::shared_ptr> onNewFrame(const CAPTURECALLBACK &cb) = 0; + // When a change in a frame is detected, the callback is invoked + virtual std::shared_ptr> onFrameChanged(const CAPTURECALLBACK &cb) = 0; + // When a mouse image changes or the mouse changes position, the callback is invoked. + virtual std::shared_ptr> onMouseChanged(const MouseCallback &cb) = 0; + // start capturing + virtual std::shared_ptr start_capturing() = 0; + }; - virtual void setFrameChangeInterval(const std::shared_ptr &timer) = 0; - virtual void setMouseChangeInterval(const std::shared_ptr &timer) = 0; - - // Will pause all capturing - virtual void pause() = 0; - // Will return whether the library is paused - virtual bool isPaused() const = 0; - // Will resume all capturing if paused, otherwise has no effect - virtual void resume() = 0; - }; - - template class ICaptureConfiguration { - public: - virtual ~ICaptureConfiguration() {} - // When a new frame is available the callback is invoked - virtual std::shared_ptr> onNewFrame(const CAPTURECALLBACK &cb) = 0; - // When a change in a frame is detected, the callback is invoked - virtual std::shared_ptr> onFrameChanged(const CAPTURECALLBACK &cb) = 0; - // When a mouse image changes or the mouse changes position, the callback is invoked. - virtual std::shared_ptr> onMouseChanged(const MouseCallback &cb) = 0; - // start capturing - virtual std::shared_ptr start_capturing() = 0; - }; - - // the callback of windowstocapture represents the list of monitors which should be captured. Users should return the list of monitors they want - // to be captured - SC_LITE_EXTERN std::shared_ptr> CreateCaptureConfiguration(const MonitorCallback &monitorstocapture); - // the callback of windowstocapture represents the list of windows which should be captured. Users should return the list of windows they want to - // be captured - SC_LITE_EXTERN std::shared_ptr> CreateCaptureConfiguration(const WindowCallback &windowstocapture); - } // namespace Screen_Capture + // the callback of windowstocapture represents the list of monitors which should be captured. Users should return the list of monitors they want + // to be captured + SC_LITE_EXTERN std::shared_ptr> CreateCaptureConfiguration(const MonitorCallback &monitorstocapture); + // the callback of windowstocapture represents the list of windows which should be captured. Users should return the list of windows they want to + // be captured + SC_LITE_EXTERN std::shared_ptr> CreateCaptureConfiguration(const WindowCallback &windowstocapture); +} // namespace Screen_Capture } // namespace SL diff --git a/include/internal/SCCommon.h b/include/internal/SCCommon.h index 1293a51e..d4e20baf 100644 --- a/include/internal/SCCommon.h +++ b/include/internal/SCCommon.h @@ -5,154 +5,123 @@ // this is INTERNAL DO NOT USE! namespace SL { - namespace Screen_Capture { - struct Point { - int x; - int y; - }; - struct Monitor { - int Id = INT32_MAX; - int Index = INT32_MAX; - int Adapter = INT32_MAX; - int Height = 0; - int Width = 0; - int OriginalHeight = 0; - int OriginalWidth = 0; - // Offsets are the number of pixels that a monitor can be from the origin. For example, users can shuffle their - // monitors around so this affects their offset. - int OffsetX = 0; - int OffsetY = 0; - int OriginalOffsetX = 0; - int OriginalOffsetY = 0; - char Name[128] = { 0 }; - float Scaling = 1.0f; - }; +namespace Screen_Capture { + struct ImageRect { + ImageRect() : ImageRect(0, 0, 0, 0) {} + ImageRect(int l, int t, int r, int b) : left(l), top(t), right(r), bottom(b) {} + int left; + int top; + int right; + int bottom; + bool Contains(const ImageRect &a) const { return left <= a.left && right >= a.right && top <= a.top && bottom >= a.bottom; } + }; + struct Image { + ImageRect Bounds; + int BytesToNextRow = 0; + bool isContiguous = false; + // alpha is always unused and might contain garbage + const ImageBGRA *Data = nullptr; + }; - struct Window { - size_t Handle; - Point Position; - - Point Size; - // Name will always be lower case. It is converted to lower case internally by the library for comparisons - char Name[128] = { 0 }; - }; - struct ImageRect { - ImageRect() : ImageRect(0, 0, 0, 0) {} - ImageRect(int l, int t, int r, int b) :left(l), top(t), right(r), bottom(b) {} - int left; - int top; - int right; - int bottom; - bool Contains(const ImageRect &a) const { return left <= a.left && right >= a.right && top <= a.top && bottom >= a.bottom; } - }; - struct Image { - ImageRect Bounds; - int BytesToNextRow = 0; - bool isContiguous = false; - // alpha is always unused and might contain garbage - const ImageBGRA *Data = nullptr; - }; + inline bool operator==(const ImageRect &a, const ImageRect &b) + { + return b.left == a.left && b.right == a.right && b.top == a.top && b.bottom == a.bottom; + } + int Height(const ImageRect &rect); + int Width(const ImageRect &rect); + const ImageRect &Rect(const Image &img); - inline bool operator==(const ImageRect &a, const ImageRect &b) - { - return b.left == a.left && b.right == a.right && b.top == a.top && b.bottom == a.bottom; - } - int Height(const ImageRect &rect); - int Width(const ImageRect &rect); - const ImageRect &Rect(const Image &img); + template struct CaptureData { + std::shared_ptr FrameTimer; + F OnNewFrame; + F OnFrameChanged; + std::shared_ptr MouseTimer; + M OnMouseChanged; + W getThingsToWatch; + }; + struct CommonData { + // Used to indicate abnormal error condition + std::atomic UnexpectedErrorEvent; + // Used to indicate a transition event occurred e.g. PnpStop, PnpStart, mode change, TDR, desktop switch and the application needs to recreate + // the duplication interface + std::atomic ExpectedErrorEvent; + // Used to signal to threads to exit + std::atomic TerminateThreadsEvent; + std::atomic Paused; + }; + struct Thread_Data { - template struct CaptureData { - std::shared_ptr FrameTimer; - F OnNewFrame; - F OnFrameChanged; - std::shared_ptr MouseTimer; - M OnMouseChanged; - W getThingsToWatch; - }; - struct CommonData { - // Used to indicate abnormal error condition - std::atomic UnexpectedErrorEvent; - // Used to indicate a transition event occurred e.g. PnpStop, PnpStart, mode change, TDR, desktop switch and the application needs to recreate - // the duplication interface - std::atomic ExpectedErrorEvent; - // Used to signal to threads to exit - std::atomic TerminateThreadsEvent; - std::atomic Paused; - }; - struct Thread_Data { + CaptureData ScreenCaptureData; + CaptureData WindowCaptureData; + CommonData CommonData_; + }; - CaptureData ScreenCaptureData; - CaptureData WindowCaptureData; - CommonData CommonData_; - }; + class BaseFrameProcessor { + public: + std::shared_ptr Data; + std::unique_ptr ImageBuffer; + int ImageBufferSize = 0; + bool FirstRun = true; + }; - class BaseFrameProcessor { - public: - std::shared_ptr Data; - std::unique_ptr ImageBuffer; - int ImageBufferSize = 0; - bool FirstRun = true; - }; + enum DUPL_RETURN { DUPL_RETURN_SUCCESS = 0, DUPL_RETURN_ERROR_EXPECTED = 1, DUPL_RETURN_ERROR_UNEXPECTED = 2 }; + Monitor CreateMonitor(int index, int id, int h, int w, int ox, int oy, const std::string &n, float scale); + Monitor CreateMonitor(int index, int id, int adapter, int h, int w, int ox, int oy, const std::string &n, float scale); + SC_LITE_EXTERN bool isMonitorInsideBounds(const std::vector &monitors, const Monitor &monitor); + SC_LITE_EXTERN Image CreateImage(const ImageRect &imgrect, int rowpadding, const ImageBGRA *data); + // this function will copy data from the src into the dst. The only requirement is that src must not be larger than dst, but it can be smaller + // void Copy(const Image& dst, const Image& src); - enum DUPL_RETURN { DUPL_RETURN_SUCCESS = 0, DUPL_RETURN_ERROR_EXPECTED = 1, DUPL_RETURN_ERROR_UNEXPECTED = 2 }; - Monitor CreateMonitor(int index, int id, int h, int w, int ox, int oy, const std::string &n, float scale); - Monitor CreateMonitor(int index, int id, int adapter, int h, int w, int ox, int oy, const std::string &n, float scale); - SC_LITE_EXTERN bool isMonitorInsideBounds(const std::vector &monitors, const Monitor &monitor); - SC_LITE_EXTERN Image CreateImage(const ImageRect &imgrect, int rowpadding, const ImageBGRA *data); - // this function will copy data from the src into the dst. The only requirement is that src must not be larger than dst, but it can be smaller - // void Copy(const Image& dst, const Image& src); - - SC_LITE_EXTERN std::vector GetDifs(const Image &oldimg, const Image &newimg); - template void ProcessCapture(const F &data, T &base, const C &mointor, - const unsigned char * startsrc, - int srcrowstride - ) { - ImageRect imageract; - imageract.left = 0; - imageract.top = 0; - imageract.bottom = Height(mointor); - imageract.right = Width(mointor); - const auto sizeofimgbgra = static_cast(sizeof(ImageBGRA)); - const auto startimgsrc = reinterpret_cast(startsrc); - auto dstrowstride = sizeofimgbgra * Width(mointor); - if (data.OnNewFrame) {//each frame we still let the caller know if asked for - auto wholeimg = CreateImage(imageract, srcrowstride, startimgsrc); + SC_LITE_EXTERN std::vector GetDifs(const Image &oldimg, const Image &newimg); + template + void ProcessCapture(const F &data, T &base, const C &mointor, const unsigned char *startsrc, int srcrowstride) + { + ImageRect imageract; + imageract.left = 0; + imageract.top = 0; + imageract.bottom = Height(mointor); + imageract.right = Width(mointor); + const auto sizeofimgbgra = static_cast(sizeof(ImageBGRA)); + const auto startimgsrc = reinterpret_cast(startsrc); + auto dstrowstride = sizeofimgbgra * Width(mointor); + if (data.OnNewFrame) { // each frame we still let the caller know if asked for + auto wholeimg = CreateImage(imageract, srcrowstride, startimgsrc); + wholeimg.isContiguous = dstrowstride == srcrowstride; + data.OnNewFrame(wholeimg, mointor); + } + if (data.OnFrameChanged) { // difs are needed! + if (base.FirstRun) { + // first time through, just send the whole image + auto wholeimg = CreateImage(imageract, srcrowstride, startimgsrc); wholeimg.isContiguous = dstrowstride == srcrowstride; - data.OnNewFrame(wholeimg, mointor); + data.OnFrameChanged(wholeimg, mointor); + base.FirstRun = false; } - if (data.OnFrameChanged) {//difs are needed! - if (base.FirstRun) { - // first time through, just send the whole image - auto wholeimg = CreateImage(imageract, srcrowstride, startimgsrc); - wholeimg.isContiguous = dstrowstride == srcrowstride; - data.OnFrameChanged(wholeimg, mointor); - base.FirstRun = false; - } - else { - // user wants difs, lets do it! - auto newimg = CreateImage(imageract, srcrowstride - dstrowstride, startimgsrc); - auto oldimg = CreateImage(imageract, 0, reinterpret_cast(base.ImageBuffer.get())); - auto imgdifs = GetDifs(oldimg, newimg); + else { + // user wants difs, lets do it! + auto newimg = CreateImage(imageract, srcrowstride - dstrowstride, startimgsrc); + auto oldimg = CreateImage(imageract, 0, reinterpret_cast(base.ImageBuffer.get())); + auto imgdifs = GetDifs(oldimg, newimg); - for (auto &r : imgdifs) { - auto leftoffset = r.left * sizeofimgbgra; - auto thisstartsrc = startsrc + leftoffset + (r.top * srcrowstride); + for (auto &r : imgdifs) { + auto leftoffset = r.left * sizeofimgbgra; + auto thisstartsrc = startsrc + leftoffset + (r.top * srcrowstride); - auto difimg = CreateImage(r, srcrowstride, reinterpret_cast(thisstartsrc)); - difimg.isContiguous = false; - data.OnFrameChanged(difimg, mointor); - } + auto difimg = CreateImage(r, srcrowstride, reinterpret_cast(thisstartsrc)); + difimg.isContiguous = false; + data.OnFrameChanged(difimg, mointor); } - auto startdst = base.ImageBuffer.get(); - if (dstrowstride == srcrowstride) { // no need for multiple calls, there is no padding here - memcpy(startdst, startsrc, dstrowstride * Height(mointor)); - } - else { - for (auto i = 0; i < Height(mointor); i++) { - memcpy(startdst + (i * dstrowstride), startsrc + (i * srcrowstride), dstrowstride); - } + } + auto startdst = base.ImageBuffer.get(); + if (dstrowstride == srcrowstride) { // no need for multiple calls, there is no padding here + memcpy(startdst, startsrc, dstrowstride * Height(mointor)); + } + else { + for (auto i = 0; i < Height(mointor); i++) { + memcpy(startdst + (i * dstrowstride), startsrc + (i * srcrowstride), dstrowstride); } } } - } // namespace Screen_Capture + } +} // namespace Screen_Capture } // namespace SL