RedApparat / Fotoapparat

Making Camera for Android more friendly. 📸
Apache License 2.0
3.82k stars 405 forks source link

Camera fails to start about 1 of every 50 launches #191

Open jpribble opened 6 years ago

jpribble commented 6 years ago

What are you trying to achieve or the steps to reproduce?

Very rarely (about 1 in 50 times), the camera fails to start. The camera preview displays a black screen and the frame processor doesn't receive any frames. When this happens, I have to force kill and relaunch the app to get the camera working again. The logs show that my Activity is very quickly created, destroyed, and recreated when this issue appears. The second time the Activity is created, it is missing the "Fotoapparat: Device: selectCamera" and "Fotoapparat: CameraDevice: open" logs. Here are the full logs:

01-22 23:16:58.088 24893-24893/ D/TakePictureActivity: onCreate() 01-22 23:16:58.322 24893-24893/ D/Fotoapparat: Device: updateLensPositionSelector 01-22 23:16:58.324 24893-24893/ D/Fotoapparat: Fotoapparat: 01-22 23:16:58.328 24893-24893/ D/TakePictureActivity: onStart() 01-22 23:16:58.347 24893-24893/ D/Fotoapparat: Fotoapparat: start 01-22 23:16:58.350 24893-24893/ D/Fotoapparat: Fotoapparat: getCurrentParameters 01-22 23:16:58.356 24893-24893/ D/Fotoapparat: Fotoapparat: getCapabilities 01-22 23:16:58.363 24893-24893/ D/TakePictureActivity: onResume() 01-22 23:16:58.366 24893-27081/ D/Fotoapparat: Device: selectCamera 01-22 23:16:58.374 24893-27081/ D/Fotoapparat: CameraDevice: open 01-22 23:16:58.420 24893-24893/ D/TakePictureActivity: onPause() 01-22 23:16:58.431 24893-24893/ D/TakePictureActivity: onStop() 01-22 23:16:58.431 24893-24893/ D/Fotoapparat: Fotoapparat: stop 01-22 23:16:58.432 24893-27083/ D/Fotoapparat: Couldn't deliver pending result: Camera operation was cancelled. 01-22 23:16:58.432 24893-27083/ D/Fotoapparat: Couldn't deliver pending result: Camera operation was cancelled. 01-22 23:16:58.436 24893-24893/ D/TakePictureActivity: onDestroy()

01-22 23:16:58.453 24893-24893/ D/TakePictureActivity: onCreate() 01-22 23:16:58.525 24893-24893/ D/Fotoapparat: Device: updateLensPositionSelector 01-22 23:16:58.526 24893-24893/ D/Fotoapparat: Fotoapparat: 01-22 23:16:58.536 24893-24893/ D/TakePictureActivity: onStart() 01-22 23:16:58.542 24893-24893/ D/Fotoapparat: Fotoapparat: start 01-22 23:16:58.543 24893-24893/ D/Fotoapparat: Fotoapparat: getCurrentParameters 01-22 23:16:58.544 24893-24893/ D/Fotoapparat: Fotoapparat: getCapabilities 01-22 23:16:58.550 24893-24893/ D/TakePictureActivity: onResume() 01-22 23:16:59.031 24893-27081/ D/Fotoapparat: CameraDevice: getCapabilities$suspendImpl 01-22 23:16:59.035 24893-27081/ D/Fotoapparat: CameraDevice: updateParameters$suspendImpl 01-22 23:16:59.037 24893-27081/ D/Fotoapparat: New camera parameters are: CameraParameters flashMode: io.fotoapparat.parameter.Flash$Off@a30268a focusMode: io.fotoapparat.parameter.FocusMode$ContinuousFocusPicture@ed2b873 jpegQuality: 90 previewFpsRange: FpsRange(min=15000, max=30000) antiBandingMode: io.fotoapparat.parameter.AntiBandingMode$Auto@89668cf sensorSensitivity: null pictureResolution: Resolution(width=1280, height=720) previewResolution: Resolution(width=1280, height=720) 01-22 23:16:59.055 24893-27081/ D/Fotoapparat: CameraDevice: updateFrameProcessor 01-22 23:16:59.084 24893-27081/ D/Fotoapparat: CameraDevice: setDisplayOrientation 01-22 23:16:59.084 24893-27081/ D/Fotoapparat: Image orientation is: io.fotoapparat.hardware.orientation.Orientation$Horizontal$ReverseLandscape@5979965. Display orientation is: io.fotoapparat.hardware.orientation.Orientation$Vertical$Portrait@b67463a. Preview orientation is: io.fotoapparat.hardware.orientation.Orientation$Vertical$Portrait@b67463a. 01-22 23:16:59.087 24893-27081/ D/Fotoapparat: CameraDevice: getPreviewResolution 01-22 23:16:59.092 24893-27081/ D/Fotoapparat: Preview resolution is: Resolution(width=1280, height=720) [no more camera related logs appear after this point]

