Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Let's make an Immersive Video with APMP
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Shingo Tamaki
August 10, 2025
Technology
55
0
Share
Let's make an Immersive Video with APMP
This document summarizes a brief explanation of APMP, which was announced at WWDC25.
Shingo Tamaki
August 10, 2025
More Decks by Shingo Tamaki
See All by Shingo Tamaki
Use Gemini CLI from Claude Code as part of Sub Agent
tamaki
0
290
Firebase Studioで始めるモバイルアプリ開発入門
tamaki
0
46
Introduction to Claude Code Action
tamaki
0
780
AIエージェントを使ったiOSアプリ開発を試してみた
tamaki
0
190
沖縄モバイルアプリ開発勉強会#1
tamaki
0
150
iOSアプリ開発を始めよう
tamaki
0
250
詳解xcresult.pdf
tamaki
0
430
メルペイでのリグレッションテスト自動化推進のこれまでとこれから
tamaki
0
820
What do you want to test with UI Test v2
tamaki
2
930
Other Decks in Technology
See All in Technology
OPENLOGI Company Profile for engineer
hr01
1
62k
Oracle AI Database@AWS:サービス概要のご紹介
oracle4engineer
PRO
4
2.2k
【関西電力KOI×VOLTMIND 生成AIハッカソン】空間AIブレイン ~⼤阪おばちゃんフィジカルAIに続く道~
tanakaseiya
0
180
プロダクトを触って語って理解する、チーム横断バグバッシュのすすめ / 20260411 Naoki Takahashi
shift_evolve
PRO
1
210
ASTのGitHub CopilotとCopilot CLIの現在地をお話しします/How AST Operates GitHub Copilot and Copilot CLI
aeonpeople
1
200
AWSで2番目にリリースされたサービスについてお話しします(諸説あります)
yama3133
0
130
推し活エージェント
yuntan_t
1
870
マルチモーダル非構造データとの闘い
shibuiwilliam
1
280
【PHPカンファレンス小田原2026】Webアプリケーションエンジニアにも知ってほしい オブザーバビリティ の本質
fendo181
0
320
第26回FA設備技術勉強会 - Claude/Claude_codeでデータ分析 -
happysamurai294
0
390
Databricksを用いたセキュアなデータ基盤構築とAIプロダクトへの応用.pdf
pkshadeck
PRO
0
200
BIツール「Omni」の紹介 @Snowflake中部UG
sagara
0
240
Featured
See All Featured
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
500
Keith and Marios Guide to Fast Websites
keithpitt
413
23k
Believing is Seeing
oripsolob
1
110
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9k
My Coaching Mixtape
mlcsv
0
94
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
Breaking role norms: Why Content Design is so much more than writing copy - Taylor Woolridge
uxyall
0
240
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
1
500
Chasing Engaging Ingredients in Design
codingconduct
0
160
Building a Scalable Design System with Sketch
lauravandoore
463
34k
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
2k
Odyssey Design
rkendrick25
PRO
2
560
Transcript
͓खݩͷಈըΛAPMPʹ ม͓ͯ͠खܰʹΠϚʔ γϰͳମݧΛ࡞Ζ͏ʂ
None
visionOSͰݟΔ͜ͱ͕Ͱ͖Δಈըͷछྨ
Apple Projected Media Profile
Apple Projected Media Profile 360°ಈըͷΑ͏ͳӨܕϝσΟΞΛѻ͏ͨΊʹISOBMFFͷ֦ு ͱͯ͠࡞ΒΕͨϓϩϑΝΠϧ
ISOBMFF (ISO Base Media File Format) ߏ ISOBMFF File ftyp
(File Type Box) ϑΝΠϧλΠϓɺϒϥϯυɺޓੑใ moov (Movie Box) - ϝλσʔλίϯςφ mvhd (Movie Header) શମͷ࣌ؒใ trak (Track Box) τϥοΫใ mvex (Movie Extends) ϑϥάϝϯτ༻֦ு tkhd ϔομʔ mdia ϝσΟΞ mdhd hdlr minf mdat (Media Data Box) ࣮ࡍͷϝσΟΞσʔλʢԻɾө૾ɾࣈນͳͲʣ ௨ৗϑΝΠϧͷେ෦ΛΊΔ free/skip (Free Space) ະ༻ྖҬ udta (User Data) Ϣʔβʔσʔλ ͦͷଞͷBox ֦ுɾΧελϜBox ɿBox ֊ߏΛ࣋ͪɺ֤Box size (4bytes) + type (4bytes) + data Ͱߏ͞ΕΔ ISOBMFFɺQTFFͱ • ISOBMFFϏσΦΦʔσΟΦͳͲ ͷϚϧνϝσΟΞσʔλΛؚΉϑΝΠ ϧͷҰൠతͳߏ͕ఆٛ͞Εͨࠃࡍ ج४ͷϑΥʔϚοτ • QTFF͕ϕʔε • MP4ISOBMFFʹج͍࣮ͮͨࡍͷ ϑΝΠϧܗࣜ
ISOBMFFͷ֦ுʹͭ ͍ͯ • Apple͕ۭؒϏσΦͷͨΊʹՃ͠ ֦ͨு: vexu(Video Extended Usage)
APMPʹରԠ͢ΔͱͲ͏ͳΔͷ͔ʁ • visonOSͷඪ४ͷࣸਅΞϓϦࣗͷΞϓϦ͔ΒΠϚʔγϒ ͳಈըͷ࠶ੜ͕Ͱ͖ΔΑ͏ʹͳΔ
APMPܗࣜͷಈըͷ࡞Γํ 1. CLIπʔϧʢavconvertʣ·ͨmacOSʢbetaʣͷػೳΛͬ ͯม͢Δ 2. طଘͷҰ෦ͷΧϝϥͰͬͨಈըࣗಈͰมͰ͖Δ 3. APIΛͬͯม͢Δ(Appleͷαϯϓϧίʔυ͋Γ)
1. avconvert
2. ࣗಈม 1. ·ͣInsta360͔Go ProΛߪೖ͠·͠ΐ͏ 2. Insta360 StudioͰMP4ग़ྗ͠·͢ 3. AirDropͰAVPʢvisionOS
26 betaʣૹΔ 4. visionOSͰ֘ϑΝΠϧΛ։͘ࡍʹม͢Δ͔Ͳ͏͔μΠΞ ϩά͕ग़ͯ͘ΔͷͰબͿ
3. APIΛͬͯม͢Δ AppleͷαϯϓϧίʔυProjectedMediaConversionΛ༻͠· ͢ https://developer.apple.com/documentation/AVFoundation/ converting-projected-video-to-apple-projected-media-profile
ॲཧͷྲྀΕ 1. ݩಈըಡΈࠐΈ 2. ύοΩϯάઃఆ 3. ѹॖϓϩύςΟઃఆ 4. Τϯίʔμʔͷઃఆ 5.
ॻ͖ग़͠
ύοΩϯά ཱମࢹʢstereoscopicʣͷ߹ύοΩ ϯά͕ҎԼͷ͍ͣΕ͔Ͱ͋Δ͔Λࢦఆ͠ ·͢ • SideBySide • OverUnder
ύοΩϯά if let viewPackingKind = projectedMediaMetadata.viewPackingKind { isFramePacked = true
if viewPackingKind.caseInsensitiveCompare("SideBySide") == .orderedSame { horizontalScale = 2.0 isSideBySide = true } else if viewPackingKind.caseInsensitiveCompare("OverUnder") == .orderedSame { verticalScale = 2.0 } } let eyeFrameSize = CGSize(width: sourceVideoFrameSize.width / horizontalScale, height: sourceVideoFrameSize.height / verticalScale) ... let cropRectDict = [ kCVImageBufferCleanApertureHorizontalOffsetKey: apertureHorizontalOffset, kCVImageBufferCleanApertureVerticalOffsetKey: apertureVerticalOffset, kCVImageBufferCleanApertureWidthKey: eyeFrameSize.width, kCVImageBufferCleanApertureHeightKey: eyeFrameSize.height ]
ѹॖϓϩύςΟͷઃఆ let MVHEVCVideoLayerIDs = [0, 1] let MVHEVCViewIDs = [0,
1] let MVHEVCLeftAndRightViewIDs = [0, 1] ... let stereoCompressionProperties: [CFString: Any] = [ kVTCompressionPropertyKey_MVHEVCVideoLayerIDs: MVHEVCVideoLayerIDs, kVTCompressionPropertyKey_MVHEVCViewIDs: MVHEVCViewIDs, kVTCompressionPropertyKey_MVHEVCLeftAndRightViewIDs: MVHEVCLeftAndRightViewIDs, kVTCompressionPropertyKey_HasLeftStereoEyeView: true, kVTCompressionPropertyKey_HasRightStereoEyeView: true ]
ѹॖϓϩύςΟͷઃఆʢ2ʣ let projectionKind = projectedMediaMetadata.projectionKind ... compressionProperties[kVTCompressionPropertyKey_ProjectionKind] = kCMFormatDescriptionProjectionKind_HalfEquirectangular ...
let baselineInMicrometers = UInt32(1000.0 * baselineInMillimeters) compressionProperties[kVTCompressionPropertyKey_StereoCameraBaseline] = baselineInMicrometers ... let encodedHorizontalFOV = UInt32(1000.0 * horizontalFOV) compressionProperties[kVTCompressionPropertyKey_HorizontalFieldOfView] = encodedHorizontalFOV
Τϯίʔμʔͷઃఆ let outputSettings: [String: Any] = [ AVVideoCodecKey: AVVideoCodecType.hevc, AVVideoWidthKey:
eyeFrameSize.width, AVVideoHeightKey: eyeFrameSize.height, AVVideoCompressionPropertiesKey: compressionProperties ]
ॻ͖ग़͠ for (layerID, eye) in zip(MVHEVCVideoLayerIDs, eyes) { let pixelBuffer
= try pixelBufferPool.makeMutablePixelBuffer() ... ΓऔΓൣғࢉग़ॲཧʢলུʣ ... CVBufferSetAttachment(imageBuffer, kCVImageBufferCleanApertureKey, cropRectDict as CFDictionary, CVAttachmentMode.shouldPropagate) VTSessionSetProperty(session, key: kVTPixelTransferPropertyKey_ScalingMode, value: kVTScalingMode_CropSourceToCleanAperture) pixelBuffer.withUnsafeBuffer { cvPixelBuffer in guard VTPixelTransferSessionTransferImage(session, from: imageBuffer, to: cvPixelBuffer) == noErr else { fatalError("Error during pixel transfer session for layer \(layerID)") } } // Create and append a tagged buffer for this eye. let tags: [CMTag] = [.videoLayerID(Int64(layerID)), .stereoView(eye)] taggedBuffers.append(.init(tags: tags, content: .pixelBuffer(.init(pixelBuffer)))) }
ॻ͖ग़͠ // Create and append a tagged buffer for this
eye. let tags: [CMTag] = [.videoLayerID(Int64(layerID)), .stereoView(eye)] taggedBuffers.append(.init(tags: tags, content: .pixelBuffer(.init(pixelBuffer))))
ग़དྷ্͕Γʂ
!
ࣗݾհ ۄ৴ޛ iOS DeveloperʢϑϦʔϥϯεʣ ԭೄࡏॅ ίϛϡχςΟ׆ಈ - try! Swift TokyoӡӦ
- ԭೄϞόΠϧΞϓϦ։ൃษڧձӡӦ
Okinawa.swiftͲ͏Ͱ͠ΐ͏ʁ
Ҏ্