Камера на Android-примере
Я хочу написать действие, которое:
- Показывает предварительный просмотр камеры (видоискатель) и имеет кнопку захвата.
- Когда нажата кнопка "захват", выполняется съемка и возвращается к вызывающей активности (setResult() и finish()).
Есть ли полный пример, который работает на каждом устройстве? Идеальным ответом будет ссылка на простое приложение с открытым исходным кодом, которое делает снимки.
Мои исследования:
Это распространенный сценарий, и на нем есть много вопросов и руководств.
Существуют два основных подхода:
Подход 1 был бы идеальным, но проблема в том, что намерение реализовано по-разному на каждом устройстве. На некоторых устройствах он работает хорошо. Однако на некоторых устройствах вы можете сделать снимок, но он никогда не возвращается в ваше приложение. На некоторых устройствах ничего не происходит, когда вы запускаете намерение. Обычно он также сохраняет изображение на SD-карте и требует наличия SD-карты. Пользовательское взаимодействие также отличается на каждом устройстве.
С подходом 2 проблемы - это стабильность. Я попробовал несколько примеров, но мне удалось остановить работу камеры (до перезапуска) на некоторых устройствах и полностью заморозить другое устройство. На другом устройстве захват работал, но предварительный просмотр остался черным.
Я бы использовал ZXing в качестве примера приложения (я много работаю с ним), но он использует только предварительный просмотр (видоискатель) и не делает никаких снимков. Я также обнаружил, что на некоторых устройствах ZXing автоматически не корректировал баланс белого при изменении условий освещения, в то время как приложение для родной камеры делало это правильно (не уверен, что это можно исправить).
Update:
Некоторое время я напрямую использовал API-интерфейс камеры. Это дает больше контроля (пользовательский интерфейс и т.д.), Но я бы никому не рекомендовал. Я бы работал на 90% устройств, но время от времени новое устройство было выпущено с другой проблемой.
Некоторые из проблем, с которыми я столкнулся:
- Работа с автофокусом
- Работа со вспышкой
- Вспомогательные устройства с фронтальной камерой, задней камерой или обоими
- Каждое устройство имеет разную комбинацию разрешения экрана, разрешения предварительного просмотра (не всегда соответствует разрешению экрана) и разрешения изображения.
Итак, в общем, я бы не стал рекомендовать этот маршрут вообще, если нет другого пути. Через два года я сбросил пользовательский код и переключился на подход, основанный на Intent. С тех пор у меня было гораздо меньше проблем. Проблемы, которые у меня были с подходом, основанным на намерениях, в прошлом были, вероятно, только моей собственной некомпетентностью.
Если вам действительно нужно пройти этот маршрут, я слышал об этом гораздо проще, если вы поддерживаете только устройства с Android 4.0 +.
Ответы
Ответ 1
С подходом 2 проблемы - это стабильность. Я попробовал несколько примеров, но мне удалось остановить работу камеры (до перезапуска) на некоторых устройствах и полностью заморозить другое устройство. На другом устройстве захват работал, но предварительный просмотр остался черным.
Есть либо ошибка в примерах, либо проблема с совместимостью с устройствами.
Ответ 2
Пример, который CommonsWare дал хорошо. Пример работает при использовании as-is, но вот те проблемы, с которыми я столкнулся, когда изменяем его для моего варианта использования:
- Никогда не делайте второй снимок перед завершением первого снимка, другими словами
PictureCallback.onPictureTaken()
был вызван. Для этой цели в CommonsWare используется флаг inPreview
.
- Убедитесь, что ваш
SurfaceView
является полноэкранным. Если вам нужен небольшой предварительный просмотр, вам может потребоваться изменить логику выбора размера предварительного просмотра, в противном случае предварительный просмотр может не вписываться в SurfaceView
на некоторых устройствах. Некоторые устройства поддерживают только полноэкранный размер предварительного просмотра, поэтому сохранение его в полноэкранном режиме является самым простым решением.
Чтобы добавить дополнительные компоненты в экран предварительного просмотра, FrameLayout
хорошо работает в моем опыте. Я начал с использования LinearLayout
, чтобы добавить текст выше предварительного просмотра, но это нарушило правило №2. При использовании FrameLayout
для добавления компонентов поверх предварительного просмотра у вас нет проблем с разрешением предварительного просмотра.
Я также разместил незначительную проблему, относящуюся к Camera.open()
на GitHub.
Ответ 3
"рекомендуемый способ доступа к камере - открыть камеру в отдельной теме" . В противном случае Camera.open() может занять некоторое время и может испортить поток пользовательского интерфейса.
"Обратные вызовы будут вызваны в поток событий, открытый (int) был вызван из" . Поэтому для достижения наилучшей производительности с помощью обратных вызовов предварительного просмотра камеры (например, для их кодирования в видео с низкой задержкой для живого общения) я рекомендую открыть камеру в новом HandlerThread, как показано здесь.