pull/3471/head
kallaballa 2 years ago
parent 2d55d08724
commit 14fe78b61c
  1. 34
      modules/v4d/CMakeLists.txt
  2. 4
      modules/v4d/samples/example_v4d_beauty-demo.html
  3. 35
      modules/v4d/samples/example_v4d_video-demo.html
  4. 2
      modules/v4d/src/detail/framebuffercontext.cpp
  5. 202
      modules/v4d/src/util.cpp

@ -49,7 +49,7 @@ macro(add_binary_sample sample)
endmacro() endmacro()
if(EMSCRIPTEN) if(EMSCRIPTEN)
set(EM_LINKER_FLAGS "-sENVIRONMENT=web,worker -sOFFSCREENCANVAS_SUPPORT -sOFFSCREENCANVASES_TO_PTHREAD=#offscreenCanvas -sEXPORTED_FUNCTIONS=_malloc,_main,_v4dSetVideoFramePointer -sEXPORTED_RUNTIME_METHODS=ccall,setValue -sPROXY_TO_PTHREAD=1 --use-preload-plugins --preload-file doc/lena.png -sINITIAL_MEMORY=128MB -sALLOW_MEMORY_GROWTH=1 -sUSE_GLFW=3 -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 --bind") set(EM_LINKER_FLAGS "-sENVIRONMENT=web,worker -sOFFSCREENCANVAS_SUPPORT -sSTANDALONE_WASM -sOFFSCREENCANVASES_TO_PTHREAD=#offscreenCanvas -sEXPORTED_FUNCTIONS=_main,_v4dInitCapture -sEXPORTED_RUNTIME_METHODS=ccall -sPROXY_TO_PTHREAD=1 --use-preload-plugins --preload-file doc/lena.png -sINITIAL_MEMORY=128MB -sALLOW_MEMORY_GROWTH=1 -sUSE_GLFW=3 -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 --bind")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${EM_LINKER_FLAGS}") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${EM_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${EM_LINKER_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${EM_LINKER_FLAGS}")
@ -118,23 +118,23 @@ if(BUILD_EXAMPLES)
set(NANOGUI_BUILD_GLFW OFF) set(NANOGUI_BUILD_GLFW OFF)
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/third/nanogui/ext/glfw/include/") include_directories("${CMAKE_CURRENT_SOURCE_DIR}/third/nanogui/ext/glfw/include/")
add_emscripten_sample(example_v4d_display_image samples/display_image.cpp) # add_emscripten_sample(example_v4d_display_image samples/display_image.cpp)
add_emscripten_sample(example_v4d_display_image_fb samples/display_image_fb.cpp) # add_emscripten_sample(example_v4d_display_image_fb samples/display_image_fb.cpp)
add_emscripten_sample(example_v4d_vector_graphics samples/vector_graphics.cpp) # add_emscripten_sample(example_v4d_vector_graphics samples/vector_graphics.cpp)
add_emscripten_sample(example_v4d_vector_graphics_and_fb samples/vector_graphics_and_fb.cpp) # add_emscripten_sample(example_v4d_vector_graphics_and_fb samples/vector_graphics_and_fb.cpp)
add_emscripten_sample(example_v4d_render_opengl samples/render_opengl.cpp) # add_emscripten_sample(example_v4d_render_opengl samples/render_opengl.cpp)
add_emscripten_sample(example_v4d_custom_source_and_sink samples/custom_source_and_sink.cpp) # add_emscripten_sample(example_v4d_custom_source_and_sink samples/custom_source_and_sink.cpp)
add_emscripten_sample(example_v4d_font_rendering samples/font_rendering.cpp) # add_emscripten_sample(example_v4d_font_rendering samples/font_rendering.cpp)
add_emscripten_sample(example_v4d_font_with_gui samples/font_with_gui.cpp) # add_emscripten_sample(example_v4d_font_with_gui samples/font_with_gui.cpp)
add_emscripten_sample(example_v4d_video_editing samples/video_editing.cpp) # add_emscripten_sample(example_v4d_video_editing samples/video_editing.cpp)
add_emscripten_sample(example_v4d_cube-demo samples/cube-demo.cpp) # add_emscripten_sample(example_v4d_cube-demo samples/cube-demo.cpp)
add_emscripten_sample(example_v4d_video-demo samples/video-demo.cpp) add_emscripten_sample(example_v4d_video-demo samples/video-demo.cpp)
add_emscripten_sample(example_v4d_nanovg-demo samples/nanovg-demo.cpp) # add_emscripten_sample(example_v4d_nanovg-demo samples/nanovg-demo.cpp)
add_emscripten_sample(example_v4d_font-demo samples/font-demo.cpp) # add_emscripten_sample(example_v4d_font-demo samples/font-demo.cpp)
add_emscripten_sample(example_v4d_shader-demo samples/shader-demo.cpp) # add_emscripten_sample(example_v4d_shader-demo samples/shader-demo.cpp)
add_emscripten_sample(example_v4d_pedestrian-demo samples/pedestrian-demo.cpp) # add_emscripten_sample(example_v4d_pedestrian-demo samples/pedestrian-demo.cpp)
add_emscripten_sample(example_v4d_optflow-demo samples/optflow-demo.cpp) # add_emscripten_sample(example_v4d_optflow-demo samples/optflow-demo.cpp)
add_emscripten_sample(example_v4d_beauty-demo samples/beauty-demo.cpp) # add_emscripten_sample(example_v4d_beauty-demo samples/beauty-demo.cpp)
else() else()
add_binary_sample(example_v4d_display_image) add_binary_sample(example_v4d_display_image)
add_binary_sample(example_v4d_custom_source_and_sink) add_binary_sample(example_v4d_custom_source_and_sink)

