feat: Skia for Android (#1731)
* feat: Call Skia Renderer * Use default NativePreviewView for Skia * Render to separate FBO * It appears once * Refactor a lot lol * Pass width/height * Read width/heights * Update SkiaRenderer.cpp * Read stencil/samples * Use switch for target * Clear full red * Update VideoPipeline.cpp * fix: Use `BorrowTextureFrom` instead of `AdoptTextureFrom` * Get it to work * Draw Camera Frame again (only works for first frame) * glDisable(GL_BLEND) * Use Frame Buffer again * Simplify Skia offscreen surface creation * fix: Get it to kinda work? * fix: Remove `sampler2D` shader Only the EXTERNAL_OES one kinda works * Revert "fix: Remove `sampler2D` shader" This reverts commit bf241a82f440f5a442f23a2b10329b813e7cdb3e. * Revert "fix: Get it to kinda work?" This reverts commit ea6a8784ad8dc7d05e8076591874f021b51dd84a. * fix: Use Skia for rendering * Simplify drawing code a lot * Clean up drawing loop a bit more * Some docs * Update SkiaRenderer.cpp * Surface * try to use Matrix * Use BottomLeft as a surface origin again * Get actual surface dimensions * Use 1x1 pbuffer instead * Update SkiaRenderer.cpp * Update SkiaRenderer.cpp * feat: Implement Skia Frame Processor (#1735) * feat: Implement JS Skia Frame Processor * Update SkiaRenderer.cpp * push * Create Frame from C++ * compile * Compile * Update VideoPipeline.cpp * Fix JNI local ref * Use `HardwareBuffer` for implementation * feat: Custom `Frame` implementation that uses CPU `ByteBuffer` (#1736) * feat: Implement JS Skia Frame Processor * Update SkiaRenderer.cpp * push * Create Frame from C++ * compile * Compile * Update VideoPipeline.cpp * Fix JNI local ref * Use `HardwareBuffer` for implementation * try: Try to just create a CPU based ByteBuffer * fix: Fix Java Type * fix remaining errors * try fixing FrameFactory * Use `free` * fix: Fix scene mode crash on some emulators * fix: Fix scene mode crash on some emulators * Fix getting pixels * fix: Fix buffer not being freed * Add some docs to `Frame` * Test Skia again * Use `getCurrentPresentationTime()` * Remove `FrameFactory.cpp` * Update VideoPipeline.h * Update VideoPipeline.cpp
This commit is contained in:
@@ -18,7 +18,6 @@ std::vector<jsi::PropNameID> FrameHostObject::getPropertyNames(jsi::Runtime& rt)
|
||||
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("width")));
|
||||
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("height")));
|
||||
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("bytesPerRow")));
|
||||
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("planesCount")));
|
||||
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("orientation")));
|
||||
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("isMirrored")));
|
||||
result.push_back(jsi::PropNameID::forUtf8(rt, std::string("timestamp")));
|
||||
@@ -176,11 +175,6 @@ jsi::Value FrameHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pr
|
||||
auto bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
|
||||
return jsi::Value((double) bytesPerRow);
|
||||
}
|
||||
if (name == "planesCount") {
|
||||
auto imageBuffer = CMSampleBufferGetImageBuffer(frame.buffer);
|
||||
auto planesCount = CVPixelBufferGetPlaneCount(imageBuffer);
|
||||
return jsi::Value((double) planesCount);
|
||||
}
|
||||
|
||||
// fallback to base implementation
|
||||
return HostObject::get(runtime, propName);
|
||||
|
@@ -39,15 +39,15 @@ using namespace facebook;
|
||||
}
|
||||
|
||||
- (void)call:(Frame*)frame {
|
||||
[_skiaRenderer renderCameraFrameToOffscreenCanvas:frame.buffer
|
||||
[_skiaRenderer renderCameraFrameToOffscreenSurface:frame.buffer
|
||||
withDrawCallback:^(SkiaCanvas _Nonnull canvas) {
|
||||
// Create the Frame Host Object wrapping the internal Frame and Skia Canvas
|
||||
self->_skiaCanvas->setCanvas(static_cast<SkCanvas*>(canvas));
|
||||
auto frameHostObject = std::make_shared<DrawableFrameHostObject>(frame, self->_skiaCanvas);
|
||||
|
||||
|
||||
// Call JS Frame Processor
|
||||
[self callWithFrameHostObject:frameHostObject];
|
||||
|
||||
|
||||
// Remove Skia Canvas from Host Object because it is no longer valid
|
||||
frameHostObject->invalidateCanvas();
|
||||
}];
|
||||
|
@@ -30,7 +30,7 @@ typedef void(^draw_callback_t)(SkiaCanvas _Nonnull);
|
||||
The given callback will be executed with a reference to the Skia Canvas
|
||||
for the user to perform draw operations on (in this case, through a JS Frame Processor)
|
||||
*/
|
||||
- (void)renderCameraFrameToOffscreenCanvas:(CMSampleBufferRef _Nonnull)sampleBuffer withDrawCallback:(draw_callback_t _Nonnull)callback;
|
||||
- (void)renderCameraFrameToOffscreenSurface:(CMSampleBufferRef _Nonnull)sampleBuffer withDrawCallback:(draw_callback_t _Nonnull)callback;
|
||||
/**
|
||||
Renders the latest Frame to the onscreen Layer.
|
||||
This should be called everytime you want the UI to update, e.g. for 60 FPS; every 16.66ms.
|
||||
|
@@ -35,7 +35,7 @@
|
||||
std::unique_ptr<RenderContext> _layerContext;
|
||||
// The texture holding the drawn-to Frame
|
||||
id<MTLTexture> _texture;
|
||||
|
||||
|
||||
// For synchronization between the two Threads/Contexts
|
||||
std::mutex _textureMutex;
|
||||
std::atomic<bool> _hasNewFrame;
|
||||
@@ -70,7 +70,7 @@
|
||||
return _texture;
|
||||
}
|
||||
|
||||
- (void)renderCameraFrameToOffscreenCanvas:(CMSampleBufferRef)sampleBuffer withDrawCallback:(draw_callback_t)callback {
|
||||
- (void)renderCameraFrameToOffscreenSurface:(CMSampleBufferRef)sampleBuffer withDrawCallback:(draw_callback_t)callback {
|
||||
// Wrap in auto release pool since we want the system to clean up after rendering
|
||||
@autoreleasepool {
|
||||
// Get the Frame's PixelBuffer
|
||||
@@ -87,7 +87,7 @@
|
||||
height:CVPixelBufferGetHeight(pixelBuffer)];
|
||||
|
||||
// Get & Lock the writeable Texture from the Metal Drawable
|
||||
|
||||
|
||||
GrMtlTextureInfo textureInfo;
|
||||
textureInfo.fTexture.retain((__bridge void*)texture);
|
||||
GrBackendRenderTarget backendRenderTarget((int)texture.width,
|
||||
@@ -122,7 +122,7 @@
|
||||
// The Frame Processor might draw the Frame again (through render()) to pass a custom paint/shader,
|
||||
// but that'll just overwrite the existing one - no need to worry.
|
||||
canvas->drawImage(image, 0, 0);
|
||||
|
||||
|
||||
// Call the draw callback - probably a JS Frame Processor.
|
||||
callback(static_cast<void*>(canvas));
|
||||
|
||||
@@ -145,7 +145,7 @@
|
||||
|
||||
@autoreleasepool {
|
||||
auto context = _layerContext->skiaContext.get();
|
||||
|
||||
|
||||
// Create a Skia Surface from the CAMetalLayer (use to draw to the View)
|
||||
GrMTLHandle drawableHandle;
|
||||
auto surface = SkSurfaces::WrapCAMetalLayer(context,
|
||||
@@ -161,14 +161,14 @@
|
||||
}
|
||||
|
||||
auto canvas = surface->getCanvas();
|
||||
|
||||
|
||||
// Lock the Mutex so we can operate on the Texture atomically without
|
||||
// renderFrameToCanvas() overwriting in between from a different thread
|
||||
std::unique_lock lock(_textureMutex);
|
||||
|
||||
auto texture = _texture;
|
||||
if (texture == nil) return;
|
||||
|
||||
|
||||
// Calculate Center Crop (aspectRatio: cover) transform
|
||||
auto sourceRect = SkRect::MakeXYWH(0, 0, texture.width, texture.height);
|
||||
auto destinationRect = SkRect::MakeXYWH(0, 0, surface->width(), surface->height());
|
||||
@@ -202,7 +202,7 @@
|
||||
id<MTLCommandBuffer> commandBuffer([_layerContext->commandQueue commandBuffer]);
|
||||
[commandBuffer presentDrawable:drawable];
|
||||
[commandBuffer commit];
|
||||
|
||||
|
||||
// Set flag back to false
|
||||
_hasNewFrame = false;
|
||||
lock.unlock();
|
||||
|
Reference in New Issue
Block a user