Skip to content

Instantly share code, notes, and snippets.

@Arnold1
Last active October 29, 2017 19:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Arnold1/d6ad302384f788cba3e6c9b6b1a14fa0 to your computer and use it in GitHub Desktop.
Save Arnold1/d6ad302384f788cba3e6c9b6b1a14fa0 to your computer and use it in GitHub Desktop.
screen capture
#include "ScreenCapture.h"
#include <algorithm>
#include <atomic>
#include <chrono>
#include <iostream>
#include <locale>
#include <string>
#include <thread>
#include <vector>
#include <queue>
// THESE LIBRARIES ARE HERE FOR CONVINIENCE!! They are SLOW and ONLY USED FOR
// HOW THE LIBRARY WORKS!
#define TJE_IMPLEMENTATION
#include "tiny_jpeg.h"
#define LODEPNG_COMPILE_PNG
#define LODEPNG_COMPILE_DISK
#include "lodepng.h"
/////////////////////////////////////////////////////////////////////////
using namespace std::chrono_literals;
std::shared_ptr<SL::Screen_Capture::IScreenCaptureManager> framgrabber;
std::atomic<int> realcounter;
std::atomic<int> onNewFramecounter;
inline std::ostream &operator<<(std::ostream &os, const SL::Screen_Capture::ImageRect &p)
{
return os << "left=" << p.left << " top=" << p.top << " right=" << p.right << " bottom=" << p.bottom;
}
inline std::ostream &operator<<(std::ostream &os, const SL::Screen_Capture::Monitor &p)
{
return os << "Id=" << p.Id << " Index=" << p.Index << " Height=" << p.Height << " Width=" << p.Width << " OffsetX=" << p.OffsetX
<< " OffsetY=" << p.OffsetY << " Name=" << p.Name;
}
template <class T>
class SafeQueue
{
public:
SafeQueue(void)
: q()
, m()
, c()
{}
~SafeQueue(void)
{}
void enqueue(T&& t)
{
{
std::lock_guard<std::mutex> lock(m);
q.push(std::move(t));
}
c.notify_one();
}
/*void enqueue(T t)
{
{
std::lock_guard<std::mutex> lock(m);
q.push(t);
}
c.notify_one();
}*/
T dequeue(void)
{
std::unique_lock<std::mutex> lock(m);
while (q.empty())
{
c.wait(lock);
}
T val = q.front();
q.pop();
return val;
}
bool try_dequeue(T &d, std::chrono::milliseconds timeout)
{
std::unique_lock<std::mutex> lock(m);
if (!c.wait_for(lock, timeout, [this] { return !q.empty(); })) {
return false;
}
d = std::move(q.front());
q.pop();
return true;
}
private:
std::queue<T> q;
mutable std::mutex m;
std::condition_variable c;
};
class data {
public:
int size;
int Width;
int Height;
std::unique_ptr<unsigned char[]> img;
data() {
}
data(int size_, int Width_, int Height_, std::unique_ptr<unsigned char[]> img_) {
size = size_;
Width = Width_;
Height = Height_;
img = std::move(img_);
}
data(const data&) = delete;
data(data&& other) {
size = other.size;
Width = other.Width;
Height = other.Height;
img = std::move(other.img);
}
data& operator=(data&& other) {
if (this != &other) {
size = other.size;
Width = other.Width;
Height = other.Height;
img = std::move(other.img);
}
return *this;
}
};
const int size = 20736000;
class BufferType {
public:
std::unique_ptr<unsigned char[]> buf;
BufferType() {
buf = (std::make_unique<unsigned char[]>(size));
}
};
const int NUMBUFFERS = 300;
class ImgProcessor {
private:
SafeQueue<data> queue;
std::chrono::time_point<std::chrono::high_resolution_clock> onNewFramestart;
std::chrono::time_point<std::chrono::high_resolution_clock> startTime;
double recordTime; // ms
int frame_num;
std::thread t1;
std::vector<BufferType> myBuffers;
public:
ImgProcessor(double recordTime_): myBuffers(NUMBUFFERS) {
onNewFramestart = std::chrono::high_resolution_clock::now();
startTime = std::chrono::high_resolution_clock::now();
frame_num = 0;
recordTime = recordTime_;
}
void work() {
unsigned int try_count = 4;
unsigned int count = 0;
bool can_exit = false;
while (true) {
data d;
auto success = queue.try_dequeue(d, std::chrono::milliseconds(100));
if (success) {
count = 0;
std::string s = std::to_string(frame_num);
s += ".jpg";
frame_num++;
tje_encode_to_file(("recording/" + s).c_str(), d.Width, d.Height, 4, (const unsigned char*)d.img.get());
}
else {
count++;
if (count == try_count) {
can_exit = true;
}
}
if (can_exit) {
break;
}
}
std::cout << "thread finished..." << std::endl;
}
void createframegrabber()
{
realcounter = 0;
onNewFramecounter = 0;
framgrabber =
SL::Screen_Capture::CreateCaptureConfiguration([]() {
auto mons = SL::Screen_Capture::GetMonitors();
std::cout << "Library is requesting the list of monitors to capture!" << std::endl;
for (auto &m : mons) {
// capture just a 512x512 square... USERS SHOULD MAKE SURE bounds are
// valid!!!!
/*
m.OffsetX += 512;
m.OffsetY += 512;
m.Height = 512;
m.Width = 512;
*/
std::cout << m << std::endl;
}
return mons;
})
->onNewFrame([&](const SL::Screen_Capture::Image &img, const SL::Screen_Capture::Monitor &monitor) {
if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - startTime).count() >= recordTime) {
framgrabber->pause();
return;
}
//auto r = realcounter.fetch_add(1);
//auto s = std::to_string(r) + std::string("MONITORNEW_") + std::string(".jpg");
auto size = RowStride(img) * Height(img);
auto start = std::chrono::high_resolution_clock::now();
std::unique_ptr<unsigned char[]> imgbuffer{new unsigned char[size]};
memcpy(imgbuffer.get(), StartSrc(img), RowStride(img) * Height(img));
queue.enqueue(data(size, Width(img), Height(img), std::move(imgbuffer)));
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start).count() << std::endl;
if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - onNewFramestart).count() >=
1000) {
std::cout << "onNewFrame fps" << onNewFramecounter << std::endl;
onNewFramecounter = 0;
onNewFramestart = std::chrono::high_resolution_clock::now();
}
onNewFramecounter += 1;
})
/*->onMouseChanged([&](const SL::Screen_Capture::Image *img, const SL::Screen_Capture::Point &point) {
auto r = realcounter.fetch_add(1);
auto s = std::to_string(r) + std::string(" M") + std::string(".png");
if (img) {
// std::cout << "New mouse coordinates AND NEW Image received." << " x= " << point.x << " y= " <<
// point.y << std::endl;
// lodepng::encode(s,StartSrc(*img), Width(*img), Height(*img));
}
else {
// std::cout << "New mouse coordinates received." << " x= " << point.x << " y= " << point.y << " The
// mouse image is still the same
// as the last" << std::endl;
}
})*/
->start_capturing();
//framgrabber->setFrameChangeInterval(std::chrono::milliseconds(100));
framgrabber->setFrameChangeInterval(std::chrono::milliseconds(33));
framgrabber->setMouseChangeInterval(std::chrono::milliseconds(100));
t1 = std::thread(&ImgProcessor::work, this);
}
void check_finished() {
t1.join();
}
};
int main()
{
std::cout << "Starting Capture Demo/Test" << std::endl;
std::cout << "Testing captured monitor bounds check" << std::endl;
auto goodmonitors = SL::Screen_Capture::GetMonitors();
for (auto &m : goodmonitors) {
std::cout << m << std::endl;
assert(isMonitorInsideBounds(goodmonitors, m));
}
auto badmonitors = SL::Screen_Capture::GetMonitors();
for (auto m : badmonitors) {
m.Height += 1;
std::cout << m << std::endl;
assert(!isMonitorInsideBounds(goodmonitors, m));
}
for (auto m : badmonitors) {
m.Width += 1;
std::cout << m << std::endl;
assert(!isMonitorInsideBounds(goodmonitors, m));
}
ImgProcessor processor(10000);
std::cout << "Changing the cpature rate to 33 milli second" << std::endl;
processor.createframegrabber();
//framgrabber->setFrameChangeInterval(std::chrono::microseconds(33000));
//std::this_thread::sleep_for(std::chrono::seconds(10));
//framgrabber->pause();
processor.check_finished();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment