// // Created by Marc Rousavy on 25.08.23. // #include "VideoPipeline.h" #include "OpenGLError.h" #include #include #include #include #include #include #include #include "JFrameProcessor.h" #include "OpenGLTexture.h" namespace vision { jni::local_ref VideoPipeline::initHybrid(jni::alias_ref jThis, int width, int height) { return makeCxxInstance(jThis, width, height); } VideoPipeline::VideoPipeline(jni::alias_ref jThis, int width, int height) : _javaPart(jni::make_global(jThis)) { _width = width; _height = height; _context = OpenGLContext::CreateWithOffscreenSurface(); } VideoPipeline::~VideoPipeline() { // 1. Remove output surfaces removeRecordingSessionOutputSurface(); // 2. Delete the input textures if (_inputTexture != std::nullopt) { glDeleteTextures(1, &_inputTexture->id); _inputTexture = std::nullopt; } // 3. Destroy the OpenGL context _context = nullptr; } void VideoPipeline::removeRecordingSessionOutputSurface() { if (_recordingSessionOutput) _recordingSessionOutput->destroy(); _recordingSessionOutput = nullptr; } void VideoPipeline::setRecordingSessionOutputSurface(jobject surface) { // 1. Delete existing output surface removeRecordingSessionOutputSurface(); // 2. Set new output surface if it is not null ANativeWindow* window = ANativeWindow_fromSurface(jni::Environment::current(), surface); _recordingSessionOutput = OpenGLRenderer::CreateWithWindowSurface(_context, window); } int VideoPipeline::getInputTextureId() { if (_inputTexture == std::nullopt) { _inputTexture = _context->createTexture(OpenGLTexture::Type::ExternalOES, _width, _height); } return static_cast(_inputTexture->id); } void VideoPipeline::onBeforeFrame() { _context->use(); glBindTexture(_inputTexture->target, _inputTexture->id); } void VideoPipeline::onFrame(jni::alias_ref transformMatrixParam) { // Get the OpenGL transform Matrix (transforms, scales, rotations) float transformMatrix[16]; transformMatrixParam->getRegion(0, 16, transformMatrix); OpenGLTexture& texture = _inputTexture.value(); if (_recordingSessionOutput) { __android_log_print(ANDROID_LOG_INFO, TAG, "Rendering to RecordingSession.."); _recordingSessionOutput->renderTextureToSurface(texture, transformMatrix); } } void VideoPipeline::registerNatives() { registerHybrid({ makeNativeMethod("initHybrid", VideoPipeline::initHybrid), makeNativeMethod("setRecordingSessionOutputSurface", VideoPipeline::setRecordingSessionOutputSurface), makeNativeMethod("removeRecordingSessionOutputSurface", VideoPipeline::removeRecordingSessionOutputSurface), makeNativeMethod("getInputTextureId", VideoPipeline::getInputTextureId), makeNativeMethod("onBeforeFrame", VideoPipeline::onBeforeFrame), makeNativeMethod("onFrame", VideoPipeline::onFrame), }); } } // namespace vision