Upgrade to Pro — share decks privately, control downloads, hide ads and more …

abema_devcon.pdf

Kyohei Ito
October 15, 2016
6.9k

 abema_devcon.pdf

Kyohei Ito

October 15, 2016
Tweet

Transcript

  1. AbemaTV Developer
    Conference 2016
    2016/10/15

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  5. ։ൃ౰ॳͷiOSΞϓϦ

    View full-size slide

  6. ݱࡏͷiOSΞϓϦ

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  11. ࠶ੜॲཧͷ࠷దԽ

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  15. 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ΑΓൈਮ

    View full-size slide

  16. 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()
    }
    }
    }

    View full-size slide

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

    View full-size slide

  18. 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
    }
    }
    }

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  22. ϚϧνεϨουॲཧ

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  25. 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)

    View full-size slide

  26. 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)

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide