Skip to content

Commit

Permalink
Revert "[camera] Fix CamcorderProfile Usages (flutter#4423) (cherry p…
Browse files Browse the repository at this point in the history
…icked from commit 29f46b4)"

This reverts commit 253cf48
  • Loading branch information
henri-henri committed Nov 29, 2021
1 parent a0744e7 commit bf2e3e4
Show file tree
Hide file tree
Showing 12 changed files with 67 additions and 656 deletions.
9 changes: 4 additions & 5 deletions packages/camera/camera/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:7.0.2'
classpath 'com.android.tools.build:gradle:3.5.0'
}
}

Expand All @@ -27,10 +27,9 @@ project.getTasks().withType(JavaCompile){
apply plugin: 'com.android.library'

android {
compileSdkVersion 31
compileSdkVersion 29

defaultConfig {
targetSdkVersion 31
minSdkVersion 21
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down Expand Up @@ -61,7 +60,7 @@ android {
dependencies {
compileOnly 'androidx.annotation:annotation:1.1.0'
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-inline:4.0.0'
testImplementation 'org.mockito:mockito-inline:3.12.4'
testImplementation 'androidx.test:core:1.3.0'
testImplementation 'org.robolectric:robolectric:4.5'
testImplementation 'org.robolectric:robolectric:4.3'
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.SessionConfiguration;
import android.media.CamcorderProfile;
import android.media.EncoderProfiles;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaRecorder;
Expand Down Expand Up @@ -200,16 +199,8 @@ private void prepareMediaRecorder(String outputFilePath) throws IOException {
((SensorOrientationFeature) cameraFeatures.getSensorOrientation())
.getLockedCaptureOrientation();

MediaRecorderBuilder mediaRecorderBuilder;

if (Build.VERSION.SDK_INT >= 31) {
mediaRecorderBuilder = new MediaRecorderBuilder(getRecordingProfile(), outputFilePath);
} else {
mediaRecorderBuilder = new MediaRecorderBuilder(getRecordingProfileLegacy(), outputFilePath);
}

mediaRecorder =
mediaRecorderBuilder
new MediaRecorderBuilder(getRecordingProfile(), outputFilePath)
.setEnableAudio(enableAudio)
.setMediaOrientation(
lockedOrientation == null
Expand Down Expand Up @@ -931,12 +922,8 @@ public float getMinZoomLevel() {
return cameraFeatures.getZoomLevel().getMinimumZoomLevel();
}

/** Shortcut to get current recording profile. Legacy method provides support for SDK < 31. */
CamcorderProfile getRecordingProfileLegacy() {
return cameraFeatures.getResolution().getRecordingProfileLegacy();
}

EncoderProfiles getRecordingProfile() {
/** Shortcut to get current recording profile. */
CamcorderProfile getRecordingProfile() {
return cameraFeatures.getResolution().getRecordingProfile();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,12 @@

package io.flutter.plugins.camera.features.resolution;

import android.annotation.TargetApi;
import android.hardware.camera2.CaptureRequest;
import android.media.CamcorderProfile;
import android.media.EncoderProfiles;
import android.os.Build;
import android.util.Size;
import androidx.annotation.VisibleForTesting;
import io.flutter.plugins.camera.CameraProperties;
import io.flutter.plugins.camera.features.CameraFeature;
import java.util.List;

/**
* Controls the resolutions configuration on the {@link android.hardware.camera2} API.
Expand All @@ -25,8 +21,7 @@
public class ResolutionFeature extends CameraFeature<ResolutionPreset> {
private Size captureSize;
private Size previewSize;
private CamcorderProfile recordingProfileLegacy;
private EncoderProfiles recordingProfile;
private CamcorderProfile recordingProfile;
private ResolutionPreset currentSetting;
private int cameraId;

Expand Down Expand Up @@ -56,11 +51,7 @@ public ResolutionFeature(
*
* @return Resolution information to configure the {@link android.hardware.camera2} API.
*/
public CamcorderProfile getRecordingProfileLegacy() {
return this.recordingProfileLegacy;
}

public EncoderProfiles getRecordingProfile() {
public CamcorderProfile getRecordingProfile() {
return this.recordingProfile;
}

Expand Down Expand Up @@ -109,29 +100,19 @@ public void updateBuilder(CaptureRequest.Builder requestBuilder) {
}

@VisibleForTesting
static Size computeBestPreviewSize(int cameraId, ResolutionPreset preset)
throws IndexOutOfBoundsException {
static Size computeBestPreviewSize(int cameraId, ResolutionPreset preset) {
if (preset.ordinal() > ResolutionPreset.high.ordinal()) {
preset = ResolutionPreset.high;
}
if (Build.VERSION.SDK_INT >= 31) {
EncoderProfiles profile =
getBestAvailableCamcorderProfileForResolutionPreset(cameraId, preset);
List<EncoderProfiles.VideoProfile> videoProfiles = profile.getVideoProfiles();
EncoderProfiles.VideoProfile defaultVideoProfile = videoProfiles.get(0);

return new Size(defaultVideoProfile.getWidth(), defaultVideoProfile.getHeight());
} else {
@SuppressWarnings("deprecation")
CamcorderProfile profile =
getBestAvailableCamcorderProfileForResolutionPresetLegacy(cameraId, preset);
return new Size(profile.videoFrameWidth, profile.videoFrameHeight);
}
CamcorderProfile profile =
getBestAvailableCamcorderProfileForResolutionPreset(cameraId, preset);
return new Size(profile.videoFrameWidth, profile.videoFrameHeight);
}

/**
* Gets the best possible {@link android.media.CamcorderProfile} for the supplied {@link
* ResolutionPreset}. Supports SDK < 31.
* ResolutionPreset}.
*
* @param cameraId Camera identifier which indicates the device's camera for which to select a
* {@link android.media.CamcorderProfile}.
Expand All @@ -140,7 +121,7 @@ static Size computeBestPreviewSize(int cameraId, ResolutionPreset preset)
* @return The best possible {@link android.media.CamcorderProfile} that matches the supplied
* {@link ResolutionPreset}.
*/
public static CamcorderProfile getBestAvailableCamcorderProfileForResolutionPresetLegacy(
public static CamcorderProfile getBestAvailableCamcorderProfileForResolutionPreset(
int cameraId, ResolutionPreset preset) {
if (cameraId < 0) {
throw new AssertionError(
Expand Down Expand Up @@ -183,74 +164,13 @@ public static CamcorderProfile getBestAvailableCamcorderProfileForResolutionPres
}
}

@TargetApi(Build.VERSION_CODES.S)
public static EncoderProfiles getBestAvailableCamcorderProfileForResolutionPreset(
int cameraId, ResolutionPreset preset) {
if (cameraId < 0) {
throw new AssertionError(
"getBestAvailableCamcorderProfileForResolutionPreset can only be used with valid (>=0) camera identifiers.");
}

String cameraIdString = Integer.toString(cameraId);

switch (preset) {
// All of these cases deliberately fall through to get the best available profile.
case max:
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_HIGH)) {
return CamcorderProfile.getAll(cameraIdString, CamcorderProfile.QUALITY_HIGH);
}
case ultraHigh:
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_2160P)) {
return CamcorderProfile.getAll(cameraIdString, CamcorderProfile.QUALITY_2160P);
}
case veryHigh:
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_1080P)) {
return CamcorderProfile.getAll(cameraIdString, CamcorderProfile.QUALITY_1080P);
}
case high:
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_720P)) {
return CamcorderProfile.getAll(cameraIdString, CamcorderProfile.QUALITY_720P);
}
case medium:
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_480P)) {
return CamcorderProfile.getAll(cameraIdString, CamcorderProfile.QUALITY_480P);
}
case low:
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_QVGA)) {
return CamcorderProfile.getAll(cameraIdString, CamcorderProfile.QUALITY_QVGA);
}
default:
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_LOW)) {
return CamcorderProfile.getAll(cameraIdString, CamcorderProfile.QUALITY_LOW);
}

throw new IllegalArgumentException(
"No capture session available for current capture session.");
}
}

