`[AVCaptureSession canAddOutput: output]` возвращает NO с перерывами. Могу ли я узнать, почему?

Я использую canAddOutput:, чтобы определить, могу ли я добавить AVCaptureMovieFileOutput в AVCaptureSession, и я обнаружил, что canAddOutput: иногда возвращает НЕТ и в основном возвращает ДА. Есть ли способ узнать, почему НЕТ был возвращен? Или способ устранить ситуацию, которая вызывает возврат НЕТ? Или что-нибудь еще, что я могу сделать, это не позволит пользователю просто увидеть прерывистый сбой?

Некоторые дополнительные примечания: Это происходит примерно раз в 30 звонков. Поскольку мое приложение не запускается, оно тестировалось только на одном устройстве: iPhone 5 работает 7.1.2

Ответ 1

Вот цитата из документации (обсуждение canAddOutput:)

You cannot add an output that reads from a track of an asset other than the asset used to initialize the receiver.

Объяснение, которое поможет вам (пожалуйста, проверьте, соответствует ли ваш код этому руководству, если вы все в порядке, он не должен вызывать ошибку, потому что в основном canAddOuput: проверяет совместимость).

AVCaptureSession
Используется для соединения между организациями Device Input и output, аналогично подключению DShow фильтра. Если вы можете подключить вход и выход, после запуска данные будут считаны с входа на выход. Несколько основных моментов:
a) AVCaptureDevice, определение оборудования, как устройства камеры.
б) AVCaptureInput
c) AVCaptureOutput
Вход и выход не являются индивидуальными, например, видеовыход, а видео + аудио вход. До и после переключения камеры:

AVCaptureSession * session = <# A capture session #>; 
[session beginConfiguration]; 
[session removeInput: frontFacingCameraDeviceInput]; 
[session addInput: backFacingCameraDeviceInput]; 
[session commitConfiguration];

Добавить захват INPUT:
Чтобы добавить устройство захвата в сеанс захвата, вы используете экземпляр AVCaptureDeviceInput (конкретный подкласс абстрактного класса AVCaptureInput). Вход устройства захвата управляет портами устройства.

NSError * error = nil; 
AVCaptureDeviceInput * input = 
[AVCaptureDeviceInput deviceInputWithDevice: device error: & error]; 
if (input) { 
   // Handle the error appropriately. 
}

Добавить выход, классификация вывода:

Чтобы получить выход из сеанса захвата, вы добавляете один или несколько выходов. Выход представляет собой экземпляр конкретного подкласс AVCaptureOutput;
вы используете:
AVCaptureMovieFileOutput для вывода в файл фильма
AVCaptureVideoDataOutput, если вы хотите обрабатывать кадры из захваченного видео
AVCaptureAudioDataOutput, если вы хотите обработать аудиоданные, которые будут записаны
AVCaptureStillImageOutput, если вы хотите захватывать неподвижные изображения с сопроводительными метаданными Вы добавляете выходы в сеанс захвата с помощью addOutput:.
Вы проверяете, совместим ли выход захвата с существующим сеансом, используя canAddOutput:.
Вы можете добавлять и удалять выходы по мере сеанс запущен.

AVCaptureSession * captureSession = <# Get a capture session #>; 
AVCaptureMovieFileOutput * movieInput = <# Create and configure a movie output #>; 
if ([captureSession canAddOutput: movieInput]) { 
   [captureSession addOutput: movieInput]; 
} 
else {
   // Handle the failure. 
}

Сохранить видеофайл, добавить выходной файл видео:

Вы сохраняете данные фильма в файл с помощью объекта AVCaptureMovieFileOutput. (AVCaptureMovieFileOutput является конкретным подклассом AVCaptureFileOutput, который определяет большую часть основного поведения.) Вы можете настроить различные аспекты вывода видеофайла, такие как максимальная продолжительность записи или максимальный файл размер. Вы также можете запретить запись, если осталось меньше заданного объема дискового пространства.

AVCaptureMovieFileOutput * aMovieFileOutput = [[AVCaptureMovieFileOutput alloc] 
init]; 
CMTime maxDuration = <# Create a CMTime to represent the maximum duration #>; 
aMovieFileOutput.maxRecordedDuration = maxDuration; 
aMovieFileOutput.minFreeDiskSpaceLimit = <# An appropriate minimum given the quality 
of the movie format and the duration #>;

Обработка предварительных данных кадра видео, данные каждого искателя кадра могут использоваться для последующей обработки на высоком уровне, таких как обнаружение лиц и т.д.
Объект AVCaptureVideoDataOutput использует делегирование для венгерских видеокадров. Вы устанавливаете делегат, используя setSampleBufferDelegate: queue:.
В дополнение к делегату вы указываете последовательную очередь, на которой они вызываются методы делегата. Вы должны использовать последовательную очередь, чтобы гарантировать, что кадры будут переданы делегату в правильном порядке.
Вы не должны передавать очередь, возвращенную dispatch_get_current_queue, поскольку не является гарантией того, в какой поток запущена текущая очередь. Вы можете использовать очередь для изменения приоритет при доставке и обработке видеокадров. Обработка данных для фрейма, должны быть ограничения размера (размера изображения) и времени обработки, если время обработки слишком велико, базовый датчик не будет отправлять данные в устройство и обратный вызов.

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

Сделка с процессом захвата:

AVCaptureStillImageOutput * stillImageOutput = [[AVCaptureStillImageOutput alloc] 
init]; 
NSDictionary * outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: AVVideoCodecJPEG, 
AVVideoCodecKey, nil]; 
[StillImageOutput setOutputSettings: outputSettings];

Возможность поддержки другого формата также поддерживает прямой генерации потока jpg. Если вы хотите захватить изображение в формате JPEG, вы обычно не должны указывать свой собственный формат сжатия. Вместо, вы должны разрешить вывод неподвижного изображения для вас, поскольку его сжатие аппаратно ускорено. Если вам требуется представление данных изображения, вы можете использовать jpegStillImageNSDataRepresentation: для получить объект NSData без повторного сжатия данных, даже если вы измените метаданные изображения.

Просмотр предварительного просмотра камеры:

Вы можете предоставить пользователю предварительный просмотр того, что записывается с помощью AVCaptureVideoPreviewLayer объект. AVCaptureVideoPreviewLayer является подклассом CALayer (см. Руководство по программированию базовой анимации. Вам не нужны выходы для показа предварительного просмотра.

AVCaptureSession * captureSession = <# Get a capture session #>; 
CALayer * viewLayer = <# Get a layer from the view in which you want to present the 
The preview #>; 
AVCaptureVideoPreviewLayer * captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer 
alloc] initWithSession: captureSession]; 
[viewLayer addSublayer: captureVideoPreviewLayer];

В общем, слой предварительного просмотра ведет себя как любой другой объект CALayer в дереве рендеринга (см. Core Animation Руководство по программированию). Вы можете масштабировать изображение и выполнять преобразования, вращения и так далее, как вы будет любой слой. Одно из отличий заключается в том, что вам может потребоваться установить свойство ориентации слоя, чтобы указать, как он должен вращать изображения, поступающие с камеры. Кроме того, на iPhone 4 слой предварительного просмотра поддерживает зеркалирование (Это значение используется при предварительном просмотре фронтальной камеры).

Ответ 2

Ссылаясь на этот ответ, возможно, что этот метод делегата может быть запущен в фоновом режиме, что приводит к тому, что предыдущий AVCaptureSession не отключается должным образом, иногда приводя к canAddOutput: иногда NO.

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection

Решением может быть использование stopRunning в вышеуказанном делетете (конечно, после выполнения необходимых действий и проверки условий, вы должны правильно закончить предыдущие сеансы?).

Добавляя к этому, было бы лучше, если бы вы предоставили некоторый код того, что вы пытаетесь сделать.

Ответ 3

Это может быть один из этих 2 случаев
1) Сессия запущена
2) Вы уже добавили вывод
 Вы не можете добавить 2 вывода или 2 ввода, а также не можете создать 2 разных сеанса

Ответ 4

Это может быть комбинация:

  • Вызов этого метода, когда камера занята.
  • Неправильно удалить ранее подключенный AVCaptureSession.

Вы должны попытаться добавить его только один раз (где я думаю, canAddOutput: всегда будет YES) и просто приостанавливает/возобновляет сеанс по мере необходимости:

// Stop session if possible
if (_captureSession.running && !_captureInProgress)
{
    [_captureSession stopRunning];
    NBULogVerbose(@"Capture session: {\n%@} stopped running", _captureSession);
}

Вы можете посмотреть здесь.

Ответ 5

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

- (BOOL)canAddOutput:(AVCaptureOutput *)output

Параметры вывод Результат, который вы хотите добавить в сеанс. Возвращаемое значение ДА, если вывод может быть добавлен в сеанс, в противном случае NO.

Наличие Доступно в OS X v10.7 и более поздних версиях.

Вот ссылка на apple doc Нажмите здесь