AVFoundation Cra sh при экспорте видео с текстовым слоем - PullRequest
1 голос
/ 03 апреля 2020

В свободное время я занимаюсь разработкой приложения для редактирования видео для iOS.

Я только что возобновил работу над ним после нескольких недель посещения других проектов, и, хотя я не сделал ни одного значительные изменения в коде - , теперь он падает каждый раз, когда я пытаюсь экспортировать мою композицию видео .

Я извлек и собрал точно такой же коммит, который был успешно загружен в TestFlight тогда (и он работал на нескольких устройствах без сбоев), так что, возможно, это проблема с последним Xcode / iOS SDK что я обновил с тех пор?

Код падает на _xpc_api_misuse в потоке:

com.apple.coremedia.basicvideocompositor.output

Навигатор отладки:

enter image description here

Во время создания cra sh в навигаторе отладки было более 70 потоков, поэтому возможно, что-то не так, и приложение использует слишком много потоков (никогда их не видел).


Мое приложение накладывает «водяной знак» на экспортируемое видео, используя текстовый слой. После игры я обнаружил, что cra sh можно предотвратить, если я закомментирую код водяного знака:

    guard let exporter = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality) else {
        return failure(ProjectError.failedToCreateExportSession)
    }
    guard let documents = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) else {
        return failure(ProjectError.temporaryOutputDirectoryNotFound)
    }
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd_HHmmss"
    let fileName = dateFormatter.string(from: Date())
    let fileExtension = "mov"
    let fileURL = documents.appendingPathComponent(fileName).appendingPathExtension(fileExtension)
    exporter.outputURL = fileURL

    exporter.outputFileType = AVFileType.mov
    exporter.shouldOptimizeForNetworkUse = true // check if needed

    // OFFENDING BLOCK (commenting out averts crash)
    if addWaterMark {
        let frame = CGRect(origin: .zero, size: videoComposition.renderSize)
        let watermark = WatermarkLayer(frame: frame)
        let parentLayer = CALayer()
        let videoLayer = CALayer()

        parentLayer.frame = frame
        videoLayer.frame = frame
        parentLayer.addSublayer(videoLayer)
        parentLayer.addSublayer(watermark)
        videoComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: parentLayer)
    }
    // END OF OFFENDING BLOCK

    exporter.videoComposition = videoComposition

    exporter.exportAsynchronously {
    // etc.

Код слоя водяного знака:

class WatermarkLayer: CATextLayer {

    private let defaultFontSize: CGFloat = 48

    private let rightMargin: CGFloat = 10
    private let bottomMargin: CGFloat = 10

    init(frame: CGRect) {
        super.init()
        guard let appName = Bundle.main.infoDictionary?["CFBundleName"] as? String else {
            fatalError("!!!")
        }
        self.foregroundColor = CGColor.srgb(r: 255, g: 255, b: 255, a: 0.5)
        self.backgroundColor = CGColor.clear
        self.string = String(format: String.watermarkFormat, appName)
        self.font = CTFontCreateWithName(String.watermarkFontName as CFString, defaultFontSize, nil)
        self.fontSize = defaultFontSize
        self.shadowOpacity = 0.75
        self.alignmentMode = .right
        self.frame = frame
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented. Use init(frame:) instead.")
    }

    override func draw(in ctx: CGContext) {
        let height = self.bounds.size.height
        let fontSize = self.fontSize
        let yDiff = (height-fontSize) - fontSize/10 - bottomMargin // Bottom (minus margin)

        ctx.saveGState()
        ctx.translateBy(x: -rightMargin, y: yDiff)
        super.draw(in: ctx)
        ctx.restoreGState()
    }
}

Есть идеи, что может произойти?

Возможно, мой код делает что-то не так, что каким-то образом "получил пропуск" в предыдущем SDK из-за какой-то ошибки Apple, которая была исправлена, или из-за дыры в реализации 'что подключено?

1 Ответ

2 голосов
/ 09 апреля 2020

У меня та же проблема. Начинается после iOS 13.4 и отображается только на симуляторе (устройство работает нормально). Если я закомментирую parentLayer.addSublayer(videoLayer), то приложение не обработает sh, но экспортированное видео не является желаемым результатом.

...