VideoFlint / Cabbage

A video composition framework build on top of AVFoundation. It's simple to use and easy to extend.
MIT License
1.52k stars 221 forks source link

图片无法在VIPlayer播放 #17

Closed AbySwifter closed 5 years ago

AbySwifter commented 5 years ago

我参考VideoCat的Demo从相册中选择了图片

let resource = PHAssetImageResource.init(asset: asset, duration: CMTime.init(value: 3000, 600))
            guard let task = resource.prepare(progressHandler: progressHandler, completion: { (status, error) in
                if status == .avaliable {
                    resource.selectedTimeRange = CMTimeRange.init(start: CMTime.zero, end: resource.duration)
                    let trackItem: TrackItem = TrackItem(resource: resource)
                    let transition = CrossDissolveTransition()
                    transition.duration = CMTime(value: 900, timescale: 600)
                    trackItem.videoTransition = transition
                    let audioTransition = FadeInOutAudioTransition(duration: CMTime(value: 66150, timescale: 44100))
                    trackItem.audioTransition = audioTransition
                    if resource.isKind(of: ImageResource.self) {
                        trackItem.videoConfiguration.contentMode = .custom
                    } else {
                        trackItem.videoConfiguration.contentMode = .aspectFill
                    }
                    complete(trackItem)
                } else {
                    Log.error("image track status is \(status), check prepare function, error: \(error?.localizedDescription ?? "")")
                    complete(nil)
                }
            })

然后检查了,图片的选择,在 resource.prepare中,Image是存在的,status也是 available的。

public func reloadPlayerItem(_ items: [TrackItem]) -> AVPlayerItem {
        let timeLine = TimeLineManager.current.timeline
        let width = UIScreen.main.bounds.width * UIScreen.main.scale
        let height = width
        timeLine.videoChannel = items
        timeLine.audioChannel = items
        do {
            try Timeline.reloadVideoStartTime(providers: timeLine.videoChannel)
        } catch {
            assert(false, error.localizedDescription)
        }
        timeLine.renderSize = CGSize.init(width: width, height: height)
        let compositonGenerator = CompositionGenerator.init(timeline: timeLine)
        return compositonGenerator.buildPlayerItem()
    }

这是buildItem的方法,视屏和livephoto都没有问题,只有图片无法正常播放,在播放器的时长也不对。

master分支。 xcode 10.2.2 swift 5.0

AbySwifter commented 5 years ago

我在buildPlayerItem中断点调试,发现

CompositionGenerator.swift 85行

timeline.videoChannel.enumerated().forEach({ (offset, provider) in
            for index in 0..<provider.numberOfVideoTracks() {
                let trackID: Int32 = getVideoTrackID(for: index) + Int32((offset % 2 + 1) * 1000)
                if let compositionTrack = provider.videoCompositionTrack(for: composition, at: index, preferredTrackID: trackID) {
                    let info = mainVideoTrackInfo.first(where: { $0.track == compositionTrack })
                    if let info = info {
                        info.info.append(provider)
                    } else {
                        let info = TrackInfo.init(track: compositionTrack, info: [provider])
                        mainVideoTrackInfo.append(info)
                    }
                }
            }

这段代码中,provider.numberOfVideoTracks(),的值始终为0.PHAssetImageResource生成的TrackItem。

AbySwifter commented 5 years ago

我解决了这个问题。在下面的方法里,添加了对Bundle的定义:

 private static let emptyAsset: AVAsset? = {
        let bundle = Bundle(for: ImageResource.self)
        /// 这里添加的3行代码解决了上述问题
        if let videoURL = bundle.url(forResource: "black_empty", withExtension: "mp4") {
            return AVAsset(url: videoURL)
        }
        if let bundleURL = bundle.resourceURL?.appendingPathComponent("Cabbage.bundle") {
            let resourceBundle = Bundle.init(url: bundleURL)
            if let videoURL = resourceBundle?.url(forResource: "black_empty", withExtension: "mp4") {
                return AVAsset(url: videoURL)
            }
        }

        if let url = Bundle.main.url(forResource: "black_empty", withExtension: "mp4") {
            let asset = AVAsset(url: url)
            return asset
        }

        return nil
    }()
vitoziv commented 5 years ago

这个修改欢迎提交 pr

AbySwifter commented 5 years ago

好的,我会在最近提交PR