Slide 1

Slide 1 text

AbemaTV Developer Conference 2016 2016/10/15

Slide 2

Slide 2 text

About Me ҏ౻ɹګฏ Github : KyoheiG3 Twitter : @KyoheiG3

Slide 3

Slide 3 text

ΠϯλϥΫςΟϒͳUIͷ ͨΊͷAVPlayerϕετ ϓϥΫςΟε

Slide 4

Slide 4 text

iOSΞϓϦͷ֓ཁ • 3ͭͷಈըΛ࠶ੜ͍ͯ͠ΔϑΟʔυ • ൪૊ද

Slide 5

Slide 5 text

։ൃ౰ॳͷiOSΞϓϦ

Slide 6

Slide 6 text

ݱࡏͷiOSΞϓϦ

Slide 7

Slide 7 text

ԣදࣔΞϓϦͷ೉͍͠ͱ͜Ζ • βοϐϯάதͰ΋ࠨӈͷಈըΛ࠶ੜ͢Δඞཁ͕͋Δ

Slide 8

Slide 8 text

ԣදࣔΞϓϦͷ೉͍͠ͱ͜Ζ • ӅΕΔಈըͷഁغ͕ॏ͍

Slide 9

Slide 9 text

ԣදࣔΞϓϦͷ೉͍͠ͱ͜Ζ • ݱΕΔಈըͷ४උ͕ॏ͍

Slide 10

Slide 10 text

ղܾ͢΂͘ߦͬͨ͜ͱ • ࠶ੜॲཧͷ࠷దԽ • ϚϧνεϨουॲཧ

Slide 11

Slide 11 text

࠶ੜॲཧͷ࠷దԽ

Slide 12

Slide 12 text

ಈըΛ࠶ੜ͢Δ·Ͱͷ͓͞Β͍

Slide 13

Slide 13 text

AVAssetͷ஫ҙ఺ Ξηοτʢ·ͨ͸τϥοΫʣΛॳظԽͯ͠΋ɺͦͷΞΠςϜʹ ؔͯ͠औಘ͍ͨ͢͠΂ͯͷ৘ใ͕͙͢ʹಘΒΕΔͱ͸ݶΓ·ͤ Μɻ৔߹ʹΑͬͯ͸ɺΞΠςϜͷ࠶ੜ࣌ؒ΋ܭࢉ͢Δඞཁ͕͋ Γ·͢ʢͨͱ͑͹ɺMP3ϑΝΠϧʹ͸ཁ໿৘ใؚ͕·Ε͍ͯͳ ͍৔߹͕͋Γ·͢ʣɻ1 1 AVFoundationϓϩάϥϛϯάΨΠυΑΓҾ༻

Slide 14

Slide 14 text

AVAssetͷ஫ҙ఺ AVAsset͸৔߹ʹΑͬͯ͸࣮ߦεϨουΛϒϩοΫͯ͠Ͱ΋ί ϯςϯπͷಡΈࠐΈΛߦ͓͏ͱ͢Δ৔߹͕͋Δ!! AVAssetͱ͸ɺϝσΟΞσʔλʹؔ͢Δ৘ใ͕·ͱ·ͬͨΦϒδ ΣΫτɻ

Slide 15

Slide 15 text

AVAssetͷplayableͳͲ͸loadValuesAsynchronouslyͰΠϕ ϯτΛड͚͔ͯΒॲཧΛߦ͏ // Load the asset's "playable" key asset.loadValuesAsynchronously(forKeys: ["playable"]) { var error: NSError? = nil let status = asset.statusOfValue(forKey: "playable", error: &error) switch status { case .loaded: // Sucessfully loaded, continue processing case .failed: // Examine NSError pointer to determine failure case .cancelled: // Loading cancelled default: // Handle all other cases } } ※AppleͷAPI ReferenceΑΓൈਮ

Slide 16

Slide 16 text

RxͰloadValuesAsynchronouslyΛߪಡ͢Δ extension Reactive where Base: AVAsset { public var playable: Observable { let keys = ["playable"] return Observable.create { observer in self.base.loadValuesAsynchronously(forKeys: keys) { observer.onNext(self.base.isPlayable) } return Disposables.create() } } }

Slide 17

Slide 17 text

AVPlayer͸playableͷΠϕϯτΛड͚͔ͯΒ࡞੒͍ͯ͠Δ asset.rx.playable .filter { $0 == true } .observeOn(MainScheduler.instance) .subscribe(onNext: { [weak self] _ in self?.player = AVPlayer(playerItem: playerItem) }) .addDisposableTo(disposeBag)

Slide 18

Slide 18 text

AVPlayerLayerͷreadyForDisplayΛߪಡ͢Δ extension Reactive where Base: AVPlayerLayer { var ready: Observable { let key = "readyForDisplay" return observe(AnyObject.self, key, options: [], retainSelf: false) .map { _ in Void() } .filter { self.base.isReadyForDisplay == true } } }

Slide 19

Slide 19 text

readyForDisplay͕trueʹͳͬͨΒදࣔॲཧΛߦ͍ͬͯΔ rx.ready .observeOn(MainScheduler.instance) .subscribe(onNext: { [weak self] in self?.hidden = false }) .addDisposableTo(disposeBag)

