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
iOSでmp4をデコードして自分だけの動画プレーヤーを作ろう!/orecon
Search
noppefoxwolf
September 12, 2018
Programming
2
11k
iOSでmp4をデコードして自分だけの動画プレーヤーを作ろう!/orecon
noppefoxwolf
September 12, 2018
Tweet
Share
More Decks by noppefoxwolf
See All by noppefoxwolf
iOSの隠されたAPIを解明し、開発効率を向上させる方法/iOSDC24
noppefoxwolf
2
360
既存アプリをvisionOS対応してリリースした話/visionOS LT vol5
noppefoxwolf
0
170
UIのブラックボックスを探る/iOSDC23
noppefoxwolf
3
3.9k
CoreGraphicsでドット絵を描こう/iOSDC22
noppefoxwolf
0
2.2k
ランタイムデバッグのススメ/iOSDC21
noppefoxwolf
1
4.3k
google/mediapipe で始めるARアプリ開発/iOSDC2020
noppefoxwolf
1
1.4k
モバイルファーストなアプリを作るためにvearがしたこと/xRDCC
noppefoxwolf
0
99
ソーシャルライブサービスにおけるデジタル化粧の仕組みと実装/iOSDC19
noppefoxwolf
4
5.3k
Limited import clarification and its effect/tryswift2019
noppefoxwolf
2
1.2k
Other Decks in Programming
See All in Programming
テストコード書いてみませんか?
onopon
2
130
PHPとAPI Platformで作る本格的なWeb APIアプリケーション(入門編) / phpcon 2024 Intro to API Platform
ttskch
0
260
Effective Signals in Angular 19+: Rules and Helpers @ngbe2024
manfredsteyer
PRO
0
140
Jakarta EE meets AI
ivargrimstad
0
260
Security_for_introducing_eBPF
kentatada
0
110
useSyncExternalStoreを使いまくる
ssssota
6
1.1k
暇に任せてProxmoxコンソール 作ってみました
karugamo
2
720
Effective Signals in Angular 19+: Rules and Helpers
manfredsteyer
PRO
0
110
From Translations to Multi Dimension Entities
alexanderschranz
2
130
情報漏洩させないための設計
kubotak
2
290
CQRS+ES の力を使って効果を感じる / Feel the effects of using the power of CQRS+ES
seike460
PRO
0
140
テストケースの名前はどうつけるべきか?
orgachem
PRO
0
140
Featured
See All Featured
Bootstrapping a Software Product
garrettdimon
PRO
305
110k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
247
1.3M
Code Reviewing Like a Champion
maltzj
520
39k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
6
520
BBQ
matthewcrist
85
9.4k
Rebuilding a faster, lazier Slack
samanthasiow
79
8.7k
No one is an island. Learnings from fostering a developers community.
thoeni
19
3k
Put a Button on it: Removing Barriers to Going Fast.
kastner
59
3.6k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
365
25k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
8
1.2k
Designing Experiences People Love
moore
138
23k
Java REST API Framework Comparison - PWX 2021
mraible
28
8.3k
Transcript
J04ͰNQΛσίʔυͯࣗͩ͠ ͚ͷಈըϓϨʔϠʔΛ࡞Ζ͏ʂ Զίϯ4VNNFS%BZ$ PSFDPO@JPTD
J04%$͓ർΕ༷Ͱͨ͠ʂʂ PSFDPO@JPTD
ϥΠϒ৴ΞϓϦͷΞΠςϜ࠶ੜΛ.FUBMͰ ࣮͢Δࣄʹͳͬͨ J04%$Ͱ݄ʹొஃ͠·ͨ͠ɻ ֤ํ໘ʹ͋Γ͕ͱ͏͍͟͝·͢ʂ IUUQTHPPHM#:X%/# PSFDPO@JPTD
OPQQF ! גࣜձࣾσΟʔɾΤψɾΤʔ " ͖ͭͶ͔Θ͍͍ # ࠓੜ PSFDPO@JPTD
"(&/%" w ಈըͷ࠶ੜํ๏ͱಛ w ϏσΦͷߏཧղ w 4XJGUͰσίʔυॲཧΛॻ͘ w ·ͱΊ PSFDPO@JPTD
Ұ൪؆୯ͳํ๏ PSFDPO@JPTD
"71MBZFS$POUSPMMFS w "7,JUGSBNFXPSL w "71MBZFSΛͤదʹ࠶ੜͯ͘͠ΕΔ w J04 PSFDPO@JPTD
"71MBZFS$POUSPMMFS ͍ํ let vc = AVPlayerViewController() vc.player = AVPlayer(url: url)
present(vc, animated: true, completion: nil) PSFDPO@JPTD
"71MBZFS$POUSPMMFS ! w 04σόΠε͝ͱʹ࠷దͳσβΠϯ w "JSQMBZͳͲʹαϙʔτ w ૢ࡞6*͕ఏڙ͞ΕΔ ! w
6*ػೳͷΧελϚΠζੑͳ͍ PSFDPO@JPTD
6*ΛΧελϚΠζ͍ͨ͠ͱ͖ʁ PSFDPO@JPTD
"71MBZFS-BZFS w "7'PVOEBUJPOGSBNFXPSL w "71MBZFSΛͯ͠ૢ࡞ w J04 PSFDPO@JPTD
"71MBZFS-BZFS let player = AVPlayer(url: url) player.play() let layer =
AVPlayerLayer(player: player) layer.frame = frame view.layer.addSublayer(layer) PSFDPO@JPTD
"71MBZFS-BZFS ! w $"-BZFSͱͯ͠ѻ͑ΔͷͰॊೈ ! w ಛʹͳ͠ PSFDPO@JPTD
ಛʹͳ͠ PSFDPO@JPTD
ಛʹͳ͠ʁ PSFDPO@JPTD
"71MBZFS-BZFSͰࣄΓͳ͍࣌ w 73ΰʔάϧͰݟΕΔΑ͏ʹͯ͠ʈʈ w ө૾͔Βਓ͚ͩൈ͖ग़ͯ͠࠶ੜ͍ͨ͠ʙ w ಈըʹϦΞϧλΠϜͰΤϑΣΫτΛ͔͚͍ͨ PSFDPO@JPTD
"71MBZFS-BZFSͰࣄΓͳ͍࣌ ө૾ࣗମΛ·ͤͨΓɺϑΟϧλΛ͔͚Δʹ "71MBZFS-BZFSͰͰ͖ͳ͍ɻ ಛʹϦΞϧλΠϜͷॲཧʹͳΔ΄Ͳ͍͠ɻ PSFDPO@JPTD
PSFDPO@JPTD
"7"TTFU3FBEFS w "7"TTFU3FBEFS5SBDL0VUQVUͱΈ߹ΘͤΔͱຖ ϑϨʔϜͷ$.4BNQMF#V⒎FS͕औΕΔ PSFDPO@JPTD
"7"TTFU3FBEFS let asset = AVURLAsset(url: url) let video = asset.tracks(withMediaType:
.video).first! let reader = try! AVAssetReader(asset: asset) let output = AVAssetReaderTrackOutput(track: video) if reader.canAdd(output) { reader.add(output) } output.copyNextSampleBuffer() output.copyNextSampleBuffer() output.copyNextSampleBuffer() PSFDPO@JPTD
PSFDPO@JPTD
"7"TTFU3FBEFS ඳըઌࣗ༝ w 6**NBHF7JFX let image = CIImage(cvPixelBuffer: pb) imageView.image
= UIImage(ciimage: image) w "74BNQMF#V⒎FS%JTQMBZ-BZFS let sb = output.copyNextSampleBuffer() displayLayer.enqueue(sb) PSFDPO@JPTD
"7"TTFU3FBEFS w .FUBM CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, textureCache, imageBuffer, nil, pixelFormat, width, height,
0, &imageTexture) // ~ লུ commandBuffer.present(drawable) commandBuffer.commit() PSFDPO@JPTD
"7"TTFU3FBEFS ! w ຖϑϨʔϜͷ4BNQMFS#V⒎FS͕ ಘΒΕΔ ! w ԻผͰॲཧ PSFDPO@JPTD
͜ΕͰԿͰग़དྷͦ͏ PSFDPO@JPTD
͜ΕͰԿͰग़དྷͦ͏ʁ PSFDPO@JPTD
ྫ͑TOBQTIPUͷ PSFDPO@JPTD
TOBQTIPU ωοτϫʔΫϦιʔεͷ63-Λࢦఆͯ͠࠶ੜ͢Δͱɺ ى͜Δɻ ࠶ੜ͍ͯ͠ΔಈըϦιʔεͷεφοϓγϣοτ͕ࡱΕͳ ͍ɻ PSFDPO@JPTD
TOBQTIPU TOBQTIPU7JFX"GUFS4DSFFO6QEBU FT ਅͬ҉ "7"TTFU*NBHF(FOFSBUPS ϩʔΧϧͷΈ "7"TTFU3FBEFS PVUQVUΛଓͰ͖ͳ͍ 04ͷεΫγϣ ࡱΕΔ
PSFDPO@JPTD
٧Μͩ PSFDPO@JPTD
٧ΜͰͳ͍ʂʂʂ PSFDPO@JPTD
ࣗͰө૾Λσίʔυ͢Ε0, PSFDPO@JPTD
PSFDPO@JPTD
5*14 w ϋʔυΣΞσίʔμ ϋʔυͱͯ͠νοϓʹࡌ͞Ε͍ͯΔσίʔμ ߴʹσίʔυՄೳ w ιϑτΣΞσίʔμ ιϑτΣΞͰ࣮͞Εͨσίʔμ جຊతʹ͍ɺ$16ϦιʔεΛ৯͏ ϋʔυΣΞ͕ରԠ͍ͯ͠ͳ͍ίʔσοΫΛ࠶ੜͰ͖Δ
PSFDPO@JPTD
ιϑτΣΞσίʔμͷྫ w CSJPO0(7,JU 7171ͳͲͷιϑτΣΞσίʔμ͕࣮͞Ε͍ͯΔ w POFWDBU"1/(,JU BQOHΛιϑτΣΞσίʔμΛͬͯ$(*NBHFʹσ ίʔυ PSFDPO@JPTD
75%FDPNQSFTTJPO4FTTJPO w 7JEFP5PPMCPYGSBNFXPSL w J04 w ϋʔυΣΞσίʔμͷΠϯλʔϑΣΠε w σίʔυࡁΈͷ$71JYFM#V⒎FSΛฦ͢ PSFDPO@JPTD
.1ͷύʔε
PSFDPO@JPTD
PSFDPO@JPTD
PSFDPO@JPTD
TXJGUͰNQΛCPY͝ͱʹύʔε͢Δ *OQVU4USFBNͰ CPY4J[Fͷॱ൪ͰಡΈଓ͚Ε 0, ಛఆͷCPYͰɺࣗͷCPYʹରͯ͠࠶ݕࡧΛߦ͏ let stream = InputStream(url:
url) stream.open() while stream.hasBytesAvailable { let size = stream.readUint32() let type = stream.readAscii(4) let data = stream.read(size - 8) } IUUQTHJUIVCDPNOPQQFGPYXPMG.1#PY%VNQFSTXJGU PSFDPO@JPTD
NQͷߏ ftyp(24) moov(52997) trak(19399) trak(33461) ... mdat(8754890) ߏྫ PSFDPO@JPTD
GUZQ CZUF͝ͱʹαϙʔτ͍ͯ͠Δϒϥϯυ͕ฒͿ ઌ಄Major Brandɺͦͷ͋ͱCompatible Brand Major Brand: mp42 Compatible Brand:
isom Compatible Brand: mp42 .BKPSͱ$PNQBUJCMFͷؒʹCZUFۭ͘ IUUQXXXGUZQTDPN PSFDPO@JPTD
NEBU ಈըͱԻͷ࣮σʔλ͕֨ೲ͞Ε͍ͯΔɻ PSFDPO@JPTD
NPPW ଟ͘ͷCPYͰߏ͞ΕΔCPY NEBUͷͲͷҐஔʹͲͷσʔλ͕ೖ͍ͬͯΔ͔ͳͲɺ ͜ͷCPYͷதʹ͋ΔCPYͰఆٛ͞Ε͍ͯΔ PSFDPO@JPTD
5*14 'BJS1MBZ %3. NEBUʹ҉߸Խ͞ΕͨΦʔσΟΦσʔλ ϚελʔΩʔΛ҉߸Խͯ͠ίϯςφʹอଘ ϚελʔΩʔͷෳ߹ΩʔΞΧϯτͱ)8ࣝผࢠͰ ཧ IUUQTEFWFMPQFSBQQMFDPNTUSFBNJOHGQT PSFDPO@JPTD
.1͔Βө૾σʔλΛऔΓग़͢ NPPWʹؚ·ΕΔใΛݩʹɺNEBU͔Β୳͢ɻ ͷͰ͕͢ʜ PSFDPO@JPTD
ࠓɺࣄલʹऔΓग़ͨ͠ͷΛ༻ҙ͠·ͨ͠ʜ $ mp4box -raw 1 movie.mp4 Extracting MPEG-4 AVC-H264 stream
to h264 PSFDPO@JPTD
Iͷߏͱσίʔυ IUUQTTQFBLFSEFDLDPNOPQQFGPYXPMGWJEFPEFDPEFPOJPT PSFDPO@JPTD
IUUQTEFWFMPQFSBQQMFDPNWJEFPTQMBZXXED
ొਓ w *ϑϨʔϜ w #1ϑϨʔϜ w 414114 ͜ΕΒ͕/"-ͱݺΕΔߏʹೖͬͯฒΜͰ͍Δ PSFDPO@JPTD
*ϑϨʔϜ w Iɺ̍ຕͷը૾ͱͦͷࠩͰඵͷө૾Λදݱ ͢Δ w *%31JDUVSFͦͷݩʹͳΔ̍ຕ w ΩʔϑϨʔϜͱݴ͏ PSFDPO@JPTD
1#ϑϨʔϜ w *ϑϨʔϜ͔Βͷࠩใ w 1͕̍ຕ͔Β༧ଌͨ͠εϥΠε w #͕̎ຕ͔Β༧ଌͨ͠εϥΠε #J 1SFEJDUJWF༧ଌ
PSFDPO@JPTD
414 4FRVFODF1BSBNFUFS4FU ϓϩϑΝΠϧɺϨϕϧ 114 1JDUVSF1BSBNFUFS4FU ϐΫνϟͷූ߸Խ PSFDPO@JPTD
/"-ͷऔΓग़͠ํ
PSFDPO@JPTD
/"-6IFBEFS /"-ͷछྨ͕ॻ͔Ε͍ͯΔ YdYεϥΠε Y*ϑϨʔϜ PSFDPO@JPTD
75%FDPNQSFTT4FTTJPO ࣮ࡍ$ͷΠϯλʔϑΣΠεͳͷͰɺ4XJGUΠϯλʔ ϑΣΠεΛͬͨٙࣅίʔυͰղઆ PSFDPO@JPTD
75%FDPNQSFTT4FTTJPOͷॳظԽ let desc: CMVideoFormatDescription = ~~ let callback = {
(imageBuffer: CVImageBuffer?) in } let attrib = [.pixelFormat : .gbra] let session = VTDecompressSession(desc, params, attrib, callback) PSFDPO@JPTD
$.7JEFP'PSNBU%FTDSJQUJPO let pps: [UInt8] = ~~ let sps: [UInt8] =
~~ let desc = CMVideoFormatDescriptionCreateFromH264ParameterSets([pps, pps]) PSFDPO@JPTD
75%FDPNQSFTT4FTTJPO session.decodeFrame(sampleBuffer) PSFDPO@JPTD
σίʔμʹ͢4BNQMF#V⒎FS let packet = (IϑϨʔϜB/PϑϨʔϜɾεϥΠε) let blockBuffer = CMBlockBuffer(packet) let
sampleBuffer = CMSampleBuffer(blockBuffer) PSFDPO@JPTD
ԻपΓ "VEJP5PPMCPY PSFDPO@JPTD
"VEJP4FSWJDF2VFVF PSFDPO@JPTD
"VEJP4FSWJDF2VFVFͷॳظԽ let format: AudioStreamBasicDescription = file[kAudioFilePropertyDataFormat] let callback = {
} let audioQueue = AudioQueue(format, callback) PSFDPO@JPTD
"VEJP2VFVFͷFORVFVF let buffer = audioQueue.allocate(size) buffer.read(packet) audioQueue.enqueue(buffer) PSFDPO@JPTD
·ͱΊ PSFDPO@JPTD
75"5Ͳ͏͍͏࣌ʹ͏͖ʁ w "7,JU"7'PVOEBUJPOͰ࣮ग़དྷͳ͍࣌ͷ࠷ऴฌث w SUNQͷετϦʔϛϯάͷදࣔͱ͔ PSFDPO@JPTD
ษڧํ๏ w TIPHP)BJTIJO,JUTXJGU NQͷCPYߏ͕Ϋϥεఆٛ͞Ε͍ͯͨΓ͢ΔͷͰɺ࣮ϕʔεͰཧղ͍͢͠ w վగࡾ൛)"7$ڭՊॻ ΠϯϓϨεඪ४ڭՊॻγϦʔζ ූ߸Խͷͱߏͷ͕ຊޠͰॻ͍ͯ͋Δɻগ͠ཧղ͔ͯ͠ΒಡΉͱಡΊͦ ͏ɻʢ8*1ʣ w
͋ͱ༷ॻͱ͔ʜ PSFDPO@JPTD
Ҏ্Ͱ͢ʂʢͪΐͬͱએʣ PSFDPO@JPTD
ٕज़ॻయ̑ OPQQFMBC͑ ຊग़͠·͢ʂʢ8*1ʣ PSFDPO@JPTD
1PDPDIB ৴αʔϏεʹڵຯͷ͋ΔΤϯδχΞืूதʂ PSFDPO@JPTD
͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ ࠓޙͱΑΖ͓͘͠ئ͍͠·͢ PSFDPO@JPTD