Last active
January 12, 2019 21:40
-
-
Save Arnold1/21d8df4d660cfd6e7e964d6217f94054 to your computer and use it in GitHub Desktop.
screen recording
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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