private void configureResolution(ResolutionPreset resolutionPreset, int cameraId)
throws IndexOutOfBoundsException {
private void configureResolution(ResolutionPreset resolutionPreset, int cameraId) {
if (!checkIsSupported()) {
return;
}

if (Build.VERSION.SDK_INT >= 31) {
recordingProfile =
getBestAvailableCamcorderProfileForResolutionPreset(cameraId, resolutionPreset);
List<EncoderProfiles.VideoProfile> videoProfiles = recordingProfile.getVideoProfiles();

EncoderProfiles.VideoProfile defaultVideoProfile = videoProfiles.get(0);
captureSize = new Size(defaultVideoProfile.getWidth(), defaultVideoProfile.getHeight());
} else {
@SuppressWarnings("deprecation")
CamcorderProfile camcorderProfile =
getBestAvailableCamcorderProfileForResolutionPresetLegacy(cameraId, resolutionPreset);
recordingProfileLegacy = camcorderProfile;
captureSize =
new Size(recordingProfileLegacy.videoFrameWidth, recordingProfileLegacy.videoFrameHeight);
}

recordingProfile =
getBestAvailableCamcorderProfileForResolutionPreset(cameraId, resolutionPreset);
captureSize = new Size(recordingProfile.videoFrameWidth, recordingProfile.videoFrameHeight);
previewSize = computeBestPreviewSize(cameraId, resolutionPreset);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,55 +5,35 @@
package io.flutter.plugins.camera.media;

import android.media.CamcorderProfile;
import android.media.EncoderProfiles;
import android.media.MediaRecorder;
import android.os.Build;
import androidx.annotation.NonNull;
import java.io.IOException;

public class MediaRecorderBuilder {
@SuppressWarnings("deprecation")
static class MediaRecorderFactory {
MediaRecorder makeMediaRecorder() {
return new MediaRecorder();
}
}

private final String outputFilePath;
private final CamcorderProfile camcorderProfile;
private final EncoderProfiles encoderProfiles;
private final CamcorderProfile recordingProfile;
private final MediaRecorderFactory recorderFactory;

private boolean enableAudio;
private int mediaOrientation;

public MediaRecorderBuilder(
@NonNull CamcorderProfile camcorderProfile, @NonNull String outputFilePath) {
this(camcorderProfile, outputFilePath, new MediaRecorderFactory());
}

public MediaRecorderBuilder(
@NonNull EncoderProfiles encoderProfiles, @NonNull String outputFilePath) {
this(encoderProfiles, outputFilePath, new MediaRecorderFactory());
@NonNull CamcorderProfile recordingProfile, @NonNull String outputFilePath) {
this(recordingProfile, outputFilePath, new MediaRecorderFactory());
}

MediaRecorderBuilder(
@NonNull CamcorderProfile camcorderProfile,
@NonNull CamcorderProfile recordingProfile,
@NonNull String outputFilePath,
MediaRecorderFactory helper) {
this.outputFilePath = outputFilePath;
this.camcorderProfile = camcorderProfile;
this.encoderProfiles = null;
this.recorderFactory = helper;
}

MediaRecorderBuilder(
@NonNull EncoderProfiles encoderProfiles,
@NonNull String outputFilePath,
MediaRecorderFactory helper) {
this.outputFilePath = outputFilePath;
this.encoderProfiles = encoderProfiles;
this.camcorderProfile = null;
this.recordingProfile = recordingProfile;
this.recorderFactory = helper;
}

Expand All @@ -67,43 +47,23 @@ public MediaRecorderBuilder setMediaOrientation(int orientation) {
return this;
}

public MediaRecorder build() throws IOException, NullPointerException, IndexOutOfBoundsException {
public MediaRecorder build() throws IOException {
MediaRecorder mediaRecorder = recorderFactory.makeMediaRecorder();

// There's a fixed order that mediaRecorder expects. Only change these functions accordingly.
// You can find the specifics here: https://developer.android.com/reference/android/media/MediaRecorder.
if (enableAudio) mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);

if (Build.VERSION.SDK_INT >= 31) {
EncoderProfiles.VideoProfile videoProfile = encoderProfiles.getVideoProfiles().get(0);
EncoderProfiles.AudioProfile audioProfile = encoderProfiles.getAudioProfiles().get(0);

mediaRecorder.setOutputFormat(encoderProfiles.getRecommendedFileFormat());
if (enableAudio) {
mediaRecorder.setAudioEncoder(audioProfile.getCodec());
mediaRecorder.setAudioEncodingBitRate(audioProfile.getBitrate());
mediaRecorder.setAudioSamplingRate(audioProfile.getSampleRate());
}
mediaRecorder.setVideoEncoder(videoProfile.getCodec());
mediaRecorder.setVideoEncodingBitRate(videoProfile.getBitrate());
mediaRecorder.setVideoFrameRate(videoProfile.getFrameRate());
mediaRecorder.setVideoSize(videoProfile.getWidth(), videoProfile.getHeight());
mediaRecorder.setVideoSize(videoProfile.getWidth(), videoProfile.getHeight());
} else {
mediaRecorder.setOutputFormat(camcorderProfile.fileFormat);
if (enableAudio) {
mediaRecorder.setAudioEncoder(camcorderProfile.audioCodec);
mediaRecorder.setAudioEncodingBitRate(camcorderProfile.audioBitRate);
mediaRecorder.setAudioSamplingRate(camcorderProfile.audioSampleRate);
}
mediaRecorder.setVideoEncoder(camcorderProfile.videoCodec);
mediaRecorder.setVideoEncodingBitRate(camcorderProfile.videoBitRate);
mediaRecorder.setVideoFrameRate(camcorderProfile.videoFrameRate);
mediaRecorder.setVideoSize(
camcorderProfile.videoFrameWidth, camcorderProfile.videoFrameHeight);
mediaRecorder.setOutputFormat(recordingProfile.fileFormat);
if (enableAudio) {
mediaRecorder.setAudioEncoder(recordingProfile.audioCodec);
mediaRecorder.setAudioEncodingBitRate(recordingProfile.audioBitRate);
mediaRecorder.setAudioSamplingRate(recordingProfile.audioSampleRate);
}

mediaRecorder.setVideoEncoder(recordingProfile.videoCodec);
mediaRecorder.setVideoEncodingBitRate(recordingProfile.videoBitRate);
mediaRecorder.setVideoFrameRate(recordingProfile.videoFrameRate);
mediaRecorder.setVideoSize(recordingProfile.videoFrameWidth, recordingProfile.videoFrameHeight);
mediaRecorder.setOutputFile(outputFilePath);
mediaRecorder.setOrientationHint(this.mediaOrientation);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Handler;
Expand Down Expand Up @@ -248,6 +249,20 @@ public void getMinZoomLevel() {
assertEquals(expectedMinZoomLevel, actualMinZoomLevel, 0);
}

@Test
public void getRecordingProfile() {
ResolutionFeature mockResolutionFeature =
mockCameraFeatureFactory.createResolutionFeature(mockCameraProperties, null, null);
CamcorderProfile mockCamcorderProfile = mock(CamcorderProfile.class);

when(mockResolutionFeature.getRecordingProfile()).thenReturn(mockCamcorderProfile);

CamcorderProfile actualRecordingProfile = camera.getRecordingProfile();

verify(mockResolutionFeature, times(1)).getRecordingProfile();
assertEquals(mockCamcorderProfile, actualRecordingProfile);
}

@Test
public void setExposureMode_shouldUpdateExposureLockFeature() {
ExposureLockFeature mockExposureLockFeature =
Expand Down
Loading

0 comments on commit bf2e3e4

Please sign in to comment.