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
TwilioのCameraSource に任意のフレームを使用するすゝめ
Search
BOB
December 22, 2020
Programming
1.8k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
TwilioのCameraSource に任意のフレームを使用するすゝめ
potatotips 72
BOB
December 22, 2020
More Decks by BOB
See All by BOB
StoreKitTestを使ってアプリ内課金のテストや検証を効率化する方法
aratayokoyama
2
1k
既存サブスクリプション商品にアップグレード・ダウングレード商品を追加しよう
aratayokoyama
1
2.7k
バーチャル背景を実現しよう
aratayokoyama
0
830
アクセシブルなチャートを実現しよう
aratayokoyama
0
1.9k
VirtualBitriseUserGroupMeetup_fresh_bob
aratayokoyama
0
150
Other Decks in Programming
See All in Programming
標準パッケージに uuid が追加された 背景から見る Go らしい意思決定 / go_127_uuid_decision
convto
5
7k
A2UI for Android: Safely Rendering AI-Generated UI with Jetpack Compose - DroidKaigi 2026
itsmedreamwalker
0
130
ゲームコントローラやキーボードのファームウェアをSwiftで書く
kishikawakatsumi
1
230
Go のフラットな パッケージに 「ファイル単位の private」を 〜Linter “declscope” を作った話〜
mpyw
0
290
The Good Stuff, Not the Slop: Engineering High-Quality Android Apps with Modern AI Tooling
danybony
1
250
変化を抱擁するドキュメントの作り方 - ビジネスルール駆動開発がもたらす、コードとの新しい関係
ioki
2
200
Java 27新機能 / Java 27 new features
kishida
2
130
更なる可用性を求めて、5年間運用したKotlinのアプリケーションをGoでリプレイスする話
ken_tunc
0
170
From 6 People Classroom Meetup to 100 People Regional Conference / FOSS4G Hiroshima 2026
furukawayasuto
0
200
自分的「カンファレンスの楽しみ方」
syumai
0
200
GKE で Pod の見方を変えたら、スケールアウト時の挙動を真に捉えられた話
stkk
0
120
AgentCore CLI で進化した AWS での AI エージェントの作り方 : 必要な機能を必要な時に
icoxfog417
PRO
3
340
Featured
See All Featured
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.7k
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
450
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
460
Java REST API Framework Comparison - PWX 2021
mraible
34
9.7k
Why Our Code Smells
bkeepers
PRO
340
58k
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
700
Skip the Path - Find Your Career Trail
mkilby
1
230
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
2.2k
Joys of Absence: A Defence of Solitary Play
codingconduct
1
520
Google's AI Overviews - The New Search
badams
0
1.6k
Into the Great Unknown - MozCon
thekraken
41
2.7k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Transcript
ʲJ04ʳ5XJMJPͷ$BNFSB4PVSDF ʹҙͷϑϨʔϜΛ༻͢Δ͢ʍΊ "3"5":0,0:"#0#!QPUBUPUJQTJ04"OESPJE։ൃ5JQTڞ༗ձ
!#0#(7J "SBUB:PLPZBNB#0# # ळݩ߁ؔ࿈ʹ10Ҏ্අ͢ # ւಓੜ·Ε # ͩͯ͜ະདྷେଔ #
2020αΠόʔΤʔδΣϯτ৽ଔೖࣾ # λοϓϧͷiOSΤϯδχΞ
λοϓϧ w ͚ͷϚονϯάΞϓϦ w ݄ϦϦʔε w ϑϦοΫ6* w ຊਓೝূɼը໘ըࢭ
w 6*͕உঁͰେ͖͘ҧ͏ w 5XJMJPΛ༻ͨ͠ϏσΦνϟοτ
λοϓϧɿϏσΦνϟοτ w ݄ϏσΦνϟοτϦϦʔε w 5XJMJPΛ༻͓ͯ͠Γ·͢ w ݄ϑΟϧλʔػೳϦϦʔε w ʮ͓෦ͷย͚͕େมʯɼ
ʮͩ͠ͳΈΛ͑Δͷʹ͕͔͔࣌ؒΔʯ ͱ͍ͬͨΛड͚ͯ։ൃ͍ͨ͠·ͨ͠ w ϑΟϧλʔػೳ"3,JU༻͓ͯ͠Γ·͢ ϚονϯάΞϓϦʮλοϓϧੜʯɺ͙͢ʹΦϯϥΠϯσʔτ͕Ͱ͖Δ ʮϏσΦνϟοτʯʹ৽ͨʹʮϑΟϧλʔػೳʯΛՃɿhttps://www.cyberagent.co.jp/news/detail/id=25083 5XJMJPհͯ͠ҙͷϑϨʔϜΛૹΔํ๏Λ͝հ
(0"- ΞδΣϯμ CameraSourceʹҙͷϑϨʔϜΛ༻͢ΔϙΠϯτ˓˓ $BNFSB4PVSDFૹΔʹ˓˓͕େ "7$BQUVSFɿϑϨʔϜͷऔΓํ "3,JUɿϑϨʔϜͷऔΓํ
$BNFSB4PVSDFʹૹΔʹ˓˓͕େ
$BNFSB4PVSDFʹૹΔʹ˓˓͕େ // TVIVideoFrame - (nullable instancetype)initWithTimestamp:(CMTime)timestamp buffer:(nonnull CVImageBufferRef)imageBuffer orientation:(TVIVideoOrientation)orientation;
- (nullable instancetype)initWithTimeInterval:(CFTimeInterval)timeInterval buffer:(nonnull CVImageBufferRef)imageBuffer orientation:(TVIVideoOrientation)orientation; TVIVideoFrame Class Referenceɿhttps://twilio.github.io/twilio-video-ios/docs/latest/Classes/TVIVideoFrame.html#//api/name/initWithTimeInterval:buffer:orientation:
$BNFSB4PVSDFʹૹΔʹ˓˓͕େ // TVIVideoFrame - (nullable instancetype)initWithTimestamp:(CMTime)timestamp buffer:(nonnull CVImageBufferRef)imageBuffer orientation:(TVIVideoOrientation)orientation;
- (nullable instancetype)initWithTimeInterval:(CFTimeInterval)timeInterval buffer:(nonnull CVImageBufferRef)imageBuffer orientation:(TVIVideoOrientation)orientation; CVImageBufferRef CVImageBufferRef TVIVideoFrame Class Referenceɿhttps://twilio.github.io/twilio-video-ios/docs/latest/Classes/TVIVideoFrame.html#//api/name/initWithTimeInterval:buffer:orientation:
$BNFSB4PVSDFʹૹΔʹ˓˓͕େ // TVIVideoFrame - (nullable instancetype)initWithTimestamp:(CMTime)timestamp buffer:(nonnull CVImageBufferRef)imageBuffer orientation:(TVIVideoOrientation)orientation;
- (nullable instancetype)initWithTimeInterval:(CFTimeInterval)timeInterval buffer:(nonnull CVImageBufferRef)imageBuffer orientation:(TVIVideoOrientation)orientation; CMTime CFTimeInterval ϑϨʔϜΛऔಘ͢Δ Ճ͢Δ 7JEFP'SBNFΛ ࡞͢Δ ྲྀ͠ࠐΉ " # TVIVideoFrame Class Referenceɿhttps://twilio.github.io/twilio-video-ios/docs/latest/Classes/TVIVideoFrame.html#//api/name/initWithTimeInterval:buffer:orientation: $ %
$BNFSB4PVSDFʹૹΔʹ4JOL͕େ import TwilioVideo final class LocalTrackSourceManager: NSObject { private(set)
var camera: CameraSource! func onVideoFrame(image: CIImage, time: TimeInterval) { guard let pixelBuffer = image.convertCVPixelBuffer() else { return } guard let videoFrame = VideoFrame(timeInterval: time, buffer: pixelBuffer, orientation: VideoOrientation.up) else { return } camera.sink?.onVideoFrame(videoFrame) } func onVideoFrame(image: CIImage, time: CMTime) { guard let pixelBuffer = image.convertCVPixelBuffer() else { return } guard let videoFrame = VideoFrame(timestamp: time, buffer: pixelBuffer, orientation: VideoOrientation.up) else { return } camera.sink?.onVideoFrame(videoFrame) } } # $ %
import TwilioVideo final class LocalTrackSourceManager: NSObject { private(set) var camera:
CameraSource! func onVideoFrame(image: CIImage, time: TimeInterval) { guard let pixelBuffer = image.convertCVPixelBuffer() else { return } guard let videoFrame = VideoFrame(timeInterval: time, buffer: pixelBuffer, orientation: VideoOrientation.up) else { return } camera.sink?.onVideoFrame(videoFrame) } func onVideoFrame(image: CIImage, time: CMTime) { guard let pixelBuffer = image.convertCVPixelBuffer() else { return } guard let videoFrame = VideoFrame(timestamp: time, buffer: pixelBuffer, orientation: VideoOrientation.up) else { return } camera.sink?.onVideoFrame(videoFrame) } } $BNFSB4PVSDFʹૹΔʹ4JOL͕େ # $ % guard let pixelBuffer = image.convertCVPixelBuffer() else { return } guard let pixelBuffer = image.convertCVPixelBuffer() else { return }
import TwilioVideo final class LocalTrackSourceManager: NSObject { private(set) var camera:
CameraSource! func onVideoFrame(image: CIImage, time: TimeInterval) { guard let pixelBuffer = image.convertCVPixelBuffer() else { return } guard let videoFrame = VideoFrame(timeInterval: time, buffer: pixelBuffer, orientation: VideoOrientation.up) else { return } camera.sink?.onVideoFrame(videoFrame) } func onVideoFrame(image: CIImage, time: CMTime) { guard let pixelBuffer = image.convertCVPixelBuffer() else { return } guard let videoFrame = VideoFrame(timestamp: time, buffer: pixelBuffer, orientation: VideoOrientation.up) else { return } camera.sink?.onVideoFrame(videoFrame) } } $BNFSB4PVSDFʹૹΔʹ4JOL͕େ # $ % VideoFrame(timeInterval: time, buffer: pixelBuffer, orientation: VideoOrientation.up) VideoFrame(timestamp: time, buffer: pixelBuffer, orientation: VideoOrientation.up)
import TwilioVideo final class LocalTrackSourceManager: NSObject { private(set) var camera:
CameraSource! func onVideoFrame(image: CIImage, time: TimeInterval) { guard let pixelBuffer = image.convertCVPixelBuffer() else { return } guard let videoFrame = VideoFrame(timeInterval: time, buffer: pixelBuffer, orientation: VideoOrientation.up) else { return } camera.sink?.onVideoFrame(videoFrame) } func onVideoFrame(image: CIImage, time: CMTime) { guard let pixelBuffer = image.convertCVPixelBuffer() else { return } guard let videoFrame = VideoFrame(timestamp: time, buffer: pixelBuffer, orientation: VideoOrientation.up) else { return } camera.sink?.onVideoFrame(videoFrame) } } $BNFSB4PVSDFʹૹΔʹ4JOL͕େ camera.sink?.onVideoFrame(videoFrame) camera.sink?.onVideoFrame(videoFrame)
$BNFSB4PVSDFʹૹΔʹ4JOL͕େ import TwilioVideo final class LocalTrackSourceManager: NSObject { private(set)
var camera: CameraSource! func onVideoFrame(image: CIImage, time: TimeInterval) { guard let pixelBuffer = image.convertCVPixelBuffer() else { return } guard let videoFrame = VideoFrame(timeInterval: time, buffer: pixelBuffer, orientation: VideoOrientation.up) else { return } camera.sink?.onVideoFrame(videoFrame) } func onVideoFrame(image: CIImage, time: CMTime) { guard let pixelBuffer = image.convertCVPixelBuffer() else { return } guard let videoFrame = VideoFrame(timestamp: time, buffer: pixelBuffer, orientation: VideoOrientation.up) else { return } camera.sink?.onVideoFrame(videoFrame) } } camera.sink?.onVideoFrame(videoFrame) camera.sink?.onVideoFrame(videoFrame) extension VideoChatAVCaptureView: VideoSource { weak var sink: VideoSink? var isScreencast: Bool { return false } func requestOutputFormat(_ outputFormat: VideoFormat) { guard let sink = sink else { return } sink.onVideoFormatRequest(outputFormat) } } w 7JEFP4PVSDFʹ४ڌͤͯ͞TJOLΛ࣋ͭ͜ͱՄೳ w ͨͩ͠ɼৗʹ4JOLϑϨʔϜΛૹΔ͜ͱ͕݅ ʢΫϥογϡ͠·͢ʣ w Ұํɼ$BNFSB4PVSDFͷ4JOLʹͦͷ͕݅ͳ͍ 5JQT var camera: CameraSource!
"7$BQUVSFɿϑϨʔϜͷऔΓํ
"7$BQUVSFɿϑϨʔϜͷऔΓํ import AVFoundation import UIKit final class VideoChatAVCaptureView: UIView
{ private var session: AVCaptureSession? private func prepare() { let output: AVCaptureVideoDataOutput = AVCaptureVideoDataOutput() output.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoChat")) } } extension VideoChatAVCaptureView: AVCaptureVideoDataOutputSampleBufferDelegate { func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { guard let ciImage = sampleBuffer.convertCIImage() else { return } let timestamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer) localTrackSourceManager.onVideoFrame(image: ciImage, time: timestamp) } } " #
"7$BQUVSFɿϑϨʔϜͷऔΓํ import AVFoundation import UIKit final class VideoChatAVCaptureView: UIView
{ private var session: AVCaptureSession? private func prepare() { let output: AVCaptureVideoDataOutput = AVCaptureVideoDataOutput() output.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoChat")) } } extension VideoChatAVCaptureView: AVCaptureVideoDataOutputSampleBufferDelegate { func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { guard let ciImage = sampleBuffer.convertCIImage() else { return } let timestamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer) localTrackSourceManager.onVideoFrame(image: ciImage, time: timestamp) } } output.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoChat")) EFMFHBUFΛࣗʹ͋ͯ·͢
"7$BQUVSFɿϑϨʔϜͷऔΓํ import AVFoundation import UIKit final class VideoChatAVCaptureView: UIView
{ private var session: AVCaptureSession? private func prepare() { let output: AVCaptureVideoDataOutput = AVCaptureVideoDataOutput() output.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoChat")) } } extension VideoChatAVCaptureView: AVCaptureVideoDataOutputSampleBufferDelegate { func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { guard let ciImage = sampleBuffer.convertCIImage() else { return } let timestamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer) localTrackSourceManager.onVideoFrame(image: ciImage, time: timestamp) } } guard let ciImage = sampleBuffer.convertCIImage() else { return } $.4BNQMF#V⒎FSΛ$**NBHFʹม͠·͢
"7$BQUVSFɿϑϨʔϜͷऔΓํ import AVFoundation import UIKit final class VideoChatAVCaptureView: UIView
{ private var session: AVCaptureSession? private func prepare() { let output: AVCaptureVideoDataOutput = AVCaptureVideoDataOutput() output.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoChat")) } } extension VideoChatAVCaptureView: AVCaptureVideoDataOutputSampleBufferDelegate { func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { guard let ciImage = sampleBuffer.convertCIImage() else { return } let timestamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer) localTrackSourceManager.onVideoFrame(image: ciImage, time: timestamp) } } let timestamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer) $.5JNFΛ࡞͠·͢
"3,JUɿϑϨʔϜͷऔΓํ
"3,JUɿϑϨʔϜͷऔΓํ import ARKit import SceneKit import UIKit final class
VideoChatARKitView: UIView { private lazy var sceneView: ARSCNView = {...}() private func prepare() { sceneView.delegate = self } } extension VideoChatARKitView: ARSCNViewDelegate { func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { guard let sceneView = renderer as? ARSCNView else { return } guard let ciImage = CIImage(image: sceneView.snapshot()) else { return } localTrackSourceManager.onVideoFrame(image: ciImage, time: time) } } " #
import ARKit import SceneKit import UIKit final class VideoChatARKitView: UIView
{ private lazy var sceneView: ARSCNView = {...}() private func prepare() { sceneView.delegate = self } } extension VideoChatARKitView: ARSCNViewDelegate { func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { guard let sceneView = renderer as? ARSCNView else { return } guard let ciImage = CIImage(image: sceneView.snapshot()) else { return } localTrackSourceManager.onVideoFrame(image: ciImage, time: time) } } "3,JUɿϑϨʔϜͷऔΓํ sceneView.delegate = self EFMFHBUFΛࣗʹ͋ͯ·͢
"3,JUɿϑϨʔϜͷऔΓํ import ARKit import SceneKit import UIKit final class
VideoChatARKitView: UIView { private lazy var sceneView: ARSCNView = {...}() private func prepare() { sceneView.delegate = self } } extension VideoChatARKitView: ARSCNViewDelegate { func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { guard let sceneView = renderer as? ARSCNView else { return } guard let ciImage = CIImage(image: sceneView.snapshot()) else { return } localTrackSourceManager.onVideoFrame(image: ciImage, time: time) } } let ciImage = CIImage(image: sceneView.snapshot()) εφοϓγϣοτΛऔಘ͠·͢
"3,JUɿϑϨʔϜͷऔΓํ import ARKit import SceneKit import UIKit final class
VideoChatARKitView: UIView { private lazy var sceneView: ARSCNView = {...}() private func prepare() { sceneView.delegate = self } } extension VideoChatARKitView: ARSCNViewDelegate { func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { guard let sceneView = renderer as? ARSCNView else { return } guard let ciImage = CIImage(image: sceneView.snapshot()) else { return } localTrackSourceManager.onVideoFrame(image: ciImage, time: time) } } time: TimeInterval ͦͷ··͢͜ͱ͕Ͱ͖·͢
·ͱΊ
·ͱΊ (0"- εςοϓ CameraSourceʹҙͷϑϨʔϜΛ༻͢ΔϙΠϯτSink ϑϨʔϜΛऔಘ͢Δ Ճ͢Δ 7JEFP'SBNFΛ ࡞͢Δ ྲྀ͠ࠐΉ
" # $ %