Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
仮想カメラで切り開く拡張現実の世界
Search
satoshi0212
December 08, 2020
Programming
700
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
仮想カメラで切り開く拡張現実の世界
satoshi0212
December 08, 2020
More Decks by satoshi0212
See All by satoshi0212
macOSで自分のカメラを作ってみよう - Core Media IO Extensions
satoshi0212
3
1.8k
NDIとARKitを連動させた新しい映像表現
satoshi0212
3
1.3k
100日間AR表現を実装して見つけた面白い実装を全力解説
satoshi0212
5
2.3k
Working on mobile AR implementation, what I've implemented and beyond
satoshi0212
0
590
macOS仮想カメラ「テロップカム」 実装方法とその先
satoshi0212
5
4k
ARで悪の組織の会議を実現する
satoshi0212
0
660
クロマキー合成を使い透過動画をAR空間に表示する
satoshi0212
3
10k
ARKit Maniacs
satoshi0212
1
3.8k
ARで作る価値のある物についての考察
satoshi0212
3
740
Other Decks in Programming
See All in Programming
ActionController meets Protocol Buffers
sorah
1
770
우리의 Nitro Modules는 당신의 Turbo Modules보다 아름답다
l2hyunwoo
0
250
AI駆動開発4年目の現在地(『あなたはFDEになるべきか?』イベント資料)
kumaiu
0
120
[Dev Group Paris Octobre 26] Agentforce, SIforce, Claudeforce, Slackbot… on s'y retrouve ?
nabondance
0
130
Railsバージョンを4倍にした話
optim
0
920
No More NoSuchMethodError
exoego
1
120
Zero-Tap Sign-In対応、結局何をすればいいの?
mitohato14
0
1.4k
Goコンパイラを作ってGoをもっと理解する / Build a Go compiler to better understand Go
ikura_hamu
0
110
Crash Auto Pipelines
veronikapj
1
330
AWS CDKを理解するために公式の定義を深掘って解説してみる / Understanding AWS CDK by Digging into Its Official Definition
akihisaikeda
1
110
AI時代のFlutter品質設計 — アプリ品質を守るQuality Layers
omatty198
0
340
Vapor Mode でアクセシビリティは 壊れないか検証した話
fuqda
1
310
Featured
See All Featured
Speed Design
sergeychernyshev
33
2.2k
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2.2k
How to Think Like a Performance Engineer
csswizardry
28
2.9k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
23k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
1.1k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
350
Typedesign – Prime Four
hannesfritz
42
3.2k
AI: The stuff that nobody shows you
jnunemaker
PRO
10
1.2k
JAMstack: Web Apps at Ludicrous Speed - All Things Open 2022
reverentgeek
1
670
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6.2k
Side Projects
sachag
456
43k
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
460
Transcript
ԾΧϝϥͰΓ։֦͘ுݱ࣮ͷੈք 93,BJHJ ෦ஐ5XJUUFS!TINEFWFMPQ
ԾΧϝϥʹڵຯ͕͋ΔΤϯδχΞʹಧ͚ େܕελδΦͰͳ͘σεΫτοϓεϚʔτϑΥϯ ఆλʔήοτ
όʔνϟϧΧϝϥ࡞ΕΔʂָͦ͠͏ʂ ͱ͍͏ฏΛ։͍ͯ΄͍͠ʂ
࣮ํ๏ ݱ࣮֦ுͱͯ͠ͷར༻
ԾΧϝϥ 4OBQ$BNFSB NNINN
None
None
None
None
None
None
None
࣮ํ๏ ݱ࣮֦ுͱͯ͠ͷར༻
5XJUUFSͰ(8όʔνϟϧΧϝϥ࡞νϟϨϯδͰ࡞աఔπΠʔτ͍ͯ͠·͢
࡞ͬͨࡍͷۤ࿑ΛৼΓฦΓ
֎෦ϥΠϒϥϦͳ͠ɺ4XJGUͷΈͰ࣮Մೳ
ԾΧϝϥ࣮αϯϓϧ IUUQTHJUIVCDPNTBUPTIJ7JSUVBM$BNFSB4BNQMF
ߏཁૉ
ߏཁૉ ɹ$PSF.FEJB*0%"-1MVHJO ɹίϯτϩʔϥΞϓϦ
$PSF.FEJB*0%"- 1MVHJO ίϯτϩʔϥΞϓϦ /41BTUFCPBSE -JCSBSZ$PSF.FEJB*01MVH*OT%"- ԾΧϝϥͷ࣮ମ 6*Λ࣋ͨͳ͍1MVHJOʹ Λ͢ΞϓϦ
ϓϩδΣΫτ࡞ QMJTUใՃ ΤϯτϦʔϙΠϯτ࣮ ΠϯλʔϑΣΠε࣮ Χϝϥө૾ͷऔಘͱग़ྗ $PSF.FEJB*0%"-1MVHJO
ϓϩδΣΫτ࡞ QMJTUใՃ ΤϯτϦʔϙΠϯτ࣮ ΠϯλʔϑΣΠε࣮ Χϝϥө૾ͷऔಘͱग़ྗ $PSF.FEJB*0%"-1MVHJO
None
None
ϓϩδΣΫτ࡞ QMJTUใՃ ΤϯτϦʔϙΠϯτ࣮ ΠϯλʔϑΣΠε࣮ Χϝϥө૾Λग़ྗઃఆ $PSF.FEJB*0%"-1MVHJO
1MVHJOGBDUPSZJOUFSGBDFT 1MVHJOUZQFT ΛՃ
None
ࣗͰࢦఆ͢Δ*%ɻ66*%ͳͲઃఆ
ΤϯτϦʔϙΠϯτGVODUJPO໊
ԾΧϝϥ1MVH*Oݻఆ ઌड़ͷ66*%
ϓϩδΣΫτ࡞ QMJTUใՃ ΤϯτϦʔϙΠϯτ࣮ ΠϯλʔϑΣΠε࣮ Χϝϥө૾Λग़ྗઃఆ $PSF.FEJB*0%"-1MVHJO
import Foundation import CoreMediaIO @_cdecl("VirtualCameraSampleMain") func VirtualCameraSampleMain(allocator: CFAllocator, requestedTypeUUID: CFUUID)
-> CMIOHardwarePlugInRef { return pluginRef } Main.swift
import Foundation import CoreMediaIO @_cdecl("VirtualCameraSampleMain") func VirtualCameraSampleMain(allocator: CFAllocator, requestedTypeUUID: CFUUID)
-> CMIOHardwarePlugInRef { return pluginRef } Main.swift ΤϯτϦʔϙΠϯτ ΠϯλʔϑΣΠεͷࢀরΛฦ٫
ϓϩδΣΫτ࡞ QMJTUใՃ ΤϯτϦʔϙΠϯτ࣮ ΠϯλʔϑΣΠε࣮ Χϝϥө૾Λग़ྗઃఆ $PSF.FEJB*0%"-1MVHJO
private func createPluginInterface() -> CMIOHardwarePlugInInterface { return CMIOHardwarePlugInInterface( _reserved: nil,
QueryInterface: QueryInterface, AddRef: AddRef, Release: Release, Initialize: Initialize, InitializeWithObjectID: InitializeWithObjectID, Teardown: Teardown, ObjectShow: ObjectShow, ObjectHasProperty: ObjectHasProperty, ObjectIsPropertySettable: ObjectIsPropertySettable, ObjectGetPropertyDataSize: ObjectGetPropertyDataSize, ObjectGetPropertyData: ObjectGetPropertyData, ObjectSetPropertyData: ObjectSetPropertyData, DeviceSuspend: DeviceSuspend, DeviceResume: DeviceResume, DeviceStartStream: DeviceStartStream, DeviceStopStream: DeviceStopStream, DeviceProcessAVCCommand: DeviceProcessAVCCommand, DeviceProcessRS422Command: DeviceProcessRS422Command, StreamCopyBufferQueue: StreamCopyBufferQueue, StreamDeckPlay: StreamDeckPlay, StreamDeckStop: StreamDeckStop, StreamDeckJog: StreamDeckJog, StreamDeckCueTo: StreamDeckCueTo) } PluginInterface.swift (ൈਮ)
private func createPluginInterface() -> CMIOHardwarePlugInInterface { return CMIOHardwarePlugInInterface( _reserved: nil,
QueryInterface: QueryInterface, AddRef: AddRef, Release: Release, Initialize: Initialize, InitializeWithObjectID: InitializeWithObjectID, Teardown: Teardown, ObjectShow: ObjectShow, ObjectHasProperty: ObjectHasProperty, ObjectIsPropertySettable: ObjectIsPropertySettable, ObjectGetPropertyDataSize: ObjectGetPropertyDataSize, ObjectGetPropertyData: ObjectGetPropertyData, ObjectSetPropertyData: ObjectSetPropertyData, DeviceSuspend: DeviceSuspend, DeviceResume: DeviceResume, DeviceStartStream: DeviceStartStream, DeviceStopStream: DeviceStopStream, DeviceProcessAVCCommand: DeviceProcessAVCCommand, DeviceProcessRS422Command: DeviceProcessRS422Command, StreamCopyBufferQueue: StreamCopyBufferQueue, StreamDeckPlay: StreamDeckPlay, StreamDeckStop: StreamDeckStop, StreamDeckJog: StreamDeckJog, StreamDeckCueTo: StreamDeckCueTo) } PluginInterface.swift (ൈਮ) ΠϯλʔϑΣΠε͕ظ͢ΔͷΛฦ٫
PluginInterface.swift (ൈਮ) ৄࡉιʔεࢀর
ϓϩδΣΫτ࡞ QMJTUใՃ ΤϯτϦʔϙΠϯτ࣮ ΠϯλʔϑΣΠε࣮ Χϝϥө૾औಘͱग़ྗ $PSF.FEJB*0%"-1MVHJO
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, ɹɹɹɹɹɹɹɹɹɹɹ ɹɹfrom connection:
AVCaptureConnection) { if output == cameraCapture.output { guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } let cameraImage = CIImage(cvImageBuffer: imageBuffer) let compositedImage = compose(bgImage: cameraImage, overlayImage: self.textImage) var pixelBuffer: CVPixelBuffer? _ = CVPixelBufferCreate( kCFAllocatorDefault, Int(compositedImage.extent.size.width), Int(compositedImage.extent.height), kCVPixelFormatType_32BGRA, self.CVPixelBufferCreateOptions as CFDictionary, &pixelBuffer ) if let pixelBuffer = pixelBuffer { context.render(compositedImage, to: pixelBuffer) delegate?.videoComposer(self, didComposeImageBuffer: pixelBuffer) } } } VideoComposer.swift (ൈਮ)
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, ɹɹɹɹɹɹɹɹɹɹɹ ɹɹfrom connection:
AVCaptureConnection) { if output == cameraCapture.output { guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } let cameraImage = CIImage(cvImageBuffer: imageBuffer) let compositedImage = compose(bgImage: cameraImage, overlayImage: self.textImage) var pixelBuffer: CVPixelBuffer? _ = CVPixelBufferCreate( kCFAllocatorDefault, Int(compositedImage.extent.size.width), Int(compositedImage.extent.height), kCVPixelFormatType_32BGRA, self.CVPixelBufferCreateOptions as CFDictionary, &pixelBuffer ) if let pixelBuffer = pixelBuffer { context.render(compositedImage, to: pixelBuffer) delegate?.videoComposer(self, didComposeImageBuffer: pixelBuffer) } } } VideoComposer.swift (ൈਮ) ผ్ੜͨ͠ΦʔόʔϨΠςΩετը૾ͱ߹ EFMFHBUFܦ༝ͰQJYFM#V⒎FSΛ͢
private lazy var timer: DispatchSourceTimer = { let interval =
1.0 / Double(frameRate) let timer = DispatchSource.makeTimerSource() timer.schedule(deadline: .now() + interval, repeating: interval) timer.setEventHandler(handler: { [weak self] in self?.enqueueBuffer() }) return timer }() Stream.swift (ൈਮ)
private lazy var timer: DispatchSourceTimer = { let interval =
1.0 / Double(frameRate) let timer = DispatchSource.makeTimerSource() timer.schedule(deadline: .now() + interval, repeating: interval) timer.setEventHandler(handler: { [weak self] in self?.enqueueBuffer() }) return timer }() Stream.swift (ൈਮ) GSBNF3BUFࢦఆ͠ߋ৽ॲཧݺͼग़͠
private func enqueueBuffer() { (தུ) var sampleBufferUnmanaged: Unmanaged<CMSampleBuffer>? = nil
error = CMIOSampleBufferCreateForImageBuffer( kCFAllocatorDefault, pixelBuffer, formatDescription, &timing, sequenceNumber, UInt32(kCMIOSampleBufferNoDiscontinuities), &sampleBufferUnmanaged ) guard error == noErr else { log("CMIOSampleBufferCreateForImageBuffer Error: \(error)") return } CMSimpleQueueEnqueue(queue, element: sampleBufferUnmanaged!.toOpaque()) queueAlteredProc?(objectID, sampleBufferUnmanaged!.toOpaque(), queueAlteredRefCon) sequenceNumber += 1 } Stream.swift (ൈਮ)
private func enqueueBuffer() { (தུ) var sampleBufferUnmanaged: Unmanaged<CMSampleBuffer>? = nil
error = CMIOSampleBufferCreateForImageBuffer( kCFAllocatorDefault, pixelBuffer, formatDescription, &timing, sequenceNumber, UInt32(kCMIOSampleBufferNoDiscontinuities), &sampleBufferUnmanaged ) guard error == noErr else { log("CMIOSampleBufferCreateForImageBuffer Error: \(error)") return } CMSimpleQueueEnqueue(queue, element: sampleBufferUnmanaged!.toOpaque()) queueAlteredProc?(objectID, sampleBufferUnmanaged!.toOpaque(), queueAlteredRefCon) sequenceNumber += 1 } Stream.swift (ൈਮ) QJYFM#V⒎FS͔Βੜͨ͠ $.4BNQMF#V⒎FSΛRVFVFʹՃ
@IBAction func sendButton_action(_ sender: Any) { SettingsPasteboard.shared.settings["text1"] = mainTextField.stringValue SettingsPasteboard.shared.update()
} ViewController.swift (ൈਮ)
None
QMVHJOϑΝΠϧΛஔ
-JCSBSZ$PSF.FEJB*01MVH*OT%"-
දࣔ͞Εͨʂ
None
ߏཁૉ ɹ$PSF.FEJB*0%"-1MVHJO ɹίϯτϩʔϥΞϓϦ
ίϯτϩʔϥΞϓϦ
$PSF.FEJB*0%"- 1MVHJO ίϯτϩʔϥΞϓϦ /41BTUFCPBSE -JCSBSZ$PSF.FEJB*01MVH*OT%"- ԾΧϝϥͷ࣮ମ 6*Λ࣋ͨͳ͍1MVHJOʹ Λ͢ΞϓϦ
1BTUFCPBSEʹΛஔׂ͘
ϓϩδΣΫτ࡞ ίϯτϩʔϧஔ /41BTUFCPBSEͰσʔλڞ༗ ίϯτϩʔϥΞϓϦ
None
None
ϓϩδΣΫτ࡞ ίϯτϩʔϧஔ /41BTUFCPBSEͰσʔλڞ༗ ίϯτϩʔϥΞϓϦ
None
None
ϓϩδΣΫτ࡞ ίϯτϩʔϧஔ /41BTUFCPBSEͰσʔλڞ༗ ίϯτϩʔϥΞϓϦ
extension NSPasteboard.Name { static let main = NSPasteboard.Name(Config.mainAppBundleIdentifier) } extension
NSPasteboard.PasteboardType { static let plain = NSPasteboard.PasteboardType(rawValue: "public.utf8-plain-text") } class SettingsPasteboard { static let shared = SettingsPasteboard() open var settings = [String: Any]() open func current() -> [String: Any] { let pasteboard = NSPasteboard(name: .main) if let element = pasteboard.pasteboardItems?.last, let str = element.string(forType: .plain), let data = str.data(using: .utf8) { do { let json = try JSONSerialization.jsonObject(with: data, options : .allowFragments) as! [String: Any] settings = json } catch { print("can't convert json") } } return settings } open func update() { let jsonStr = stringify(json: settings) let pasteboard = NSPasteboard(name: .main) pasteboard.declareTypes([.string], owner: nil) pasteboard.setString(jsonStr, forType: .string) } ... } SettingsPasteboard.swift (ൈਮ)
None
$PSF.FEJB*0%"- 1MVHJO ίϯτϩʔϥΞϓϦ /41BTUFCPBSE -JCSBSZ$PSF.FEJB*01MVH*OT%"- ԾΧϝϥͷ࣮ମ 6*Λ࣋ͨͳ͍1MVHJOʹ Λ͢ΞϓϦ
ίϯτϩʔϥΞϓϦ͔ΒΛૹ৴
None
None
None
࣮ํ๏ ݱ࣮֦ுͱͯ͠ͷར༻
'BDFUJNFΧϝϥө૾ Իೖྗ ը૾Ճ "1*Ϩεϙϯε ΩʔϘʔυೖྗ ,FZOPUFը໘ FUD ֎෦ ԾΧϝϥ ग़ྗՃػߏ
ݱ࣮֦ுͱͯ͠ͷԾΧϝϥ ֤छೖྗ
NNINNϏοάϋϯυϞʔυ
Ή͜͏ͷ͘ʹϑΟϧλɺϚΠϖʔδɺϝλόʔε
ϑΟϧλҟٞ͋Γɺͬͨ
ϑΟϧλΠϩϞωΞత
UPOBSJԕִϦΞϧλΠϜө૾
ϚΠϯυϚοϓ
None
δΣωϨΠςΟϒදݱ
ελϯϓϦΞΫγϣϯ
Իೝࣝͱ༁
None
None
ݱ࣮֦ுͱͯ͠ͷԾΧϝϥ
ࢀߟ IUUQTEFWFMPQFSBQQMFDPNMJCSBSZBSDIJWFTBNQMFDPEF$PSF.FEJB*0*OUSPEVDUJPO*OUSPIUNM IUUQTHJUIVCDPNKPIOCPJMFTDPSFNFEJBJPEBMNJOJNBMFYBNQMF IUUQTHJUIVCDPNTFBODIBT4JNQMF%"-1MVHJO IUUQTTQFBLFSEFDLDPNLJTIJLBXBLBUTVNJWJSUVBMXFCDBNFSBXP[VPSPV
5XJUUFSͰ࠷৽ใൃ৴த !TINEFWFMPQ ԾΧϝϥ࣮αϯϓϧ IUUQTHJUIVCDPNTBUPTIJ7JSUVBM$BNFSB4BNQMF