Platforms to show: All Mac Windows Linux Cross-Platform

/AVFoundation/AVVideoWall


Required plugins for this example: MBS MacBase Plugin, MBS AVFoundation Plugin, MBS MacCG Plugin, MBS MacCF Plugin, MBS Main Plugin

You find this example project in your Plugins Download as a Xojo project file within the examples folder: /AVFoundation/AVVideoWall

This example is the version from Sat, 21th Jun 2019.

Project "AVVideoWall.xojo_binary_project"
Class App Inherits Application
Const kEditClear = "&Löschen"
Const kFileQuit = "Beenden"
Const kFileQuitShortcut = ""
EventHandler Sub Open() if AVAssetExportSessionMBS.available = false then MsgBox "Please run on Mac OS X 10.7 or newer." quit end if End EventHandler
End Class
Class Window1 Inherits Window
EventHandler Sub Close() for each layer as AVCaptureVideoPreviewLayerMBS in videoPreviewLayers layer.session = nil next if session<>nil then session.stopRunning session = nil end if window = nil End EventHandler
EventHandler Sub Open() call configure End EventHandler
EventHandler Sub Resized() Resize End EventHandler
EventHandler Sub Resizing() Resize End EventHandler
Function Configure() As Boolean // Create a screen-sized window and Core Animation layer createWindowAndRootLayer // Create a capture session session = new AVCaptureSessionMBS // Set the session preset dim preset as string = AVFoundationMBS.AVCaptureSessionPreset640x480 session.SessionPreset = preset // Create a wall of video out of the video capture devices on your Mac dim success as boolean = setupVideoWall return success End Function
Sub Resize() CATransactionMBS.begin // Disable implicit animations for this transaction CATransactionMBS.setValue(true, CATransactionMBS.kCATransactionDisableActions) dim u as integer = UBound(videoPreviewLayers) for i as integer = 0 to u dim currentDevice as integer = i \ 4 dim rootBounds as CGRectMBS = rootlayer.bounds dim deviceSquareBounds as CGRectMBS = CGRectMBS.Make(0, 0, rootBounds.size.width / devicesCount, rootBounds.size.height) deviceSquareBounds.left = deviceSquareBounds.size.width * currentDevice dim videoPreviewLayer as AVCaptureVideoPreviewLayerMBS = videoPreviewLayers(i) dim q as integer = quadrantIndexes(i) dim curLayerFrame as CGRectMBS = rectForQuadrant(q, deviceSquareBounds) videoPreviewLayer.Frame = curLayerFrame next CATransactionMBS.commit End Sub
Sub createWindowAndRootLayer() window = window1.NSWindowMBS // Make the content view layer-backed dim windowContentView as NSViewMBS = window.contentView windowContentView.wantsLayer = true // Grab the Core Animation layer rootLayer = windowContentView.layer rootLayer.autoresizingMask = rootLayer.kCALayerHeightSizable + rootLayer.kCALayerWidthSizable 'rootLayer = window1.canvas1.calayermbs // Set its background color to opaque black dim colorspace as CGColorSpaceMBS = CGColorSpaceMBS.CreateDeviceRGB dim black as new MemoryBlock(8*4) black.SingleValue(0) = 0 // red black.SingleValue(4) = 0 // green black.SingleValue(8) = 0 // blue black.SingleValue(12) = 1.0 // alpha dim blackcolor as CGColorMBS = CGColorMBS.Create(colorspace, black) rootLayer.backgroundColor = blackColor // Show the window window1.show End Sub
Function devicesThatCanProduceVideo() As AVCaptureDeviceMBS() dim devices() as AVCaptureDeviceMBS dim allDevices() as AVCaptureDeviceMBS = AVCaptureDeviceMBS.devices for each d as AVCaptureDeviceMBS in allDevices if d.HasMediaType(AVFoundationMBS.AVMediaTypeVideo) or d.HasMediaType(AVFoundationMBS.AVMediaTypeMuxed) then devices.Append d end if next Return devices End Function
Function rectForQuadrant(i as integer, rect as CGRectMBS) As CGRectMBS dim curLayerFrame as new CGRectMBS(rect) curLayerFrame.width = curLayerFrame.width / 2 curLayerFrame.height = curLayerFrame.height / 2 select case i case 0 // top left // currentLayerBounds.origin.x/y are unchanged. case 1 // top right curLayerFrame.left = curLayerFrame.left + curLayerFrame.width case 2 // bottom left curLayerFrame.top = curLayerFrame.top + curLayerFrame.height case 3 // bottom right curLayerFrame.top = curLayerFrame.top + curLayerFrame.height curLayerFrame.left = curLayerFrame.left + curLayerFrame.width end Select // Make a 2-pixel border curLayerFrame.top = curLayerFrame.top + 2 curLayerFrame.left = curLayerFrame.left + 2 curLayerFrame.width = curLayerFrame.width - 4 curLayerFrame.height = curLayerFrame.height - 4 return curLayerFrame End Function
Function setupVideoWall() As Boolean // Create 4 video preview layers per video device in a mirrored square, and // set up these squares left to right within the root layer dim error as NSErrorMBS // Find video devices dim devices() as AVCaptureDeviceMBS = devicesThatCanProduceVideo devicesCount = UBound(devices)+1 dim currentDevice as integer = 0 dim rootBounds as CGRectMBS = rootlayer.bounds if devicesCount = 0 then return false end if // For each video device for each d as AVCaptureDeviceMBS in devices // Create a device input with the device and add it to the session input = AVCaptureDeviceInputMBS.deviceInputWithDevice(d, error) if error<>Nil then MsgBox "deviceInputWithDevice: "+error.localizedDescription return false end if session.addInputWithNoConnections input // Find the video input port dim videoPort as AVCaptureInputPortMBS = input.portWithMediaType(AVFoundationMBS.AVMediaTypeVideo) // Set up its corresponding square within the root layer dim deviceSquareBounds as CGRectMBS = CGRectMBS.Make(0, 0, rootBounds.size.width / devicesCount, rootBounds.size.height) deviceSquareBounds.left = deviceSquareBounds.size.width * currentDevice // Create 4 video preview layers in the square for i as integer = 0 to 3 // Create a video preview layer with the session videoPreviewLayer = AVCaptureVideoPreviewLayerMBS.layerWithSessionWithNoConnection(session) // Add it to the arrays videoPreviewLayers.append videoPreviewLayer quadrantIndexes.append i // Create a connection with the input port and the preview layer // and add it to the session dim connection as AVCaptureConnectionMBS = AVCaptureConnectionMBS.connectionWithInputPort(videoPort,videoPreviewLayer) session.addConnection connection // If the preview layer is at top-right (i=1) or bottom-left (i=2), // flip it left-right. dim doMirror as boolean = ((i = 1) or (i = 2)) if ( doMirror ) then connection.AutomaticallyAdjustsVideoMirroring = false connection.VideoMirrored = true end if // Compute the frame for the current layer // Each layer fills a quadrant of the square dim curLayerFrame as CGRectMBS = rectForQuadrant(i, deviceSquareBounds) CATransactionMBS.begin // Disable implicit animations for this transaction CATransactionMBS.setValue(true, CATransactionMBS.kCATransactionDisableActions) // Set the layer frame videoPreviewLayer.Frame = curLayerFrame // Save the frame in an array for the "sendLayersHome" animation '[_homeLayerRects addObject:[NSValue valueWithRect:NSRectFromCGRect(curLayerFrame)]]; // We want the video content to always fill the entire layer regardless of the layer size, // so set video gravity to ResizeAspectFill videoPreviewLayer.VideoGravity = AVFoundationMBS.AVLayerVideoGravityResizeAspectFill // If the layer is at top of the square (i=0, 1), make it upside down if ( i < 2 ) then connection.VideoOrientation = AVCaptureConnectionMBS.AVCaptureVideoOrientationPortraitUpsideDown end if // Add the preview layer to the root layer rootLayer.addSublayer videoPreviewLayer CATransactionMBS.commit next currentDevice = currentDevice +1 next session.startRunning return true End Function
Property devicesCount As Integer
Property input As AVCaptureDeviceInputMBS
Property quadrantIndexes() As Integer
Property rootLayer As CALayerMBS
Property session As AVCaptureSessionMBS
Property videoPreviewLayer As AVCaptureVideoPreviewLayerMBS
Property videoPreviewLayers() As AVCaptureVideoPreviewLayerMBS
Property window As NSWindowMBS
End Class
MenuBar MenuBar1
MenuItem FileMenu = "&Ablage"
MenuItem FileQuit = "#App.kFileQuit"
MenuItem EditMenu = "&Bearbeiten"
MenuItem EditUndo = "&Rückgängig"
MenuItem UntitledMenu1 = "-"
MenuItem EditCut = "&Ausschneiden"
MenuItem EditCopy = "&Kopieren"
MenuItem EditPaste = "&Einfügen"
MenuItem EditClear = "#App.kEditClear"
MenuItem UntitledMenu0 = "-"
MenuItem EditSelectAll = "&Alles auswählen"
End MenuBar
ExternalFile info
End ExternalFile
End Project

The items on this page are in the following plugins: MBS AVFoundation Plugin.


The biggest plugin in space...