@ -128,8 +128,8 @@
var statusElement = document.getElementById('status'); var statusElement = document.getElementById('status');
var progressElement = document.getElementById('progress'); var progressElement = document.getElementById('progress');
var fsButton = document.querySelector("#fullscreenBtn"); var fsButton = document.querySelector("#fullscreenBtn");
var cameraBtn = document.querySelector("#captureBtn"); var cameraBtn = document.querySelector("captureBtn");
var videoElement = document.querySelector("#video"); var videoElement = document.querySelector("#v4dVideoElement");
var cameraCanvas = document.querySelector("#cameraCanvas"); var cameraCanvas = document.querySelector("#cameraCanvas");
function fixCanvasSize() { function fixCanvasSize() {

@ -110,7 +110,7 @@
</span> </span>
<canvas id="offscreenCanvas" width="1280" height="720" style="display: none;"></canvas> <canvas id="offscreenCanvas" width="1280" height="720" style="display: none;"></canvas>
<canvas id="cameraCanvas" width="1280" height="720" style="display: none;"></canvas> <canvas id="cameraCanvas" width="1280" height="720" style="display: none;"></canvas>
<video id="video" width="1280" height="720" autoplay style="display: none;"></video> <video id="v4dVideoElement" width="1280" height="720" autoplay style="display: none;"></video>
<div class="emscripten" id="status">Downloading...</div> <div class="emscripten" id="status">Downloading...</div>
@ -128,8 +128,8 @@
var statusElement = document.getElementById('status'); var statusElement = document.getElementById('status');
var progressElement = document.getElementById('progress'); var progressElement = document.getElementById('progress');
var fsButton = document.querySelector("#fullscreenBtn"); var fsButton = document.querySelector("#fullscreenBtn");
var cameraBtn = document.querySelector("#captureBtn"); var captureBtn = document.querySelector("#captureBtn");
var videoElement = document.querySelector("#video"); var videoElement = document.querySelector("#v4dVideoElement");
var cameraCanvas = document.querySelector("#cameraCanvas"); var cameraCanvas = document.querySelector("#cameraCanvas");
function fixCanvasSize() { function fixCanvasSize() {
@ -142,9 +142,7 @@
var Module = { var Module = {
onRuntimeInitialized: function() { onRuntimeInitialized: function() {
fixCanvasSize(); fixCanvasSize();
Module.videoBuffer = Module._malloc(1280 * 720 * 4); Module._v4dInitCapture(1280, 720);
Module.cameraCtx = null;
Module.ccall('v4dSetVideoFramePointer', 'void', ['number', 'number', 'number'], [Module.videoBuffer, 1280, 720]);
}, },
preRun: [], preRun: [],
postRun: [], postRun: [],
@ -207,26 +205,16 @@
}; };
Module.setStatus('Downloading...'); Module.setStatus('Downloading...');
window.onerror = function(event) {
// TODO: do not warn on ok events like simulating an infinite loop or exitStatus
Module.setStatus('Exception thrown, see JavaScript console');
//spinnerElement.style.display = 'none';
Module.setStatus = function(text) {
if (text) Module.printErr('[post-exception status] ' + text);
};
};
var playing = false; var playing = false;
var timeupdate = false; var timeupdate = false;
function checkReady() { function checkReady() {
if (playing && timeupdate) { if (playing && timeupdate) {
Module.doCapture = true; globalThis.doCapture = true;
} }
} }
cameraBtn.addEventListener('click', async function() { captureBtn.addEventListener('click', async function() {
let stream = await navigator.mediaDevices.getUserMedia({ video: { width: 1280, height: 720 }, audio: false}); let stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: false });
videoElement.addEventListener( videoElement.addEventListener(
"playing", "playing",
() => { () => {
@ -247,6 +235,15 @@
videoElement.srcObject = stream; videoElement.srcObject = stream;
}); });
window.onerror = function(event) {
// TODO: do not warn on ok events like simulating an infinite loop or exitStatus
Module.setStatus('Exception thrown, see JavaScript console');
//spinnerElement.style.display = 'none';
Module.setStatus = function(text) {
if (text) Module.printErr('[post-exception status] ' + text);
};
};
fsButton.addEventListener('click', async function () { fsButton.addEventListener('click', async function () {
Module.requestFullscreen(false, false) Module.requestFullscreen(false, false)
}); });

@ -78,7 +78,7 @@ void FrameBufferContext::init() {
glfwWindowHint(GLFW_STENCIL_BITS, 8); glfwWindowHint(GLFW_STENCIL_BITS, 8);
glfwWindowHint(GLFW_DEPTH_BITS, 24); glfwWindowHint(GLFW_DEPTH_BITS, 24);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
glfwWindowHint(GLFW_VISIBLE, offscreen_ ? GLFW_FALSE : GLFW_TRUE); glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE);
glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE); glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE);
glfwWindow_ = glfwCreateWindow(frameBufferSize_.width, frameBufferSize_.height, title_.c_str(), nullptr, glfwWindow_ = glfwCreateWindow(frameBufferSize_.width, frameBufferSize_.height, title_.c_str(), nullptr,

@ -312,120 +312,140 @@ Source makeCaptureSource(const string& inputFilename) {
#else #else
using namespace emscripten; using namespace emscripten;
uint8_t* current_frame = nullptr;
extern "C" { class HTML5Capture {
private:
EMSCRIPTEN_KEEPALIVE cv::Ptr<V4D> window_;
void v4dSetVideoFramePointer(uint8_t* frame, int width, int height) { int width_;
assert(current_frame == nullptr); int height_;
current_frame = frame; UMat tmp_;
// memset(current_frame, 127, width * height * 4); GLuint framebuffer = 0;
} GLuint texture = 0;
} public:
HTML5Capture(cv::Ptr<V4D> window, int width, int height) :
GLuint framebuffer = 0; window_(window), width_(width), height_(height), tmp_(cv::Size(width, height), CV_8UC4) {
GLuint texture = 0; cerr << "start constr" << endl;
EM_ASM({
bool captureVideoFrameGPU(int width, int height) { globalThis.playing = false;
int ret = EM_ASM_INT( globalThis.timeupdate = false;
if(typeof Module.ctx !== 'undefined' && Module.ctx !== null && Module.doCapture) { globalThis.v4dVideoElement = document.querySelector("#v4dVideoElement");
globalThis.gl = Module.ctx; globalThis.v4dCopyCanvasElement = document.createElement("canvas");
globalThis.v4dMainFrameBuffer = globalThis.gl.getParameter(globalThis.gl.FRAMEBUFFER_BINDING); globalThis.v4dCopyCanvasElement.id = "v4dCopyCanvasElement0";
globalThis.v4dMainTexture = globalThis.gl.getFramebufferAttachmentParameter(globalThis.gl.FRAMEBUFFER, globalThis.gl.COLOR_ATTACHMENT0, globalThis.gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME); globalThis.v4dCopyCanvasElement.width = $0;
return 1; globalThis.v4dCopyCanvasElement.height = $1;
} else { globalThis.v4dCopyCanvasElement.style.display = "none";
return 0; }, width, height);
} cerr << "end constr" << endl;
); }
if(ret) { bool captureGPU(UMat& dst) {
EM_ASM( cerr << "start capture" << endl;
if(typeof globalThis.v4dVideoElement === 'undefined' || globalThis.v4dVideoElement === null) { FrameBufferContext::GLScope scope(window_->fbCtx());
globalThis.v4dVideoElement = document.querySelector("#video"); cerr << "start em" << endl;
int ret = EM_ASM_INT(
if(typeof Module.ctx !== 'undefined' && Module.ctx != null && globalThis.doCapture) {
globalThis.gl = Module.ctx;
globalThis.v4dMainFrameBuffer = globalThis.gl.getParameter(globalThis.gl.FRAMEBUFFER_BINDING);
globalThis.v4dMainTexture = globalThis.gl.getFramebufferAttachmentParameter(globalThis.gl.FRAMEBUFFER, globalThis.gl.COLOR_ATTACHMENT0, globalThis.gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME);
return 1;
} else {
return 0;
} }
); );
cerr << "en em: " << ret << endl;
if(ret) {
cerr << "1" << endl;
if(framebuffer == 0) {
GL_CHECK(glGenFramebuffers(1, &framebuffer));
}
if(framebuffer == 0) { GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer));
GL_CHECK(glGenFramebuffers(1, &framebuffer)); cerr << "2" << endl;
} if(texture == 0) {
GL_CHECK(glGenTextures(1, &texture));
GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer)); }
if(texture == 0) {
GL_CHECK(glGenTextures(1, &texture));
}
GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture));
EM_ASM( GL_CHECK(glBindTexture(GL_TEXTURE_2D, texture));
const level = 0; cerr << "3" << endl;
const internalFormat = globalThis.gl.RGBA; EM_ASM(
const border = 0; const level = 0;
const srcFormat = globalThis.gl.RGBA; const internalFormat = globalThis.gl.RGBA;
const srcType = globalThis.gl.UNSIGNED_BYTE; const border = 0;
globalThis.gl.texImage2D( const srcFormat = globalThis.gl.RGBA;
globalThis.gl.TEXTURE_2D, const srcType = globalThis.gl.UNSIGNED_BYTE;
level, globalThis.gl.texImage2D(
internalFormat, globalThis.gl.TEXTURE_2D,
srcFormat, level,
srcType, internalFormat,
globalThis.v4dVideoElement srcFormat,
srcType,
globalThis.v4dVideoElement
);
); );
); cerr << "4" << endl;
GL_CHECK(glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0));
EM_ASM(
globalThis.gl.bindFramebuffer(globalThis.gl.DRAW_FRAMEBUFFER, globalThis.v4dMainFrameBuffer);
globalThis.gl.bindTexture(globalThis.gl.TEXTURE_2D, globalThis.v4dMainTexture);
globalThis.gl.pixelStorei(globalThis.gl.UNPACK_FLIP_Y_WEBGL, true);
globalThis.gl.framebufferTexture2D(globalThis.gl.DRAW_FRAMEBUFFER, globalThis.gl.COLOR_ATTACHMENT0, globalThis.gl.TEXTURE_2D, globalThis.v4dMainTexture, 0);
);
cerr << "5" << endl;
FrameBufferContext::FrameBufferScope fbScope(window_->fbCtx(), tmp_);
cvtColor(tmp_, dst, COLOR_BGRA2RGB);
cerr << "captured" << endl;
return true;
}
cerr << "not captured" << endl;
return false;
}
GL_CHECK(glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0)); void captureCPU() {
EM_ASM( EM_ASM(
globalThis.gl.bindFramebuffer(globalThis.gl.DRAW_FRAMEBUFFER, globalThis.v4dMainFrameBuffer); if(globalThis.doCapture) {
globalThis.gl.bindTexture(globalThis.gl.TEXTURE_2D, globalThis.v4dMainTexture); if(typeof globalThis.v4dCopyCanvasContext === 'undefined' || globalThis.v4dCopyCanvasContext === null)
globalThis.gl.pixelStorei(globalThis.gl.UNPACK_FLIP_Y_WEBGL, true); globalThis.v4dCopyCanvasContext = globalThis.v4dCopyCanvasElement.getContext('2d', { willReadFrequently: true });
globalThis.gl.framebufferTexture2D(globalThis.gl.DRAW_FRAMEBUFFER, globalThis.gl.COLOR_ATTACHMENT0, globalThis.gl.TEXTURE_2D, globalThis.v4dMainTexture, 0); if(typeof globalThis.v4dFrameData === 'undefined' || globalThis.v4dFrameData === null)
globalThis.v4dFrameData = Module._malloc(width_ * height_ * 4);
globalThis.v4dCopyCanvasElement.drawImage(globalThis.v4dVideoElement, 0, 0, 1280, 720);
var cameraArrayBuffer = globalThis.v4dCopyCanvasContext.getImageData(0, 0, 1280, 720);
Module.HEAPU8.set(cameraArrayBuffer.data, globalThis.v4dFrameData);
}
); );
return true;
} }
return false; };
}
EM_JS(void,copyVideoFrameCPU,(int p), { cv::Ptr<HTML5Capture> capture = nullptr;
if(Module.doCapture) { int capture_width = 0;
if(typeof Module.cameraCtx === 'undefined' || Module.cameraCtx === null) int capture_height = 0;
Module.cameraCtx = document.querySelector("#cameraCanvas").getContext('2d', { willReadFrequently: true });
if(typeof Module.videoElement === 'undefined' || Module.videoElement === null)
Module.videoElement = document.querySelector("#video");
Module.cameraCtx.drawImage(Module.videoElement, 0, 0, 1280, 720); extern "C" {
var cameraArrayBuffer = Module.cameraCtx.getImageData(0, 0, 1280, 720);
Module.HEAPU8.set(cameraArrayBuffer.data, p); EMSCRIPTEN_KEEPALIVE
} void v4dInitCapture(int width, int height) {
}); capture_width = width;
capture_height = height;
}
}
Source makeCaptureSource(int width, int height, cv::Ptr<V4D> window) { Source makeCaptureSource(int width, int height, cv::Ptr<V4D> window) {
using namespace std; using namespace std;
return Source([=](cv::UMat& frame) { return Source([=](cv::UMat& frame) {
//FIXME if(capture == nullptr && capture_width > 0 && capture_height > 0)
static cv::UMat tmp(cv::Size(width, height), CV_8UC4); // run_sync_on_main<16>([&](){
// capture = new HTML5Capture(window, capture_width, capture_height);
// });
try { try {
if(frame.empty()) if(frame.empty())
frame.create(cv::Size(width, height), CV_8UC3); frame.create(cv::Size(width, height), CV_8UC3);
if (current_frame != nullptr) { if(capture != nullptr) {
run_sync_on_main<17>([&](){ // run_sync_on_main<17>([&](){
FrameBufferContext::GLScope scope(window->fbCtx()); // capture->captureGPU(frame);
if(captureVideoFrameGPU(width, height)) {
FrameBufferContext::FrameBufferScope fbScope(window->fbCtx(), tmp);
cvtColor(tmp, frame, COLOR_BGRA2RGB);
}
});
// run_sync_on_main<16>([&](){
// copyVideoFrameCPU(reinterpret_cast<int>(current_frame));
// cv::Mat tmp(cv::Size(width, height), CV_8UC4, current_frame);
// cv::UMat utmp = tmp.getUMat(ACCESS_READ);
// cvtColor(utmp, frame, cv::COLOR_BGRA2RGB);
// utmp.release();
// tmp.release();
// }); // });
} else { } else {
std::cerr << "Nothing captured" << endl; std::cerr << "Nothing captured" << endl;

Loading…
Cancel
Save