A couple of fixes and docs improvements (#1184)

* fix typos and add minor details to the docs

* fix the issue #1175 & fix a typo

* fix the issue #1168 & fix a typo

* fix a typo in PR template

* check result data for null in the onPictureResult() callback

* revert unnecessary changes

* improve log message

Co-authored-by: Dmitry Naymushin <d.naymushin@tinkoff.ru>
pull/1187/head
Dmitry Naymushin 2 years ago committed by GitHub
parent 82ea49f6e2
commit ae3f3da0e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .github/pull_request_template.md
  2. 2
      cameraview/src/main/java/com/otaliastudios/cameraview/BitmapCallback.java
  3. 7
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera1Engine.java
  4. 2
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java
  5. 4
      cameraview/src/main/java/com/otaliastudios/cameraview/engine/CameraBaseEngine.java
  6. 8
      demo/src/main/kotlin/com/otaliastudios/cameraview/demo/PicturePreviewActivity.kt
  7. 6
      docs/_docs/capturing-media.md
  8. 2
      docs/_docs/filters.md
  9. 2
      docs/_docs/frame-processing.md
  10. 4
      docs/_docs/metering.md
  11. 4
      docs/_docs/preview-size.md
  12. 6
      docs/_extra/v1-migration-guide.md

@ -6,7 +6,7 @@ unfortunately, this PR will likely be ignored.
If the edited files were covered by tests, updated tests are required for merging. If the edited files were covered by tests, updated tests are required for merging.
Please look into the tests folders and make sure you cover new code. Please look into the tests folders and make sure you cover new code.
- Fixes ... (*issue number*) - Fixes: ... (*issue number*)
- Tests: ... (*yes/no*) - Tests: ... (*yes/no*)
- Docs updated: ... (*yes/no*) - Docs updated: ... (*yes/no*)

@ -12,7 +12,7 @@ public interface BitmapCallback {
/** /**
* Notifies that the bitmap was successfully decoded. * Notifies that the bitmap was successfully decoded.
* This is run on the UI thread. * This is run on the UI thread.
* Returns a null object if a {@link OutOfMemoryError} was encountered. * Returns a null object if an {@link OutOfMemoryError} was encountered.
* *
* @param bitmap decoded bitmap, or null * @param bitmap decoded bitmap, or null
*/ */

@ -881,7 +881,12 @@ public class Camera1Engine extends CameraBaseEngine implements
if (maxAF > 0) params.setFocusAreas(transformed.get(maxAF, transform)); if (maxAF > 0) params.setFocusAreas(transformed.get(maxAF, transform));
if (maxAE > 0) params.setMeteringAreas(transformed.get(maxAE, transform)); if (maxAE > 0) params.setMeteringAreas(transformed.get(maxAE, transform));
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.setParameters(params); try {
mCamera.setParameters(params);
} catch (RuntimeException re) {
LOG.e("startAutoFocus:", "Failed to set camera parameters");
throw new CameraException(re, CameraException.REASON_UNKNOWN);
}
getCallback().dispatchOnFocusStart(gesture, legacyPoint); getCallback().dispatchOnFocusStart(gesture, legacyPoint);
// The auto focus callback is not guaranteed to be called, but we really want it // The auto focus callback is not guaranteed to be called, but we really want it

@ -479,7 +479,7 @@ public class Camera2Engine extends CameraBaseEngine implements
// Compute sizes. // Compute sizes.
// TODO preview stream should never be bigger than 1920x1080 as per // TODO preview stream should never be bigger than 1920x1080 as per
// CameraDevice.createCaptureSession. This should be probably be applied // CameraDevice.createCaptureSession. This should probably be applied
// before all the other external selectors, to treat it as a hard limit. // before all the other external selectors, to treat it as a hard limit.
// OR: pass an int into these functions to be able to take smaller dims // OR: pass an int into these functions to be able to take smaller dims
// when session configuration fails // when session configuration fails

@ -559,10 +559,10 @@ public abstract class CameraBaseEngine extends CameraEngine {
@Override @Override
public void onPictureResult(@Nullable PictureResult.Stub result, @Nullable Exception error) { public void onPictureResult(@Nullable PictureResult.Stub result, @Nullable Exception error) {
mPictureRecorder = null; mPictureRecorder = null;
if (result != null) { if (result != null && result.data != null) {
getCallback().dispatchOnPictureTaken(result); getCallback().dispatchOnPictureTaken(result);
} else { } else {
LOG.e("onPictureResult", "result is null: something went wrong.", error); LOG.e("onPictureResult", "result or data is null: something went wrong.", error);
getCallback().dispatchError(new CameraException(error, getCallback().dispatchError(new CameraException(error,
CameraException.REASON_PICTURE_FAILED)); CameraException.REASON_PICTURE_FAILED));
} }

@ -46,7 +46,7 @@ class PicturePreviewActivity : AppCompatActivity() {
result.toBitmap(1000, 1000) { bitmap -> imageView.setImageBitmap(bitmap) } result.toBitmap(1000, 1000) { bitmap -> imageView.setImageBitmap(bitmap) }
} catch (e: UnsupportedOperationException) { } catch (e: UnsupportedOperationException) {
imageView.setImageDrawable(ColorDrawable(Color.GREEN)) imageView.setImageDrawable(ColorDrawable(Color.GREEN))
Toast.makeText(this, "Can't preview this format: " + result.getFormat(), Toast.LENGTH_LONG).show() Toast.makeText(this, "Can't preview this format: " + result.format, Toast.LENGTH_LONG).show()
} }
if (result.isSnapshot) { if (result.isSnapshot) {
// Log the real size for debugging reason. // Log the real size for debugging reason.
@ -76,13 +76,13 @@ class PicturePreviewActivity : AppCompatActivity() {
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.share) { if (item.itemId == R.id.share) {
Toast.makeText(this, "Sharing...", Toast.LENGTH_SHORT).show() Toast.makeText(this, "Sharing...", Toast.LENGTH_SHORT).show()
val extension = when (pictureResult!!.format) { val extension = when (requireNotNull(pictureResult).format) {
PictureFormat.JPEG -> "jpg" PictureFormat.JPEG -> "jpg"
PictureFormat.DNG -> "dng" PictureFormat.DNG -> "dng"
else -> throw RuntimeException("Unknown format.") else -> throw RuntimeException("Unknown format.")
} }
val file = File(filesDir, "picture.$extension") val destFile = File(filesDir, "picture.$extension")
CameraUtils.writeToFile(pictureResult!!.data, file) { file -> CameraUtils.writeToFile(requireNotNull(pictureResult?.data), destFile) { file ->
if (file != null) { if (file != null) {
val context = this@PicturePreviewActivity val context = this@PicturePreviewActivity
val intent = Intent(Intent.ACTION_SEND) val intent = Intent(Intent.ACTION_SEND)

@ -46,9 +46,9 @@ resulting snapshots are square as well, no matter what the sensor available size
|`takePictureSnapshot()`|Pictures|Snapshot|`yes`|`yes`|`yes`|That of the preview stream, [or less](snapshot-size)| |`takePictureSnapshot()`|Pictures|Snapshot|`yes`|`yes`|`yes`|That of the preview stream, [or less](snapshot-size)|
|`takeVideoSnapshot(File)`|Videos|Snapshot|`yes`|`yes`|`yes`|That of the preview stream, [or less](snapshot-size)| |`takeVideoSnapshot(File)`|Videos|Snapshot|`yes`|`yes`|`yes`|That of the preview stream, [or less](snapshot-size)|
> Please note that the video snaphot features requires: > Please note that the video snapshot features require:
> - API 18. If called before, it throws > - API 18. If called on earlier versions, it throws an `IllegalStateException`
> - An OpenGL preview (see [previews](previews)). If not, it throws > - An OpenGL preview (see [previews](previews)). If not, it throws an `IllegalStateException`
### Capturing pictures while recording ### Capturing pictures while recording

@ -25,7 +25,7 @@ flag to use it. The only condition is to use the `Preview.GL_SURFACE` preview.
Real-time filters are applied at creation time, through the `app:cameraFilter` XML attribute, Real-time filters are applied at creation time, through the `app:cameraFilter` XML attribute,
or anytime during the camera lifecycle using `cameraView.setFilter()`. or anytime during the camera lifecycle using `cameraView.setFilter()`.
We offers a reasonable amount of filters through the `Filters` class, for example: We offer a reasonable amount of filters through the `Filters` class, for example:
```java ```java
cameraView.setFilter(Filters.BLACK_AND_WHITE.newInstance()); cameraView.setFilter(Filters.BLACK_AND_WHITE.newInstance());

@ -120,7 +120,7 @@ You can check which formats are available for use through `CameraOptions.getSupp
### Advanced: Thread Control ### Advanced: Thread Control
Starting from `v2.5.1`, you can control the number of background threads that are allocated Starting from `v2.5.1`, you can control the number of background threads that are allocated
for frame processing work. This should further push you into perform processing actions synchronously for frame processing work. This should further push you into performing processing actions synchronously
and can be useful if processing is very slow with respect to the preview frame rate, in order to and can be useful if processing is very slow with respect to the preview frame rate, in order to
avoid dropping too many frames. avoid dropping too many frames.

@ -53,7 +53,7 @@ This action needs the coordinates of a point or region computed with respect to
```java ```java
// Start touch metering at the center: // Start touch metering at the center:
cameraView.startAutoFocus(cameraView.getWidth() / 2F, cameraView.getHeight/() / 2F); cameraView.startAutoFocus(cameraView.getWidth() / 2F, cameraView.getHeight() / 2F);
// Start touch metering within a given area, // Start touch metering within a given area,
// like the bounding box of a face. // like the bounding box of a face.
cameraView.startAutoFocus(rect); cameraView.startAutoFocus(rect);
@ -102,7 +102,7 @@ cameraView.setAutoFocusMarker(new DefaultAutoFocusMarker());
##### Touch Metering Reset Delay ##### Touch Metering Reset Delay
You control control how a touch metering operation is reset after completed. You control how a touch metering operation is reset after being completed.
Setting a negative value (or 0, or `Long.MAX_VALUE`) will not reset the metering values. Setting a negative value (or 0, or `Long.MAX_VALUE`) will not reset the metering values.
This is useful for low end devices that have slow auto-focus capabilities. This is useful for low end devices that have slow auto-focus capabilities.
Defaults to 3 seconds. Defaults to 3 seconds.

@ -66,7 +66,7 @@ by the engine. The default selector will do the following:
- Constraint 2: match sizes a bit bigger than the View (so there is no upscaling) - Constraint 2: match sizes a bit bigger than the View (so there is no upscaling)
- Try to match both, or just one, or fallback to the biggest available size - Try to match both, or just one, or fallback to the biggest available size
There are not so many reason why you would replace this, other than control the frame processor size There are not so many reasons why you would replace this, other than to control the frame processor size
or, indirectly, the snapshot size. You can, however, hook into the process using `setPreviewStreamSize(SizeSelector)`: or, indirectly, the snapshot size. You can, however, hook into the process using `setPreviewStreamSize(SizeSelector)`:
```java ```java
@ -79,7 +79,7 @@ cameraView.setPreviewStreamSize(new SizeSelector() {
}); });
``` ```
After the preview stream size is determined, if it has changed since list time, the `CameraView` will receive After the preview stream size is determined, if it has changed since last time, the `CameraView` will receive
another call to `onMeasure` so the `WRAP_CONTENT` magic can take place. another call to `onMeasure` so the `WRAP_CONTENT` magic can take place.
To understand how SizeSelectors work and the available utilities, please read the [Capture Size](capture-size) document. To understand how SizeSelectors work and the available utilities, please read the [Capture Size](capture-size) document.

@ -105,8 +105,8 @@ which means that **square videos** or any other ratio are possible.
The video snapshot supports audio and respects the `Audio`, max duration, max size & codec settings, The video snapshot supports audio and respects the `Audio`, max duration, max size & codec settings,
which makes it a powerful tool. The drawback is that it needs: which makes it a powerful tool. The drawback is that it needs:
- API 18. If called before, it throws - API 18. If called on earlier versions, it throws an `IllegalStateException`
- An OpenGL preview (see below). If not, it throws - An OpenGL preview (see below). If not, it throws an `IllegalStateException`
##### Video capturing ##### Video capturing
Some new APIs were introduced, which are respected by both standard videos and snapshot videos: Some new APIs were introduced, which are respected by both standard videos and snapshot videos:
@ -141,7 +141,7 @@ smart enough to
- respect the picture/video aspect ratio - respect the picture/video aspect ratio
- be a bit bigger than the view so that there is no upscaling - be a bit bigger than the view so that there is no upscaling
There are not so many reason why you would use this method, other than, for example, control the frame There are not so many reasons why you would use this method, other than, for example, to control the frame
processor size or, indirectly, the snapshots size. If what you are doing is just assigning an aspect ratio, processor size or, indirectly, the snapshots size. If what you are doing is just assigning an aspect ratio,
for instance, please do so using `setPictureSize()` and `setVideoSize()`. for instance, please do so using `setPictureSize()` and `setVideoSize()`.

Loading…
Cancel
Save