]> git.sesse.net Git - nageru/blob - cef_capture.cpp
Implement basic support for CEF.
[nageru] / cef_capture.cpp
1 #include <assert.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <chrono>
5 #include <memory>
6 #include <string>
7
8 #include "cef_capture.h"
9 #include "nageru_cef_app.h"
10
11 #undef CHECK
12 #include <cef_app.h>
13 #include <cef_browser.h>
14 #include <cef_client.h>
15
16 #include "bmusb/bmusb.h"
17
18 using namespace std;
19 using namespace std::chrono;
20 using namespace bmusb;
21
22 extern CefRefPtr<NageruCefApp> cef_app;
23
24 CEFCapture::CEFCapture(const string &url, unsigned width, unsigned height)
25         : cef_client(new NageruCEFClient(width, height, this)),
26           width(width),
27           height(height),
28           start_url(url)
29 {
30         char buf[256];
31         snprintf(buf, sizeof(buf), "CEF card %d", card_index + 1);
32         description = buf;
33 }
34
35 CEFCapture::~CEFCapture()
36 {
37         if (has_dequeue_callbacks) {
38                 dequeue_cleanup_callback();
39         }
40 }
41
42 void CEFCapture::OnPaint(const void *buffer, int width, int height)
43 {
44         steady_clock::time_point timestamp = steady_clock::now();
45
46         VideoFormat video_format;
47         video_format.width = width;
48         video_format.height = height;
49         video_format.stride = width * 4;
50         video_format.frame_rate_nom = 60;  // FIXME
51         video_format.frame_rate_den = 1;
52         video_format.has_signal = true;
53         video_format.is_connected = true;
54
55         FrameAllocator::Frame video_frame = video_frame_allocator->alloc_frame();
56         if (video_frame.data != nullptr) {
57                 assert(video_frame.size >= unsigned(width * height * 4));
58                 assert(!video_frame.interleaved);
59                 memcpy(video_frame.data, buffer, width * height * 4);
60                 video_frame.len = video_format.stride * height;
61                 video_frame.received_timestamp = timestamp;
62         }
63         frame_callback(timecode++,
64                 video_frame, 0, video_format,
65                 FrameAllocator::Frame(), 0, AudioFormat());
66 }
67
68 #define FRAME_SIZE (8 << 20)  // 8 MB.
69
70 void CEFCapture::configure_card()
71 {
72         if (video_frame_allocator == nullptr) {
73                 owned_video_frame_allocator.reset(new MallocFrameAllocator(FRAME_SIZE, NUM_QUEUED_VIDEO_FRAMES));
74                 set_video_frame_allocator(owned_video_frame_allocator.get());
75         }
76 }
77
78 void CEFCapture::start_bm_capture()
79 {
80         cef_app->initialize_cef();
81
82         CefBrowserSettings browser_settings;
83         browser_settings.web_security = cef_state_t::STATE_DISABLED;
84         browser_settings.webgl = cef_state_t::STATE_ENABLED;
85         browser_settings.windowless_frame_rate = 60;
86
87         CefWindowInfo window_info;
88         window_info.SetAsWindowless(0);
89         CefBrowserHost::CreateBrowser(window_info, cef_client, start_url, browser_settings, nullptr);
90 }
91
92 void CEFCapture::stop_dequeue_thread()
93 {
94         lock_guard<mutex> lock(browser_mutex);
95         cef_app->close_browser(browser);
96         browser = nullptr;  // Or unref_cef() will be sad.
97         cef_app->unref_cef();
98 }
99
100 std::map<uint32_t, VideoMode> CEFCapture::get_available_video_modes() const
101 {
102         VideoMode mode;
103
104         char buf[256];
105         snprintf(buf, sizeof(buf), "%ux%u", width, height);
106         mode.name = buf;
107
108         mode.autodetect = false;
109         mode.width = width;
110         mode.height = height;
111         mode.frame_rate_num = 60;  // FIXME
112         mode.frame_rate_den = 1;
113         mode.interlaced = false;
114
115         return {{ 0, mode }};
116 }
117
118 std::map<uint32_t, std::string> CEFCapture::get_available_video_inputs() const
119 {
120         return {{ 0, "HTML video input" }};
121 }
122
123 std::map<uint32_t, std::string> CEFCapture::get_available_audio_inputs() const
124 {
125         return {{ 0, "Fake HTML audio input (silence)" }};
126 }
127
128 void CEFCapture::set_video_mode(uint32_t video_mode_id)
129 {
130         assert(video_mode_id == 0);
131 }
132
133 void CEFCapture::set_video_input(uint32_t video_input_id)
134 {
135         assert(video_input_id == 0);
136 }
137
138 void CEFCapture::set_audio_input(uint32_t audio_input_id)
139 {
140         assert(audio_input_id == 0);
141 }
142
143 void NageruCEFClient::OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type, const RectList &dirtyRects, const void *buffer, int width, int height)
144 {
145         parent->OnPaint(buffer, width, height);
146 }
147
148 bool NageruCEFClient::GetViewRect(CefRefPtr<CefBrowser> browser, CefRect &rect)
149 {
150         rect = CefRect(0, 0, width, height);
151         return true;
152 }