video: use openGL when metal is not available
Change-Id: Ic2d19d19da72b71f73f12d3efab75c9bb384d2fb
diff --git a/src/CurrentCallVC.mm b/src/CurrentCallVC.mm
index c51af7a..1316ea8 100644
--- a/src/CurrentCallVC.mm
+++ b/src/CurrentCallVC.mm
@@ -51,6 +51,7 @@
#import "VideoCommon.h"
#import "views/GradientView.h"
#import "views/MovableView.h"
+#import "views/RenderingView.h"
@interface CurrentCallVC () <NSPopoverDelegate> {
QString convUid_;
@@ -96,12 +97,12 @@
// Video
@property (unsafe_unretained) IBOutlet CallView *videoView;
-@property (unsafe_unretained) IBOutlet CallMTKView *previewView;
+@property (unsafe_unretained) IBOutlet RenderingView *previewView;
@property (unsafe_unretained) IBOutlet MovableView *movableBaseForView;
@property (unsafe_unretained) IBOutlet NSView* hidePreviewBackground;
@property (unsafe_unretained) IBOutlet NSButton* hidePreviewButton;
-@property (unsafe_unretained) IBOutlet CallMTKView *videoMTKView;
+@property (unsafe_unretained) IBOutlet RenderingView *distantView;
@property RendererConnectionsHolder* renderConnections;
@property QMetaObject::Connection videoStarted;
@@ -373,13 +374,13 @@
[headerGradientView setHidden:YES];
[controlsPanel setHidden:YES];
[controlsStackView setHidden:YES];
- [self.videoMTKView fillWithBlack];
+ [self.distantView fillWithBlack];
[self.previewView fillWithBlack];
[hidePreviewBackground setHidden:YES];
[self.previewView setHidden: YES];
- [self.videoMTKView setHidden: YES];
- self.previewView.stopRendering = true;
- self.videoMTKView.stopRendering = true;
+ [self.distantView setHidden: YES];
+ self.previewView.videoRunning = NO;
+ self.distantView.videoRunning = NO;
[backgroundImage setHidden:NO];
[bluerBackgroundEffect setHidden:NO];
break;
@@ -392,13 +393,13 @@
[backgroundImage setHidden:NO];
[bluerBackgroundEffect setHidden:NO];
if(!currentCall.isAudioOnly) {
- [self.videoMTKView fillWithBlack];
+ [self.distantView fillWithBlack];
[self.previewView fillWithBlack];
[hidePreviewBackground setHidden:YES];
[self.previewView setHidden: YES];
- [self.videoMTKView setHidden: YES];
- self.previewView.stopRendering = true;
- self.videoMTKView.stopRendering = true;
+ [self.distantView setHidden: YES];
+ self.previewView.videoRunning = NO;
+ self.distantView.videoRunning = NO;
}
break;
case Status::INACTIVE:
@@ -436,19 +437,19 @@
-(void) setUpVideoCallView {
[previewView fillWithBlack];
- [self.videoMTKView fillWithBlack];
+ [self.distantView fillWithBlack];
[previewView setHidden: NO];
- [self.videoMTKView setHidden:NO];
- [hidePreviewBackground setHidden: self.previewView.stopRendering];
+ [self.distantView setHidden:NO];
+ [hidePreviewBackground setHidden: !self.previewView.videoRunning];
[bluerBackgroundEffect setHidden:YES];
[backgroundImage setHidden:YES];
- self.previewView.stopRendering = false;
- self.videoMTKView.stopRendering = false;
+ self.previewView.videoRunning = true;
+ self.distantView.videoRunning = true;
}
-(void) setUpAudioOnlyView {
[self.previewView setHidden: YES];
- [self.videoMTKView setHidden: YES];
+ [self.distantView setHidden: YES];
[hidePreviewBackground setHidden: YES];
[bluerBackgroundEffect setHidden:NO];
[backgroundImage setHidden:NO];
@@ -536,11 +537,11 @@
if (id == lrc::api::video::PREVIEW_RENDERER_ID) {
[self.previewView setHidden:NO];
[hidePreviewBackground setHidden: NO];
- self.previewView.stopRendering = false;
+ self.previewView.videoRunning = true;
} else if ([self isCurrentCall: id]) {
[self mouseIsMoving: NO];
- self.videoMTKView.stopRendering = false;
- [self.videoMTKView setHidden:NO];
+ self.distantView.videoRunning = true;
+ [self.distantView setHidden:NO];
[bluerBackgroundEffect setHidden:YES];
[backgroundImage setHidden:YES];
}
@@ -551,11 +552,11 @@
[=](const QString& id) {
if (id == lrc::api::video::PREVIEW_RENDERER_ID) {
[self.previewView setHidden:YES];
- self.previewView.stopRendering = true;
+ self.previewView.videoRunning = false;
} else if ([self isCurrentCall: id]) {
[self mouseIsMoving: YES];
- self.videoMTKView.stopRendering = true;
- [self.videoMTKView setHidden:YES];
+ self.distantView.videoRunning = false;
+ [self.distantView setHidden:YES];
[bluerBackgroundEffect setHidden:NO];
[backgroundImage setHidden:NO];
}
@@ -569,46 +570,19 @@
if(!renderer->isRendering()) {
return;
}
- [hidePreviewBackground setHidden: self.previewView.stopRendering];
- [self renderer: renderer renderFrameForPreviewView:previewView];
+ [hidePreviewBackground setHidden: !self.previewView.videoRunning];
+ [self rendererPreview: renderer];
} else if ([self isCurrentCall: id]) {
auto renderer = &mediaModel->getRenderer(id);
if(!renderer->isRendering()) {
return;
}
- [self renderer:renderer renderFrameForDistantView: self.videoMTKView];
+ [self rendererDistantView: renderer];
}
});
}
--(void) renderer: (const lrc::api::video::Renderer*)renderer renderFrameForPreviewView:(CallMTKView*) view
-{
- @autoreleasepool {
- auto framePtr = renderer->currentAVFrame();
- auto frame = framePtr.get();
- if(!frame || !frame->width || !frame->height) {
- return;
- }
- auto frameSize = CGSizeMake(frame->width, frame->height);
- auto rotation = 0;
- if (frame->data[3] != NULL && (CVPixelBufferRef)frame->data[3]) {
- [view renderWithPixelBuffer:(CVPixelBufferRef)frame->data[3]
- size: frameSize
- rotation: rotation
- fillFrame: true];
- return;
- }
- else if (CVPixelBufferRef pixelBuffer = [self getBufferForPreviewFromFrame:frame]) {
- [view renderWithPixelBuffer: pixelBuffer
- size: frameSize
- rotation: rotation
- fillFrame: true];
- }
- }
-}
-
--(void) renderer: (const lrc::api::video::Renderer*)renderer renderFrameForDistantView:(CallMTKView*) view
-{
+-(void) rendererDistantView: (const lrc::api::video::Renderer*)renderer {
@autoreleasepool {
auto framePtr = renderer->currentAVFrame();
auto frame = framePtr.get();
@@ -622,13 +596,13 @@
rotation = av_display_rotation_get(data);
}
if (frame->data[3] != NULL && (CVPixelBufferRef)frame->data[3]) {
- [view renderWithPixelBuffer: (CVPixelBufferRef)frame->data[3]
+ [self.distantView renderWithPixelBuffer: (CVPixelBufferRef)frame->data[3]
size: frameSize
rotation: rotation
fillFrame: false];
}
if (CVPixelBufferRef pixelBuffer = [self getBufferForDistantViewFromFrame:frame]) {
- [view renderWithPixelBuffer: pixelBuffer
+ [self.distantView renderWithPixelBuffer: pixelBuffer
size: frameSize
rotation: rotation
fillFrame: false];
@@ -636,6 +610,34 @@
}
}
+-(void) rendererPreview: (const lrc::api::video::Renderer*)renderer {
+ @autoreleasepool {
+ auto framePtr = renderer->currentAVFrame();
+ auto frame = framePtr.get();
+ if(!frame || !frame->width || !frame->height) {
+ return;
+ }
+ auto frameSize = CGSizeMake(frame->width, frame->height);
+ auto rotation = 0;
+ if (auto matrix = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX)) {
+ const int32_t* data = reinterpret_cast<int32_t*>(matrix->data);
+ rotation = av_display_rotation_get(data);
+ }
+ if (frame->data[3] != NULL && (CVPixelBufferRef)frame->data[3]) {
+ [self.previewView renderWithPixelBuffer: (CVPixelBufferRef)frame->data[3]
+ size: frameSize
+ rotation: rotation
+ fillFrame: false];
+ }
+ if (CVPixelBufferRef pixelBuffer = [self getBufferForPreviewFromFrame:frame]) {
+ [self.previewView renderWithPixelBuffer: pixelBuffer
+ size: frameSize
+ rotation: rotation
+ fillFrame: true];
+ }
+ }
+}
+
-(CVPixelBufferRef) getBufferForPreviewFromFrame:(const AVFrame*)frame {
[VideoCommon fillPixelBuffr:&pixelBufferPreview fromFrame:frame bufferPool:&pixelBufferPoolPreview];
CVPixelBufferRef buffer = pixelBufferPreview;
@@ -700,7 +702,7 @@
[backgroundImage setHidden:NO];
backgroundImage.layer.contents = nil;
[self.previewView setHidden:YES];
- [self.videoMTKView setHidden:YES];
+ [self.distantView setHidden:YES];
contactNameLabel.textColor = [NSColor highlightColor];
contactNameLabel.textColor = [NSColor highlightColor];
diff --git a/src/RecordFileVC.mm b/src/RecordFileVC.mm
index 9a09b6d..edd1ce6 100644
--- a/src/RecordFileVC.mm
+++ b/src/RecordFileVC.mm
@@ -21,8 +21,8 @@
#import "AppDelegate.h"
#import "VideoCommon.h"
#import "views/HoverButton.h"
-#import "views/CallMTKView.h"
#import "views/NSColor+RingTheme.h"
+#import "views/RenderingView.h"
#import "NSString+Extensions.h"
//lrc
@@ -32,7 +32,7 @@
#import <AVFoundation/AVFoundation.h>
@interface RecordFileVC ()
-@property (unsafe_unretained) IBOutlet CallMTKView* previewView;
+@property (unsafe_unretained) IBOutlet RenderingView* previewView;
@property (unsafe_unretained) IBOutlet NSTextField* timeLabel;
@property (unsafe_unretained) IBOutlet NSTextField* infoLabel;
@@ -106,7 +106,7 @@
#pragma mark - dispaly
--(void) renderer: (const lrc::api::video::Renderer*)renderer renderFrameForView:(CallMTKView*) view
+-(void) renderer: (const lrc::api::video::Renderer*)renderer renderFrameForView:(RenderingView*) view
{
@autoreleasepool {
const CGSize frameSize = [VideoCommon fillPixelBuffr:&pixBuf
@@ -270,7 +270,7 @@
}
[previewView fillWithBlack];
- self.previewView.stopRendering = false;
+ self.previewView.videoRunning = true;
[self connectPreviewSignals];
avModel->stopPreview();
avModel->startPreview();
diff --git a/src/VideoCommon.mm b/src/VideoCommon.mm
index 5e3be63..70ff004 100644
--- a/src/VideoCommon.mm
+++ b/src/VideoCommon.mm
@@ -122,10 +122,27 @@
return;
}
base = static_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1));
- for(size_t i = 0; i < frame->height / 2 * bytesPerRowUV / 2; i++ ){
- *base++ = frame->data[1][i];
- *base++ = frame->data[2][i];
- }
+ if (bytesPerRowUV == frame->linesize[1] * 2) {
+ for(size_t i = 0; i < frame->height / 2 * bytesPerRowUV / 2; i++ ) {
+ *base++ = frame->data[1][i];
+ *base++ = frame->data[2][i];
+ }
+ } else {
+ uint32_t size = frame->linesize[1] * frame->height / 2;
+ uint8_t* dstData = new uint8_t[2 * size];
+ for (int i = 0; i < 2 * size; i++){
+ if (i % 2 == 0){
+ dstData[i] = frame->data[1][i/2];
+ }else {
+ dstData[i] = frame->data[2][i/2];
+ }
+ }
+ [VideoCommon copyLineByLineSrc: dstData
+ toDest: base
+ srcLinesize: frame->linesize[1] * 2
+ destLinesize: bytesPerRowUV
+ height: frame->height/2];
+ }
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
}
diff --git a/src/VideoPrefsVC.mm b/src/VideoPrefsVC.mm
index ff0680d..ed9739a 100644
--- a/src/VideoPrefsVC.mm
+++ b/src/VideoPrefsVC.mm
@@ -18,7 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#import "VideoPrefsVC.h"
-#import "views/CallMTKView.h"
+#import "views/RenderingView.h"
#import "AppDelegate.h"
#import "VideoCommon.h"
@@ -36,7 +36,7 @@
@interface VideoPrefsVC ()
-@property IBOutlet CallMTKView* previewView;
+@property IBOutlet RenderingView* previewView;
@property (assign) IBOutlet NSPopUpButton* videoDevicesList;
@property (assign) IBOutlet NSPopUpButton* sizesList;
@property (assign) IBOutlet NSPopUpButton* ratesList;
@@ -85,7 +85,7 @@
QObject::disconnect(deviceEvent);
AppDelegate* appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
if (![appDelegate getActiveCalls].size()) {
- self.previewView.stopRendering = true;
+ self.previewView.videoRunning = false;
avModel->stopPreview();
[previewView fillWithBlack];
}
@@ -162,7 +162,7 @@
if (id != lrc::api::video::PREVIEW_RENDERER_ID) {
return;
}
- self.previewView.stopRendering = false;
+ self.previewView.videoRunning = true;
QObject::disconnect(frameUpdated);
QObject::disconnect(previewStarted);
QObject::disconnect(previewStopped);
@@ -187,7 +187,7 @@
::PREVIEW_RENDERER_ID) {
return;
}
- self.previewView.stopRendering = true;
+ self.previewView.videoRunning = false;
QObject::disconnect(previewStopped);
QObject::disconnect(frameUpdated);
});
@@ -203,7 +203,7 @@
bool updatePreview = avModel->getRenderer(lrc::api ::video::PREVIEW_RENDERER_ID).isRendering() && (defaultDevice != currentVideoDevice);
if (updatePreview) {
[previewView fillWithBlack];
- self.previewView.stopRendering = true;
+ self.previewView.videoRunning = false;
[self startPreview];
}
[self addDevices];
@@ -212,7 +212,7 @@
#pragma mark - dispaly
--(void) renderer: (const lrc::api::video::Renderer*)renderer renderFrameForView:(CallMTKView*) view
+-(void) renderer: (const lrc::api::video::Renderer*)renderer renderFrameForView:(RenderingView*) view
{
@autoreleasepool {
auto framePtr = renderer->currentAVFrame();
@@ -272,7 +272,7 @@
AppDelegate* appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
auto calls = [appDelegate getActiveCalls];
if (calls.empty()) {
- self.previewView.stopRendering = false;
+ self.previewView.videoRunning = true;
[self connectPreviewSignals];
avModel->stopPreview();
avModel->startPreview();
diff --git a/src/views/CallLayer.h b/src/views/CallLayer.h
index 86d21c7..f604e29 100644
--- a/src/views/CallLayer.h
+++ b/src/views/CallLayer.h
@@ -20,11 +20,9 @@
#import <Cocoa/Cocoa.h>
#import <QSize>
#import <video/renderer.h>
+#import "VideoRendering.h"
-@interface CallLayer : NSOpenGLLayer
+@interface CallLayer : NSOpenGLLayer <VideoRendering>
-@property BOOL videoRunning;
-
-- (void) setCurrentFrame:(Video::Frame)framePtr;
@end
diff --git a/src/views/CallLayer.mm b/src/views/CallLayer.mm
index 3dd5fd3..4e03fa9 100644
--- a/src/views/CallLayer.mm
+++ b/src/views/CallLayer.mm
@@ -26,13 +26,14 @@
in vec2 in_Pos;
in vec2 in_TexCoord;
uniform vec2 in_Scaling;
+uniform mat4 in_rotationMatrix;
out vec2 texCoord;
void main()
{
texCoord = in_TexCoord;
- gl_Position = vec4(in_Pos.x*in_Scaling.x, in_Pos.y*in_Scaling.y, 0.0, 1.0);
+ gl_Position = in_rotationMatrix * vec4(in_Pos.x*in_Scaling.x, in_Pos.y*in_Scaling.y, 0.0, 1.0);
}
)glsl";
@@ -42,23 +43,37 @@
out vec4 fragColor;
in vec2 texCoord;
-uniform sampler2D tex;
+uniform sampler2D tex_y, tex_uv;
void main()
{
- fragColor = texture(tex, texCoord);
+ mediump vec3 yuv, rgb;
+ yuv.x = (texture(tex_y, texCoord).r);
+ yuv.yz = (texture(tex_uv, texCoord).rg - vec2(0.5, 0.5));
+ rgb = mat3( 1, 1, 1,
+ 0, -0.3441, 1.7720,
+ 1.4020, -0.7141, 0) * yuv;
+ fragColor = vec4(rgb, 1);
}
)glsl";
+@interface CallLayer()
+
+@property BOOL currentFrameDisplayed;
+@property NSLock* currentFrameLk;
+@property CGFloat currentWidth;
+@property CGFloat currentHeight;
+@property CGFloat currentAngle;
+@property CVPixelBufferRef currentFrame;
+
+@end
+
@implementation CallLayer
// OpenGL handlers
-GLuint tex, vbo, vShader, fShader, sProg, vao;
+GLuint textureY, textureUV, textureUniformY, textureUniformUV, vbo, vShader, fShader, sProg, vao;
-// Last frame data and attributes
-Video::Frame currentFrame;
-BOOL currentFrameDisplayed;
-NSLock* currentFrameLk;
+@synthesize currentAngle, currentFrameDisplayed, currentFrameLk, currentWidth, currentHeight, currentFrame, videoRunning;
- (id) init
{
@@ -113,6 +128,9 @@
glLinkProgram(sProg);
glUseProgram(sProg);
+ textureUniformY = glGetUniformLocation(sProg, "tex_y");
+ textureUniformUV = glGetUniformLocation(sProg, "tex_uv");
+
// Vertices position attrib
GLuint inPosAttrib = glGetAttribLocation(sProg, "in_Pos");
glEnableVertexAttribArray(inPosAttrib);
@@ -122,10 +140,19 @@
GLuint inTexCoordAttrib = glGetAttribLocation(sProg, "in_TexCoord");
glEnableVertexAttribArray(inTexCoordAttrib);
glVertexAttribPointer(inTexCoordAttrib, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (void*)(2*sizeof(GLfloat)));
+ // TextureY
+ glActiveTexture(GL_TEXTURE0);
+ glGenTextures(1, &textureY);
+ glBindTexture(GL_TEXTURE_2D, textureY);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
- // Texture
- glGenTextures(1, &tex);
- glBindTexture(GL_TEXTURE_2D, tex);
+ // TextureUV
+ glActiveTexture(GL_TEXTURE1);
+ glGenTextures(1, &textureUV);
+ glBindTexture(GL_TEXTURE_2D, textureUV);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
@@ -161,25 +188,35 @@
- (void)drawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat forLayerTime:(CFTimeInterval)t displayTime:(const CVTimeStamp *)ts
{
GLenum errEnum;
- glBindTexture(GL_TEXTURE_2D, tex);
-
[currentFrameLk lock];
- if(!currentFrameDisplayed) {
- if(currentFrame.ptr) {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, currentFrame.width, currentFrame.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, currentFrame.ptr);
- }
+ if(!currentFrameDisplayed && currentFrame) {
+ CVPixelBufferLockBaseAddress(currentFrame, 0);
+ [self configureTexture:textureY
+ index:0
+ uniform:textureUniformY
+ activeTexture:GL_TEXTURE0
+ format:GL_RED
+ fullPlane: YES];
+ [self configureTexture:textureUV
+ index:1
+ uniform:textureUniformUV
+ activeTexture:GL_TEXTURE1
+ format:GL_RG
+ fullPlane: NO];
+ CVPixelBufferUnlockBaseAddress(currentFrame, 0);
+ CVPixelBufferRelease(currentFrame);
currentFrameDisplayed = YES;
}
// To ensure that we will not divide by zero
- if (currentFrame.ptr && currentFrame.width && currentFrame.height) {
+ if (currentFrame && currentWidth && currentHeight) {
// Compute scaling factor to keep the original aspect ratio of the video
CGSize viewSize = self.frame.size;
- float viewRatio = viewSize.width/viewSize.height;
- float frameRatio = ((float)currentFrame.width)/((float)currentFrame.height);
+ float viewRatio = (currentAngle == 90 || currentAngle == -90) ?
+ viewSize.height/viewSize.width : viewSize.width/viewSize.height;
+ float frameRatio = ((float)currentWidth)/((float)currentHeight);
float ratio = viewRatio * (1/frameRatio);
GLint inScalingUniform = glGetUniformLocation(sProg, "in_Scaling");
-
float multiplier = MAX(frameRatio, ratio);
if((viewRatio >= 1 && frameRatio >= 1) ||
(viewRatio < 1 && frameRatio < 1) ||
@@ -193,24 +230,73 @@
glUniform2f(inScalingUniform, 1.0, 1.0 * ratio);
else
glUniform2f(inScalingUniform, 1.0/ratio, 1.0);
-
}
}
- [currentFrameLk unlock];
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ // apply rotation
+ float radians = (currentAngle * M_PI) / 180;
+ float rotation[16] =
+ {
+ cos(radians), -sin(radians), 0.0f, 0.0f,
+ sin(radians), cos(radians), 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ };
+ GLint location = glGetUniformLocation(sProg, "in_rotationMatrix");
+ glUniformMatrix4fv(location, 1, GL_FALSE, rotation);
+
+ [currentFrameLk unlock];
+ glClearColor(0.0f, 0.0f, 0.0f, 0.1f);
glClear(GL_COLOR_BUFFER_BIT);
if([self videoRunning])
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
-- (void) setCurrentFrame:(Video::Frame)framePtr
-{
+-(void)configureTexture:(GLuint)texture index:(int)index
+ uniform:(GLuint)uniform
+ activeTexture:(GLenum)activeTexture
+ format:(GLint)format
+ fullPlane:(BOOL)fullPlane {
+ auto plane = CVPixelBufferGetBaseAddressOfPlane(currentFrame, index);
+ auto width = CVPixelBufferGetWidthOfPlane(currentFrame, index);
+ auto height = CVPixelBufferGetHeightOfPlane(currentFrame, index);
+ auto strideWidth = CVPixelBufferGetBytesPerRowOfPlane(currentFrame, index);
+ strideWidth = fullPlane ? strideWidth : strideWidth * 0.5;
+ if(strideWidth > width) {
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, strideWidth);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ } else {
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 0);
+ }
+ glActiveTexture(activeTexture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, plane);
+ glUniform1i(uniform, index);
+}
+
+-(void)fillWithBlack {
[currentFrameLk lock];
- currentFrame = std::move(framePtr);
- currentFrameDisplayed = NO;
+ if(currentFrame) {
+ currentFrame = nullptr;
+ currentFrameDisplayed = YES;
+ }
[currentFrameLk unlock];
}
+-(void)renderWithPixelBuffer:(CVPixelBufferRef)buffer size:(CGSize)size rotation: (float)rotation fillFrame: (bool)fill {
+ [currentFrameLk lock];
+ currentFrame = buffer;
+ CFRetain(currentFrame);
+ currentWidth = size.width;
+ currentHeight = size.height;
+ currentAngle = rotation;
+ currentFrameDisplayed = NO;
+ videoRunning = YES;
+ [currentFrameLk unlock];
+}
+-(void)setupView {
+}
+
@end
diff --git a/src/views/CallMTKView.h b/src/views/CallMTKView.h
index edf09d5..ab432a4 100644
--- a/src/views/CallMTKView.h
+++ b/src/views/CallMTKView.h
@@ -19,10 +19,7 @@
#import <Cocoa/Cocoa.h>
#import <MetalKit/MetalKit.h>
+#import "VideoRendering.h"
-@interface CallMTKView: MTKView
--(void)renderWithPixelBuffer:(CVPixelBufferRef)buffer size:(CGSize)size rotation: (float)rotation fillFrame: (bool)fill;
--(void)fillWithBlack;
--(void)setupView;
-@property bool stopRendering;
+@interface CallMTKView: MTKView <VideoRendering>
@end
diff --git a/src/views/CallMTKView.mm b/src/views/CallMTKView.mm
index b49dd46..98d0afc 100644
--- a/src/views/CallMTKView.mm
+++ b/src/views/CallMTKView.mm
@@ -48,6 +48,7 @@
simd::float4x4 projectionMatrix;
simd::float4x4 rotationMatrix;
};
+@synthesize videoRunning;
- (instancetype)initWithFrame:(NSRect)frame
{
@@ -151,7 +152,7 @@
if(frameDisplayed) {
return;
}
- if(_stopRendering) {
+ if(!self.videoRunning) {
self.releaseDrawables;
return;
}
diff --git a/src/views/RenderingView.h b/src/views/RenderingView.h
new file mode 100644
index 0000000..1be755f
--- /dev/null
+++ b/src/views/RenderingView.h
@@ -0,0 +1,26 @@
+/*
+* Copyright (C) 2020 Savoir-faire Linux Inc.
+* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#import <Cocoa/Cocoa.h>
+#import "VideoRendering.h"
+
+@interface RenderingView : NSView <VideoRendering>
+
+@end
+
diff --git a/src/views/RenderingView.mm b/src/views/RenderingView.mm
new file mode 100644
index 0000000..24d8006
--- /dev/null
+++ b/src/views/RenderingView.mm
@@ -0,0 +1,89 @@
+/*
+* Copyright (C) 2020 Savoir-faire Linux Inc.
+* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#import "RenderingView.h"
+#import "src/utils.h"
+#import "CallMTKView.h"
+#import "CallLayer.h"
+
+@interface RenderingView()
+
+@property id <VideoRendering> renderer;
+
+@end
+
+@implementation RenderingView
+@synthesize videoRunning, renderer;
+
+- (instancetype)initWithFrame:(NSRect)frame {
+ self = [super initWithFrame:frame];
+ [self commonInit];
+ return self;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)coder {
+ self = [super initWithCoder:coder];
+ [self commonInit];
+ return self;
+}
+
+-(void)commonInit {
+ if ([self metalSupported]) {
+ renderer = [[CallMTKView alloc] initWithFrame:self.frame];
+ NSView* renderView = (NSView*)renderer;
+ [self addSubview: renderView];
+ renderView.translatesAutoresizingMaskIntoConstraints = true;
+ [renderView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+ [renderView.topAnchor constraintEqualToAnchor:self.topAnchor constant:0].active = YES;
+ [renderView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:0].active = YES;
+ [renderView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:0].active = YES;
+ [renderView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:0].active = YES;
+ } else {
+ [self setLayer:[[CallLayer alloc] init]];
+ [self setWantsLayer:true];
+ CallLayer* callLayer = (CallLayer*)self.layer;
+ renderer = callLayer;
+ }
+}
+
+-(void)renderWithPixelBuffer:(CVPixelBufferRef)buffer size:(CGSize)size rotation: (float)rotation fillFrame: (bool)fill {
+ [renderer renderWithPixelBuffer:buffer size:size rotation:rotation fillFrame:fill];
+}
+
+-(void)fillWithBlack {
+ [renderer fillWithBlack];
+ [self.layer setBackgroundColor:NSColor.blackColor.CGColor];
+}
+
+-(void)setupView {
+ [renderer setupView];
+}
+
+-(void)setVideoRunning:(BOOL)running {
+ // for opengl video running set when new frame received
+ if ([self metalSupported] || !running) {
+ renderer.videoRunning = running;
+ }
+ videoRunning = running;
+}
+
+-(BOOL)metalSupported {
+ return MTLCreateSystemDefaultDevice() != nil;
+}
+
+@end
diff --git a/src/views/VideoRendering.h b/src/views/VideoRendering.h
new file mode 100644
index 0000000..cef76e7
--- /dev/null
+++ b/src/views/VideoRendering.h
@@ -0,0 +1,29 @@
+/*
+* Copyright (C) 2020 Savoir-faire Linux Inc.
+* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#import <Foundation/Foundation.h>
+#import <video/renderer.h>
+@protocol VideoRendering
+-(void)renderWithPixelBuffer:(CVPixelBufferRef)buffer size:(CGSize)size rotation: (float)rotation fillFrame: (bool)fill;
+-(void)fillWithBlack;
+-(void)setupView;
+@property BOOL videoRunning;
+
+@end
+