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
11k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
iOSでmp4をデコードして自分だけの動画プレーヤーを作ろう!/orecon
noppefoxwolf
September 12, 2018
More Decks by noppefoxwolf
See All by noppefoxwolf
High performance GIF playback/iOSDC25
noppefoxwolf
1
620
Spice up your notifications/try!Swift25
noppefoxwolf
3
840
iOSの隠されたAPIを解明し、開発効率を向上させる方法/iOSDC24
noppefoxwolf
2
1.3k
今から理解するApp Intentエコシステム/WWDC24Recap
noppefoxwolf
0
74
既存アプリをvisionOS対応してリリースした話/visionOS LT vol5
noppefoxwolf
0
230
UIのブラックボックスを探る/iOSDC23
noppefoxwolf
3
5.1k
CoreGraphicsでドット絵を描こう/iOSDC22
noppefoxwolf
0
3.2k
ランタイムデバッグのススメ/iOSDC21
noppefoxwolf
1
5.7k
google/mediapipe で始めるARアプリ開発/iOSDC2020
noppefoxwolf
1
1.7k
Other Decks in Programming
See All in Programming
freee が目指す データ マネジメント戦略 AI-Ready 時代を支える 攻めのガバナンスとは
freee
PRO
0
300
Cloudflare is Agents
chimame
0
150
改善しないと、タスクが回らない。 “てんこ盛りポジション” を引き継いだ情シスの、入社3ヶ月の業務改善録
krm963
0
260
壊れたパーサから始める関数型設計と構成的なパーサ #fp_matsuri
raiga0310
2
450
Foundation Models frameworkで画像分析
ryodeveloper
1
600
Welcome to the "Parametricity" 🏙️ − Generic だけど Specific な世界 −
guvalif
PRO
1
210
変わらないものが、変わるものを決める — 意図駆動開発 × イベントソーシング × イミュータブル | What Doesn't Change Decides What Can — IDD × Event Sourcing × Immutability
tomohisa
0
1.4k
今さら聞けない .NET CLI
htkym
0
180
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
18k
継続モナドとリアクティブプログラミング
yukikurage
3
700
その節約、円になってますか?
isamumumu
1
710
Android CLI
fornewid
0
210
Featured
See All Featured
Reality Check: Gamification 10 Years Later
codingconduct
0
2.2k
Design in an AI World
tapps
1
280
The Invisible Side of Design
smashingmag
301
52k
Between Models and Reality
mayunak
4
390
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
200
Measuring & Analyzing Core Web Vitals
bluesmoon
9
950
Marketing to machines
jonoalderson
1
5.7k
Optimizing for Happiness
mojombo
378
71k
The World Runs on Bad Software
bkeepers
PRO
72
12k
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
650
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
200
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