How did you initialize FA?

override fun onCreate() {
  super.onCreate()
  …
  camera = Fotoapparat
    .with(this)
    .into(cameraView!!)
    .previewScaleType(ScaleType.CenterCrop)
    .photoResolution([custom_selector])
    .previewResolution([custom_selector])
    .lensPosition(single(LensPosition.Back))
    .focusMode(firstAvailable(
        continuousFocusPicture(),
        autoFocus(),
        fixed(),
        infinity()))
    .flash(off())
    .frameProcessor { … }
    .previewFpsRange(highestFps())
    .cameraErrorCallback { … }
    .logger(logcat())
    .build()
}

  override fun onStart() {
    super.onStart()
    if (hasCameraPermission) {
      camera.start()
    }
  }

  override fun onStop() {
    if (hasCameraPermission) {
      camera.stop()
    }
    super.onStop()
  }

Context:

Diolor commented 6 years ago

I have the speculation this is because the camera doesn't have time to stop properly (because it runs in a separate thread).

@jpribble if that's not your production code logs, would you mind adding a thread sleep e.g. 200ms and see if that solves it?

jpribble commented 6 years ago

I'm not able to consistently reproduce this so I don't think I'll be able to test that. However, I suspect this is being caused by a quick configuration change right after the activity is launched. I was able to reproduce similar issues with the following steps:

  1. Configure the device to lock when the power button is pressed & set lock type to password.
  2. Configure the camera Activity to be locked to landscape only.
  3. Open the camera and then press the power button to lock the device.
  4. Press the power button again and enter the password to unlock.

When the device is unlocked and returns the camera, it crashes. I confirmed that the Activity is receiving a configuration change when the device is unlocked (probably caused by the keyboard). I was able to "fix" this by adding configChanges="..." to the camera Activity so it doesn't get recreated due to config changes. I believe the configChanges flag will also help me work around the issue originally described above. However, it'd still be good to still investigate the root issue to help others avoid it in the future.

andrewcking commented 6 years ago

Could this be a remnant of #115 still lingering? On the physical devices I tested (galaxy s6,s5) #115 was extremely reproducible pre 2.0, but since the 2.0 release I haven't had it occur yet on those devices. I am able to observe the issue occur in the Android Studio Emulator but that could be camera emulation related.

If it is helpful though, If you launch the default Fotoapparat sample in the emulator running a Nexus 5 API 22, hit the home button and return to the app, the preview will be blank.

Raenar4k commented 6 years ago

Can confirm, have this issue (#115) even after updating to 2.2.0 from 1.5.0, for now using post delayed as a hacky workaround. I managed to reproduce it on Nexus 5, Samsung S7 using Fotoapparat's sample app.

Here i start the app, go to overview(recents) and back: https://gfycat.com/BeautifulFlusteredAsiantrumpetfish

When going to overview and back camera can either manage to start or not: https://gfycat.com/CourteousBabyishDunlin

wellbranding commented 6 years ago

Why this issue occurs?? Library is really bad if this continue on... Should I switch all my app code to CameraKit? This issue should be a priority number 1.

fazalBykea commented 5 years ago

Is there any workaround for this issue?

Raenar4k commented 5 years ago

Just managed to get a device that i used to reproduce this bug year ago. It is Samsung S7 edge (SM-G935FD)(Android 6.0)

The bug is consistently reproduced both in 2.2.0 (as before) and in 2.7.0 (version with this fix). If we add delay before camera start:

    override fun onStart() {
        super.onStart()
        if (permissionsGranted) {
            cameraView.postDelayed({
                fotoapparat.start()
                adjustViewsVisibility()
            }, 20)
        }
    }

then bug is no longer reproduced and camera always manages to start. So in 2.7.0 we are still using that workaround.

@Diolor can you reopen this bug?

EDIT: I should add that i used sample app for tests and workaround example. EDIT2: Removed delay in on stop.

wellbranding commented 5 years ago

@Raenar4k this is really bad news... I have released 2.7.0 version, by removing handlers... How did you reproduced bug? Did bug appears always or at some times?

Raenar4k commented 5 years ago

It is easily reproduced on that device, when going to home screen and back to app from recents. There is a gif that illustrates this: https://github.com/RedApparat/Fotoapparat/issues/191#issuecomment-363411738

wellbranding commented 5 years ago

@Raenar4k i have tested also on many devices.. I found that you must call fotoappart.stop() on onPause, not onStop. Can you try that on your phone?

Raenar4k commented 5 years ago

I've tested that and the bug is still there.

wellbranding commented 5 years ago

@Raenark4k.. Oh ok. Let me know if library works well it you use handler only for starting session? I can't use it onStop because it creates issues when switching fragments from front and back. I would like to avoid some hacky solutions for switching cameras. By my logic Handler on onStart should be enough