Skip to content

Instantly share code, notes, and snippets.

@Arnold1
Last active January 12, 2019 21:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Arnold1/21d8df4d660cfd6e7e964d6217f94054 to your computer and use it in GitHub Desktop.
Save Arnold1/21d8df4d660cfd6e7e964d6217f94054 to your computer and use it in GitHub Desktop.
screen recording
#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(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;
}
T try_dequeue(bool &success, std::chrono::milliseconds timeout)
{
std::unique_lock<std::mutex> lock(m);
if (!c.wait_for(lock, timeout, [this] { return !q.empty(); })) {
success = false;
return nullptr;
}
T val = std::move(q.front());
q.pop();
success = true;
return val;
}
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<SL::Screen_Capture::Image> img;
data(int size_, int Width_, int Height_, std::unique_ptr<SL::Screen_Capture::Image> img_) {
size = size_;
Width = Width_;
Height = Height_;
img = std::move(img_);
}
};
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;
public:
ImgProcessor(double recordTime_) {
onNewFramestart = std::chrono::high_resolution_clock::now();
startTime = std::chrono::high_resolution_clock::now();
frame_num = 0;
recordTime = recordTime_;
}
void work() {
bool success = false;
unsigned int try_count = 4;
unsigned int count = 0;
bool can_exit = false;
while (true) {
//auto data = queue.dequeue();
auto data = queue.try_dequeue(success, std::chrono::milliseconds(100));
if (success) {
count = 0;
std::string s = std::to_string(frame_num);
s += ".jpg";
frame_num++;
auto imgbuffer(std::make_unique<unsigned char[]>(data->size));
ExtractAndConvertToRGBA(*data->img.get(), imgbuffer.get(), data->size);
tje_encode_to_file(("recording/" + s).c_str(), data->Width, data->Height, 4, (const unsigned char*)imgbuffer.get());
//delete data;
}
else {
count++;
if (count == try_count) {
can_exit = true;
}
}
//delete data;
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;
})
/*->onFrameChanged([&](const SL::Screen_Capture::Image &img, const SL::Screen_Capture::Monitor &monitor) {
// std::cout << "Difference detected! " << img.Bounds << std::endl;
auto r = realcounter.fetch_add(1);
auto s = std::to_string(r) + std::string("MONITORDIF_") + std::string(".jpg");
auto size = RowStride(img) * Height(img);
//auto imgbuffer(std::make_unique<unsigned char[]>(size));
//ExtractAndConvertToRGBA(img, imgbuffer.get(), size);
//tje_encode_to_file(("recording/" + s).c_str(), Width(img), Height(img), 4, (const unsigned char*)imgbuffer.get());
})*/
->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) {
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 imgbuffer(std::make_unique<unsigned char[]>(size));
//ExtractAndConvertToRGBA(img, imgbuffer.get(), size);
//tje_encode_to_file(("recording/" + s).c_str(), Width(img), Height(img), 4, (const unsigned char*)imgbuffer.get());
queue.enqueue(new data(size, Width(img), Height(img), std::make_unique<SL::Screen_Capture::Image>(img)));
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();
//std::this_thread::sleep_for(std::chrono::seconds(10));
processor.check_finished();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment