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
680
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
580
macOS仮想カメラ「テロップカム」 実装方法とその先
satoshi0212
5
4k
ARで悪の組織の会議を実現する
satoshi0212
0
640
クロマキー合成を使い透過動画をAR空間に表示する
satoshi0212
3
10k
ARKit Maniacs
satoshi0212
1
3.8k
ARで作る価値のある物についての考察
satoshi0212
3
730
Other Decks in Programming
See All in Programming
速く作れる。その次は、速く確かめられる開発へ 〜AIネイティブ開発を支える、Shift Down〜 / Can build fast. Next, moving to development where we can verify fast.
rkaga
5
3.3k
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
150
cdk deploy JawsSonic #MARATHONしながらAWSリソースをデプロイしてみよう
akihisaikeda
2
140
巨大モノリシックアプリ モダン化大作戦
ktcryomm
1
1k
Webの地図
yosuke_furukawa
PRO
6
4.6k
GraphRAGのKnowledge Graphを 直接!見る/View-GraphRAG's-KnowledgeGraph-directly!
tyumugi1113
1
340
フロントエンドUIフレームワークのこれまでとこれから
ssssota
5
2.8k
WebMCP Challenge に星空観察アプリで参加した話
okajun35
0
180
仕様駆動開発による爆速プロダクト開発 / Bakusoku Spec Driven Development
kobakei
0
120
市販E-Readerを乗っ取れ 〜Embedded Swiftで電子ペーパーガジェットを制御する〜
trickart
0
190
{ Android | Kotlin } Gradle Plugin in 2026
ryunen344
1
320
Java 27新機能 / Java 27 new features
kishida
2
150
Featured
See All Featured
Are puppies a ranking factor?
jonoalderson
2
3.9k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.6k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
Color Theory Basics | Prateek | Gurzu
gurzu
1
470
Ruling the World: When Life Gets Gamed
codingconduct
0
340
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
380
Build your cross-platform service in a week with App Engine
jlugia
234
19k
The Spectacular Lies of Maps
axbom
PRO
1
1k
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
360
Into the Great Unknown - MozCon
thekraken
41
2.7k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
56k
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.9k
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