Slide 20

Slide 20 text

ಈըͷಡΈࠐΈ։࢝࣌͸௿BitRateʹઃఆ • ௿BitRateͰɺ࠶ੜ։࢝·Ͱͷ࣌ؒΛ୹ॖ • ಈըͷղ૾౓͸௿͍΄͏͕CPUͷෛՙ͸௿͍ͷͰɺ྆࿬ͷಈ ըͷղ૾౓͸௿͘ઃఆ

Slide 21

Slide 21 text

replaceCurrentItem(with:)͸࢖Θͳ͍ • ϝΠϯεϨουͰ࢖͏ʹ͸ύϑΥʔϚϯε͕ΠϚΠν • ॳظԽͯ͠࢖͏৔߹ͱ࠶ར༻ͯ͠࢖͏৔߹ͷ2ຊཱͯʹͳͬͯ ͠·͏ • αϒεϨουͰద੾ʹॲཧͰ͖ͳ͍ʢ˞ޙड़

Slide 22

Slide 22 text

ϚϧνεϨουॲཧ

Slide 23

Slide 23 text

ϚϧνεϨουॲཧͷ஫ҙ఺ UI͸ϝΠϯεϨουͰॲཧ͢Δ!! ϝΠϯεϨουҎ֎ͰUIΛૢ࡞ͨ͠৔߹ͷڍಈ͸อূ͞Ε͍ͯ ͳ͍ɻʢৗࣝͰ͢Ͷ

Slide 24

Slide 24 text

ϚϧνεϨουॲཧͷ஫ҙ఺ ҋӢʹαϒεϨουʹ౤͛ͳ͍!! αϒεϨουͷॲཧ͸ɺεΫϩʔϧͳͲUIૢ࡞ʹର͢ΔϝΠϯ εϨουॲཧͷ༏ઌ౓ʹෛ͚ͯ͠·͍ɺಈըࢹௌͷUXΛ௿Լ͞ ͤΔ৔߹͕͋Δɻ

Slide 25

Slide 25 text

AVAssetͱAVPlayerItem͸αϒεϨουͰ࡞੒͍ͯ͠Δ class VideoPlayer { init(url: URL) { let asset = AVURLAsset(url: url) playerItem = AVPlayerItem(asset: asset) } } rx.streamUrl .observeOn(scheduler) // αϒεϨουͰॲཧ .subscribe(onNext: { [weak self] url in self?.videoPlayer = VideoPlayer(url: videoURL) }) .addDisposableTo(disposeBag)

Slide 26

Slide 26 text

playable͕trueʹͳͬͨΒϝΠϯεϨουͰAVPlayerΛ࡞੒ ͍ͯ͠Δ videoPlayer.asset.rx.playable .filter { $0 == true } .observeOn(MainScheduler.instance) // ϝΠϯεϨουͰॲཧ .subscribe(onNext: { [weak self] _ in self?.player = AVPlayer(playerItem: playerItem) }) .addDisposableTo(disposeBag)

Slide 27

Slide 27 text

AVPlayerͱAVPlayerLayerͷഁغ͸αϒεϨουͰߦ͍ͬͯΔ deinit { let layer = playerLayer let qos = DispatchQoS.QoSClass.background DispatchQueue.global(qos: qos).async { layer.videoPlayer = nil layer.player = nil } }

Slide 28

Slide 28 text

AVPlayerͱAVPlayerLayer͸ηοτͰഁغ͢Δ AVPlayer͚ͩΛαϒεϨουͰഁغ͢Δͱɺͦͷ͏ͪಈը͕࠶ ੜ͞Εͳ͘ͳΔࣄ͕͋ͬͨ!! AVPlayerͷഁغͷॲཧ͕ޙճ͠ʹ͞ΕͯɺAVPlayer࡞੒਺ͷ্ ݶʹୡ͍ͯ͠ΔΑ͏ͳڍಈɻ

Slide 29

Slide 29 text

replaceCurrentItem(with:)͸࢖Θͳ͍ • AVPlayerͷ࡞੒͸ϝΠϯεϨουͷํ͕ྑͦ͞͏ • AVPlayerͷഁغ͸αϒεϨουͷํ͕ྑͦ͞͏ • replaceCurrentItem(with:)͸྆ํͷئ͍Λ׎͑ͯ͘ΕΔ ͜ͱ͸ແ͔ͬͨ

Slide 30

Slide 30 text

·ͱΊ

Slide 31

Slide 31 text

·ͱΊ • AVAssetͷ஋͸ϩʔυ͕׬͔ྃͯ͠Βࢀর͢Δ • ద੾ͳBitRateʹઃఆ͢Δ • αϒεϨουͰద੾ʹॲཧ͢Δʢಛʹഁغʣ • replaceCurrentItem(with:)͸࢖Θͳ͍

Slide 32

Slide 32 text

Thanks!

Slide 33

Slide 33 text

͓·͚ • CIʹ͍ͭͯ • Swift3ʹ͍ͭͯ