Металл - Измените размер видеобуфера перед переходом к настраиваемому фильтру ядра.

В нашем приложении для iOS мы используем настраиваемые фильтры с использованием Metal (оболочки CIKernel / CIColorKernel).

Предположим, у нас есть видео 4K и пользовательская композиция видео с выходным размером 1080p, которая применяет расширенный фильтр к видеобуферам.
Очевидно, нам не нужно фильтровать видео в исходном размере, поэтому мы Вероятно, завершит работу приложения с предупреждением о памяти (реальная история).

Это конвейер видеофильтрации:

Получение буфера в 4K (как CIImage) ->
Применить фильтр к CIImage ->
фильтр применяет функцию фильтра CIKernel Metal к CIImage ->
Возвращает отфильтрованный CIImage в композицию

Единственные два места, где я могу думать о применении изменения размера, - это до того, как мы отправим его в процесс фильтрации или внутри функции Metal.

public class VHSFilter: CIFilter {

    public override var outputImage: CIImage? {
        // InputImage size is 4K
        guard let inputImage = self.inputImage else { return nil }

        // Manipulate the image here

        let roiCallback: CIKernelROICallback = { _, rect -> CGRect in
            return inputImage.extent
        }


        // Or inside the Kernel Metal function
        let outputImage = self.kernel.apply(extent: inputExtent,
                                            roiCallback: roiCallback,
                                            arguments: [inputImage])

        return outputImage

    }
}

Я уверен, что я не первый, кто столкнулся с этой проблемой

Что делать, если входящий видеобуфер слишком велик (с точки зрения памяти) для фильтрации, и их размер необходимо оперативно изменять на лету? Без перекодирования видео раньше?


