iOS 10 ломает пользовательский CIFilter

Я написал фильтр хромакея, чтобы сделать фон фильмов MPEG прозрачным, чтобы вы могли использовать файл фильма для более длинных анимаций без необходимости длинных последовательностей PNG (как это обычно делается для некоторых типов анимации iOS).

Я использую AVPlayer, AVVideoComposition и пользовательский CIFilter для рендеринга видео поверх фонового изображения. Фоновое изображение может динамически изменяться пользователем, взаимодействующим с приложением.

Раньше это работало нормально, пока не вышла iOS 10, а теперь не работает.

Что происходит сейчас, так это то, что видео воспроизводится, но хроматический ключ не происходит, и Xcode постоянно выдает следующую ошибку:

need a swizzler so that YCC420v can be written.

Вот изображение того, что должен произвести CIFilter:

результат работы пользовательского CIFilter (до iOS 10)

И вместо этого это то, что он производит (начиная с iOS 10):

результат со сломанным CIFilter (после iOS 10)

Вот раздел моего кода, который создает EAGLContext и применяет пользовательский CIFilter:

    let myEAGLContext = EAGLContext.init(API: EAGLRenderingAPI.OpenGLES2)
    //let cicontext = CIContext.init(EAGLContext: myEAGLContext, options: [kCIContextWorkingColorSpace: NSNull()])
    let cicontext = CIContext.init(EAGLContext: myEAGLContext)

    let filter = ChromaKeyFilter()
    filter.activeColor = CIColor.init(red: 0, green:1.0, blue: 0.0)
    filter.threshold = self.threshold

    //most of below comes from the "WWDC15 What's New In Core Image" slides
    let vidComp = AVVideoComposition(asset: videoAsset!,
                                     applyingCIFiltersWithHandler:
        {
            request in
            let input = request.sourceImage.imageByClampingToExtent()

            filter.inputImage = input

            let output = filter.outputImage!.imageByClampingToExtent()
            request.finishWithImage(output, context: cicontext)
            self.reloadInputViews()

    })

    let playerItem = AVPlayerItem(asset: videoAsset!)
    playerItem.videoComposition = vidComp
    self.player = AVPlayer(playerItem: playerItem)
    self.playerInitialized = true
    let layer = AVPlayerLayer(player: player)

    self.subviews.forEach { subview in
        subview.removeFromSuperview()
    }

    layer.frame = CGRect(x: 0.0, y: 0.0, width: self.frame.size.width, height: self.frame.size.height)
    self.layer.addSublayer(layer)

А вот код для пользовательского CIFilter:

private class ChromaKeyFilter : CIFilter {
private var kernel: CIColorKernel!
var inputImage: CIImage?
var activeColor = CIColor(red: 0.0, green: 1.0, blue: 0.0)
var threshold: Float = 0.05

override init() {
    super.init()
    kernel = createKernel()
}

required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)!
    kernel = createKernel()
}

override var outputImage: CIImage? {
    if let inputImage = inputImage {
        let dod = inputImage.extent
        let args = [inputImage as AnyObject, activeColor as AnyObject, threshold as AnyObject]
        return kernel.applyWithExtent(dod, arguments: args)
    }
    return nil
}

private func createKernel() -> CIColorKernel {
    let kernelString =
        "kernel vec4 chromaKey( __sample s, __color c, float threshold ) { \n" +
            //below kernel was adapted from the GPUImage custom chromakeyfilter:
            //https://github.com/BradLarson/GPUImage/blob/master/framework/Source/GPUImageChromaKeyFilter.m#L30
            "  float maskY = 0.2989 * c.r + 0.5866 * c.g + 0.1145 * c.b;\n" +
            "  float maskCr = 0.7132 * (c.r - maskY);\n" +
            "  float maskCb = 0.5647 * (c.b - maskY);\n" +
            "  float Y = 0.2989 * s.rgb.r + 0.5866 * s.rgb.g + 0.1145 * s.rgb.b;\n" +
            "  float Cr = 0.7132 * (s.rgb.r - Y);\n" +
            "  float Cb = 0.5647 * (s.rgba.b - Y);\n" +
            "  float blendValue = smoothstep(threshold, threshold + 0.5, distance(vec2(Cr, Cb), vec2(maskCr, maskCb)));\n" +
            "  return blendValue * vec4( s.rgb, 1.0 ); \n" +
    "}"
    let kernel = CIColorKernel(string: kernelString)
    return kernel!
}

}

У кого-нибудь есть идеи о том, почему это только сейчас ломается? Интересно, ломается только на телефоне. Он по-прежнему работает в симуляторе, хотя и намного медленнее, чем до выхода iOS 10.


person Geoffrey Wall    schedule 25.09.2016    source источник
comment
Возможная параллель здесь: stackoverflow.com/questions/33097976/   -  person matt    schedule 25.09.2016


Ответы (1)


Похоже, что какая-то часть (уровень игрока?) конвейера iOS10 (устройства) переключилась на YUV.

Установка pixelBufferAttributes вашего AVPlayerLayer на BGRA устраняет отсутствие альфы и заглушает зарегистрированную ошибку:

layer.pixelBufferAttributes = [kCVPixelBufferPixelFormatTypeKey as String: NSNumber(value: kCVPixelFormatType_32BGRA)]
person Rhythmic Fistman    schedule 26.09.2016
comment
Спасибо за это! у меня это работает с небольшими изменениями: layer.pixelBufferAttributes = [kCVPixelBufferPixelFormatTypeKey as String: NSNumber(unsignedInt: kCVPixelFormatType_32BGRA)] - person Geoffrey Wall; 09.10.2016
comment
Ой, мой плохой - я предположил, что вы используете Swift 3 - person Rhythmic Fistman; 10.10.2016
comment
Исправлена ​​проблема с воспроизведением видео, хотя оно возвращается при экспорте (с использованием AVAssetExportSession). Насколько я вижу, нет опции для пиксельного буфера для этого объекта. Любая подсказка? :) - person Roi Mulia; 29.12.2017
comment
Можете ли вы начать новый вопрос, я думаю, о CIFilter и AVAssetExportSession? - person Rhythmic Fistman; 29.12.2017