#xamarin #android-camera2
#xamarin #android-camera2
Вопрос:
Я использую Xamarin / Android (не Forms), пытаясь интегрировать образец camera2basic api в свой проект. https://developer.xamarin.com/samples/monodroid/android5.0/Camera2Basic /
Я ничего не изменил в примере, и меня интересует только использование основной камеры и только создание моментального снимка.
В моем проекте есть MainActivity, и camera2 является одним из его фрагментов, который я вызываю следующим образом:
string fragmentTag = this.Resources.GetString(Resource.String.camera_form);
// Begin the transaction
FragmentTransaction trans = this.FragmentManager.BeginTransaction();
// Replace the old fragment with the new one.
trans.Add(Resource.Id.fragment_container, camera2BasicFragment, fragmentTag);
// Add the transaction to the back stack.
// The tag is added so we can use PopBackStack to skip a screen on the back key
trans.AddToBackStack(fragmentTag);
// Don't forget to commit
trans.Commit();
Все работает с первого раза. Он делает снимок и сохраняет его в папке.
Во второй раз, когда я запускаю его, он показывает предварительный просмотр, затем, когда я делаю снимок, происходит сбой здесь, где находится throw:
public void CaptureStillPicture()
{
try
{
var activity = Activity;
if (null == activity || null == mCameraDevice)
{
return;
}
// This is the CaptureRequest.Builder that we use to take a picture.
if (stillCaptureBuilder == null)
stillCaptureBuilder = mCameraDevice.CreateCaptureRequest(CameraTemplate.StillCapture);
stillCaptureBuilder.AddTarget(mImageReader.Surface);
// Use the same AE and AF modes as the preview.
stillCaptureBuilder.Set(CaptureRequest.ControlAfMode, (int)ControlAFMode.ContinuousPicture);
SetAutoFlash(stillCaptureBuilder);
// Orientation
int rotation = (int)activity.WindowManager.DefaultDisplay.Rotation;
stillCaptureBuilder.Set(CaptureRequest.JpegOrientation, GetOrientation(rotation));
mCaptureSession.StopRepeating();
try
{
mCaptureSession.Capture(stillCaptureBuilder.Build(), new CameraCaptureStillPictureSessionCallback(this), null);
}
catch (System.Exception e)
{
throw;
}
}
catch (CameraAccessException e)
{
e.PrintStackTrace();
}
}
С этой ошибкой:
{Java.Lang.IllegalArgumentException: CaptureRequest contains unconfigured Input/Output Surface!
at Java.Interop.JniEnvironment InstanceMethods.CallIntMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x00069] in <286213b9e14c442ba8d8d94cc9dbec8e>:0
at Java.Interop.JniPeerMembers JniInstanceMethods.InvokeAbstractInt32Method (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x00014] in <286213b9e14c442ba8d8d94cc9dbec8e>:0
at Android.Hardware.Camera2.CameraCaptureSessionInvoker.Capture (Android.Hardware.Camera2.CaptureRequest request, Android.Hardware.Camera2.CameraCaptureSession CaptureCallback listener, Android.OS.Handler handler) [0x00078] in <b781ed64f1d743e7881ac038e0fbdf85>:0
at RvsMobileApp.Activities.Camera2BasicFragment.CaptureStillPicture () [0x000b7] in C:SourceRVSrvs-mobile-appsrcRvs.Mobile.AppActivitiesCamera2BasicFragment.cs:807
--- End of managed Java.Lang.IllegalArgumentException stack trace ---
java.lang.IllegalArgumentException: CaptureRequest contains unconfigured Input/Output Surface!
at android.hardware.camera2.CaptureRequest.convertSurfaceToStreamId(CaptureRequest.java:674)
at android.hardware.camera2.impl.CameraDeviceImpl.submitCaptureRequest(CameraDeviceImpl.java:1066)
at android.hardware.camera2.impl.CameraDeviceImpl.capture(CameraDeviceImpl.java:936)
at android.hardware.camera2.impl.CameraCaptureSessionImpl.capture(CameraCaptureSessionImpl.java:173)
at md5bbb797339b35f7667da89d6634e22c37.CameraCaptureListener.n_onCaptureCompleted(Native Method)
at md5bbb797339b35f7667da89d6634e22c37.CameraCaptureListener.onCaptureCompleted(CameraCaptureListener.java:37)
at android.hardware.camera2.impl.CameraCaptureSessionImpl$1.lambda$onCaptureCompleted$3(CameraCaptureSessionImpl.java:640)
at android.hardware.camera2.impl.-$$Lambda$CameraCaptureSessionImpl$1$OA1Yz_YgzMO8qcV8esRjyt7ykp4.run(Unknown Source:8)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.os.HandlerThread.run(HandlerThread.java:65)
}
base: {Java.Lang.RuntimeException}
JniPeerMembers: {Android.Runtime.XAPeerMembers}
Сначала я подумал, что это утечка памяти, поэтому я убедился, что мой фрагмент уничтожает сам себя. Вот как я завершаю фрагмент при нажатии кнопки готово:
case Resource.Id.camera_finished:
// EventHandler<DialogClickEventArgs> nullHandler = null;
Activity activity = Activity;
if (activity != null)
{
// Send all of the data to the service
// SendPhotosAndDataToService();
// Call the paren activitity's back to END this Fragment
activity.FragmentManager.BeginTransaction().Remove(this).CommitNow();
//activity.OnBackPressed();
}
break;
Вот мои шаги по воспроизведению ошибки:
Запустите камеру (загрузите фрагмент) Просмотреть предварительный просмотр, сделать снимок, вернуться к основному действию (закрыть фрагмент)
Запустите камеру (загрузите фрагмент) Смотрите предварительный просмотр, СБОЙ при съемке!!!
Пока я не делаю никаких фотографий, я могу загружать и выгружать фрагмент столько раз, сколько мне нужно.
Я погуглил «CaptureRequest содержит неконфигурированную поверхность ввода / вывода!» и не получил достаточно информации, чтобы действительно понять проблему. Я думаю, что что-то не самоочищается после первого запуска. Я работаю над этой проблемой уже несколько дней.
Комментарии:
1. Может ли сбой произойти из-за того, что при выгрузке фрагмента вы не уничтожаете stillCaptureBuilder ? Обратите внимание, что в строке 621 этот конструктор создается, но только в том случае, если он имеет значение null .
Ответ №1:
Как указал Алекс Кон, и я обнаружил, когда прочитал эту статью: https://hofmadresu.com/2018/09/11/android-camera2-trials-and-tribulations.html
Кстати, это отличный ресурс, в примере кода не был выпущен stillCaptureBuilder, поэтому его можно использовать во второй раз.
public void CaptureStillPicture()
{
try
{
var activity = Activity;
if (null == activity || null == mCameraDevice)
{
return;
}
// THIS WAS NOT RELEASING THE RESOURCES AND SHOULD BE REMOVED FROM THE SAMPLE!
//// This is the CaptureRequest.Builder that we use to take a picture.
////if (stillCaptureBuilder == null)
//// stillCaptureBuilder = mCameraDevice.CreateCaptureRequest(CameraTemplate.StillCapture);
// This is the proper code
var stillCaptureBuilder = mCameraDevice.CreateCaptureRequest(CameraTemplate.StillCapture);
stillCaptureBuilder.AddTarget(mImageReader.Surface);
// Use the same AE and AF modes as the preview.
stillCaptureBuilder.Set(CaptureRequest.ControlAfMode, (int)ControlAFMode.ContinuousPicture);
SetAutoFlash(stillCaptureBuilder);
// Orientation
int rotation = (int)activity.WindowManager.DefaultDisplay.Rotation;
stillCaptureBuilder.Set(CaptureRequest.JpegOrientation, GetOrientation(rotation));
mCaptureSession.StopRepeating();
mCaptureSession.AbortCaptures();
try
{
mCaptureSession.Capture(stillCaptureBuilder.Build(), new CameraCaptureStillPictureSessionCallback(this), null);
}
catch (System.Exception e)
{
throw;
}
}
catch (CameraAccessException e)
{
e.PrintStackTrace();
}
}
Я документирую это, чтобы любой, кто еще испытывает трудности с camera2, мог научиться.
Спасибо, как всегда
Комментарии:
1. Я согласен с тем, что в этом случае нет необходимости сохранять экземпляр
stillCaptureBuilder
во всех запросах CaptureStillPicture(), выполняемых с помощью CaptureStillPicture.
Ответ №2:
При восстановлении фрагмента камеры повторно инициализировался stillCaptureBuilder. Еще лучше, убедитесь, что вы очистили stillCaptureBuilder, когда фрагмент будет уничтожен.
Комментарии:
1. Это правильный ответ, мы оба нашли его одновременно. (Это то, что я получаю, когда использую код, который я не до конца понимаю).
2. Как вы можете «очистить» stillCaptureBuilder?
3. @Darius в исправленном коде
stillCaptureBuilder
экземпляр является локальным дляCaptureStillPicture()
метода. В исходном коде это был член класса fragment. Под чистотой я подразумеваю не что иное, какstillCaptureBuilder=null
.