person Roi Mulia    schedule 22.07.2019    source источник
comment
Вы пробовали вставить масштабирующее преобразование, такое как CILanczosScaleTransform, в цепочку перед вашим пользовательским фильтром / ядром?   -  person warrenm    schedule 23.07.2019
comment
Привет, @warrenm, спасибо за ответ! Я не использовал его, но я использовал функцию CIImage transformed(by:) для уменьшения размера изображения (что, похоже, не влияет на использование ОЗУ). Это то же самое, что CILanczosScaleTransform или Ланц делает что-то другое?   -  person Roi Mulia    schedule 23.07.2019
comment
Я не уверен в деталях реализации, но может случиться так, что преобразованное изображение просто содержит исходные данные изображения и преобразование, чтобы избежать дорогостоящего выделения. Возможно, вам придется принудительно использовать фильтр, такой как Lanczos, который (вероятно) фактически выполняет повторную выборку как явный шаг.   -  person warrenm    schedule 23.07.2019
comment
@warrenm Я попробую завтра. Основа Ланцоша на металле? Если (надеюсь) это действительно повторная выборка, должна ли она быть достаточно эффективной, чтобы делать это для каждого кадра без пропуска кадров? Хотя теоретически, если это передискретизация, усиление фильтрации передискретизированного буфера должно быть выше, чем сам процесс передискретизации в целом (может быть?)   -  person Roi Mulia    schedule 23.07.2019
comment
Я предполагаю, что он будет использовать Metal при запуске с контекстом Metal. Lanczos - относительно дорогой и качественный фильтр; Я не знаю, насколько производительным он будет с 4K до 1K на новейшем оборудовании iPhone. Но да, теория заключается в том, что, если предоставить остальной части конвейера гораздо меньше пикселей для обработки, стоимость понижающей дискретизации будет компенсирована сниженной стоимостью запуска последующих фильтров. Сложно сказать без тестирования.   -  person warrenm    schedule 23.07.2019
comment
Привет @warrenm. Я и Фрэнк собираемся заняться этим, чтобы выяснить, какой метод наиболее эффективен (хотя на данный момент нет рабочего метода). Я создал репозиторий GitHub и настроил конвейер с видео 4K. Если вам интересно, я могу добавить вас в качестве соавтора, чтобы вы тоже могли посмотреть. Если вам интересно, пришлите свое имя пользователя GitHub. В любом случае, я сделаю сообщение в блоге позже на этой неделе (если мы решим его, ха-ха) и сообщу вам. Хорошего дня!   -  person Roi Mulia    schedule 24.07.2019
comment
Привет, @RoiMulia, ты когда-нибудь мог это исправить? Я столкнулся с аналогичной проблемой. Интересно, что если я использую встроенные фильтры CIFilters, приложение не вылетает (использование памяти довольно стабильно). Хотя даже если я использую настраиваемый сквозной фильтр, использование памяти продолжает расти, пока приложение не выйдет из строя. Каким-то образом пользовательские фильтры обрабатываются по-разному :(. Делали обычные вещи, такие как изменение размера рендеринга и использование CILanczosScaleTransform для уменьшения размера входного изображения до настраиваемого фильтра. Было бы очень признательно, если бы вы могли указать мне правильное направление.   -  person Amit    schedule 20.08.2020


Ответы (1)


Как говорит Уорренм, вы можете использовать фильтр CILanczosScaleTransform для уменьшения разрешения видеокадров перед обработкой. Однако это все равно заставит AVFoundation выделять буферы в полном разрешении.

Я полагаю, вы используете AVMutableVideoComposition для фильтрации? В этом случае вы можете просто установить renderSize композиции на целевой размер. Из документов:

Размер, с которым должна отображаться композиция видео.

Это скажет AVFoundation выполнить повторную выборку кадров (эффективно и быстро), прежде чем передавать их в конвейер фильтров.

person Frank Schlegel    schedule 23.07.2019
comment
Привет, Фрэнк, еще раз спасибо. Обещаю, это последний выпуск, который я публикую о Metal, ха-ха. Я изменил свойство renderSize, но исходный CIImage extent все еще имеет исходный размер (4K, (0.0, 0.0, 2160.0, 3840.0)). Я вижу визуальный результат, на который я меняю renderSize, но обработанные кадры кажутся не соответствующими их размеру. Это должно быть так? - person Roi Mulia; 23.07.2019
comment
Ты прав! Свойство renderSize не влияет на sourceImage в AVAsynchronousCIImageFilteringRequest, оно устанавливает только renderSize запроса, и кажется, что вы должны использовать это при выполнении своей обработки. Так что я думаю, что CILanczosScaleTransform - лучший вариант. @warrenm Вы хотите опубликовать это в качестве ответа? - person Frank Schlegel; 23.07.2019
comment
На самом деле я не обнаружил, что фильтр Ланцоша хоть что-то улучшает. Что-то странное в использовании анимации Metal Kernel, она потребляет так много памяти, даже если я изменяю наш фильтр VHS, чтобы он выполнял почти пустую функцию (возвращая тот же буфер src без манипуляций). Я хотел бы поделиться этим с вами. Возможно ли (полностью понятно, если нет), если вы предоставите нам небольшого оплачиваемого консультанта примерно на час (через Skype или что-то в этом роде), чтобы мы могли просмотреть наш код и найти подводные камни? - person Roi Mulia; 23.07.2019
comment
Это с SpriteKit + CoreImage, но вам может быть интересно. Я бы посоветовал вам просто изменить размер с помощью Metal, чтобы уменьшить размер видео, прежде чем пытаться использовать какие-либо фильтры. stackoverflow.com/ questions / 54431826 / - person MoDJ; 24.07.2019
comment
Привет, @MoDJ, спасибо за ответ. Это один из методов, который мы попробуем сегодня. При обработке одного видео это нормально. Проблемы начинаются, когда вы используете AVVideoComposition для одновременного воспроизведения нескольких видео. Мы постараемся решить эту проблему в ближайшие дни. Если вам интересно - пришлите свое имя пользователя GitHub, и я добавлю вас в качестве соавтора для наших пробных версий git. Хорошего дня! - person Roi Mulia; 24.07.2019
comment
Привет, Рой, мое имя пользователя на github - mdejong, мне было бы интересно посмотреть, что вы придумали. - person MoDJ; 25.07.2019