Применение эффекта к iPhone Camera Preview "Видео" - PullRequest
3 голосов
/ 04 февраля 2011

Моя цель - написать собственный контроллер вида камеры, который:

  1. Может делать фотографии во всех четырех ориентациях интерфейса как с задней, так и, при наличии, передней камерой.
  2. Правильно поворачивает и масштабирует предварительный просмотр «видео», а также фотографию в полном разрешении.
  3. Позволяет применить (простой) эффект к ОБА предварительному просмотру «видео» и фотографии в полном разрешении.

Реализация (на iOS 4.2 / Xcode 3.2.5):

Из-за требования (3) мне нужно было перейти к AVFoundation.

Я начал с Технические вопросы и ответыQA1702 и внесла следующие изменения:

  1. Изменен параметр sessionPreset на AVCaptureSessionPresetPhoto.
  2. Добавлен AVCaptureStillImageOutput в качестве дополнительного вывода перед началом сеанса.

Проблема, с которой я сталкиваюсь, связана с производительностью обработки изображения для предварительного просмотра (кадр предварительного просмотра "video").

Сначала я получаю результат UIImage imageFromSampleBuffer: в буфере семплов.от captureOutput:didOutputSampleBuffer:fromConnection:.Затем я масштабирую и поворачиваю его для экрана, используя CGGraphicsContext.

В этот момент частота кадров уже ниже 15 кадров в секунду, что указано в видеовыходе сеанса и при добавлении эффекта, он падает ниже или около 10. Быстро происходит сбой приложения из-за нехватки памяти.

У меня был некоторый успех с снижением частоты кадров до 9 FPS на iPhone 4 и 8 FPS на iPod Touch (4-йgen).

Я также добавил в некоторый код, чтобы "очистить" очередь отправки, но я не уверен, насколько это на самом деле помогает.По сути, каждые 8-10 кадров устанавливается флаг, который сигнализирует captureOutput:didOutputSampleBuffer:fromConnection:, что нужно сразу же вернуться, а не обрабатывать кадр.Флаг сбрасывается после завершения операции синхронизации в очереди вывода.

На данный момент я даже не обращаю внимания на низкие частоты кадров, но, очевидно, мы не можем поставлять с низкими сбоями памяти.У кого-нибудь есть идеи, как принять меры для предотвращения нехватки памяти в этом случае (и / или лучшего способа «очистить» очередь отправки)?

Ответы [ 2 ]

4 голосов
/ 05 февраля 2011

Чтобы избежать проблем с памятью, просто создайте пул автоматического выпуска в captureOutput:didOutputSampleBuffer:fromConnection:.

Это имеет смысл, поскольку imageFromSampleBuffer: возвращает объект UIImage с автоматическим выпуском.Кроме того, он сразу освобождает любые автоматически выпущенные объекты, созданные кодом обработки изображений.

// Delegate routine that is called when a sample buffer was written
- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
fromConnection:(AVCaptureConnection *)connection
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    // Create a UIImage from the sample buffer data
    UIImage *image = [self imageFromSampleBuffer:sampleBuffer];

    < Add your code here that uses the image >

    [pool release];
}

Мои тесты показали, что это будет выполняться без предупреждений памяти на iPhone 4 или iPod Touch (4-го поколения), даже если запрашивается FPSочень высокий (например, 60) и обработка изображений очень медленная (например, 0,5+ с).

СТАРЫЕ РЕШЕНИЯ:

Как указал Брэд, Apple рекомендует обработку изображенийбыть в фоновом потоке, чтобы не мешать отзывчивости пользовательского интерфейса.Я не заметил большой задержки в этом случае, но лучшие практики - это лучшие практики, поэтому используйте вышеупомянутое решение с пулом автоматического выпуска вместо запуска этого в основной очереди отправки / главном потоке.

Чтобы предотвратить проблемы с памятьюпросто используйте основную очередь отправки вместо создания новой.

Это также означает, что вам не нужно переключаться на основной поток в captureOutput:didOutputSampleBuffer:fromConnection:, когда вы хотите обновить пользовательский интерфейс.

В setupCaptureSession, изменить С:

// Configure your output.
dispatch_queue_t queue = dispatch_queue_create("myQueue", NULL);
[output setSampleBufferDelegate:self queue:queue];
dispatch_release(queue);

ДО:

// we want our dispatch to be on the main thread
[output setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
2 голосов
/ 04 февраля 2011

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

Хотя кажется странным, что вы будете сталкиваться с накоплением памяти при обработке кадров (по моему опыту, вы просто прекращаете получать их, если не можете обработать их достаточно быстро), очереди Grand Central Dispatch могут быть заблокированы, если они ждут ввода / вывода.

Возможно, семафор отправки позволит вам ограничить добавление новых элементов в очереди обработки. Более подробно об этом я настоятельно рекомендую статью Майка Эша « GCD Practicum », в которой он рассматривает оптимизацию операции обработки миниатюр, связанных с вводом / выводом, с использованием семафоров диспетчеризации.

...