summaryrefslogtreecommitdiffstats
path: root/src/com/android
diff options
context:
space:
mode:
authorPraveen Chavan <pchavan@codeaurora.org>2016-01-07 22:36:51 +0100
committerDaniel Hillenbrand <codeworkx@cyanogenmod.org>2016-01-07 13:45:38 -0800
commit3626f48bf1293ba1e8b15309df9a698a77fe786e (patch)
tree061c8b27a80c527db34272f79f7c42d7903f0a60 /src/com/android
parent06ac71fabf96e0a6d6ef5b0a96f729b4a1c0e412 (diff)
downloadandroid_packages_apps_Snap-3626f48bf1293ba1e8b15309df9a698a77fe786e.tar.gz
android_packages_apps_Snap-3626f48bf1293ba1e8b15309df9a698a77fe786e.tar.bz2
android_packages_apps_Snap-3626f48bf1293ba1e8b15309df9a698a77fe786e.zip
SnapdragonCamera: Add support for high-speed video recording
[1] Use combination of MediaRecorder.setCaptureRate and setVideoFrameRate API to achieve HFR/HSR ------------------------------------------------------------ CaptureRate videoFrameRate Recorded-video ------------------------------------------------------------ 120 30 slow-mo @30fps 120 120 high-speed-video @120fps ------------------------------------------------------------ Deprecate usage of custom fields added to media-profiles for checking max-capabilities. Instead, introduce high-speed profiles and advertize correct values (resolution, fps) to indicate target capabilities. Add conversion routines in CameraSettings to convert from normal quality level to time-lapse/high-speed quality. Also, add back 4KDCI and VGA support TODO: Implement bitrate scaling if AOSP does not implement in native. Change-Id: Ic1d5ed8ef52348cab2383abe304056e0401f7069
Diffstat (limited to 'src/com/android')
-rw-r--r--src/com/android/camera/CameraSettings.java54
-rw-r--r--src/com/android/camera/VideoModule.java180
2 files changed, 168 insertions, 66 deletions
diff --git a/src/com/android/camera/CameraSettings.java b/src/com/android/camera/CameraSettings.java
index d97e3b86d..2567e89c0 100644
--- a/src/com/android/camera/CameraSettings.java
+++ b/src/com/android/camera/CameraSettings.java
@@ -266,7 +266,51 @@ public class CameraSettings {
VIDEO_QUALITY_TABLE.put("352x288", CamcorderProfile.QUALITY_CIF);
VIDEO_QUALITY_TABLE.put("320x240", CamcorderProfile.QUALITY_QVGA);
VIDEO_QUALITY_TABLE.put("176x144", CamcorderProfile.QUALITY_QCIF);
- }
+ }
+
+ // Following maps help find a corresponding time-lapse or high-speed quality
+ // given a normal quality.
+ // Ideally, one should be able to traverse by offsetting +1000, +2000 respectively,
+ // But the profile values are messed-up in AOSP
+ private static final HashMap<Integer, Integer>
+ VIDEO_QUALITY_TO_TIMELAPSE = new HashMap<Integer, Integer>();
+ static {
+ VIDEO_QUALITY_TO_TIMELAPSE.put(CamcorderProfile.QUALITY_LOW , CamcorderProfile.QUALITY_TIME_LAPSE_LOW );
+ VIDEO_QUALITY_TO_TIMELAPSE.put(CamcorderProfile.QUALITY_HIGH , CamcorderProfile.QUALITY_TIME_LAPSE_HIGH );
+ VIDEO_QUALITY_TO_TIMELAPSE.put(CamcorderProfile.QUALITY_QCIF , CamcorderProfile.QUALITY_TIME_LAPSE_QCIF );
+ VIDEO_QUALITY_TO_TIMELAPSE.put(CamcorderProfile.QUALITY_CIF , CamcorderProfile.QUALITY_TIME_LAPSE_CIF );
+ VIDEO_QUALITY_TO_TIMELAPSE.put(CamcorderProfile.QUALITY_480P , CamcorderProfile.QUALITY_TIME_LAPSE_480P );
+ VIDEO_QUALITY_TO_TIMELAPSE.put(CamcorderProfile.QUALITY_720P , CamcorderProfile.QUALITY_TIME_LAPSE_720P );
+ VIDEO_QUALITY_TO_TIMELAPSE.put(CamcorderProfile.QUALITY_1080P, CamcorderProfile.QUALITY_TIME_LAPSE_1080P);
+ VIDEO_QUALITY_TO_TIMELAPSE.put(CamcorderProfile.QUALITY_QVGA , CamcorderProfile.QUALITY_TIME_LAPSE_QVGA );
+ VIDEO_QUALITY_TO_TIMELAPSE.put(CamcorderProfile.QUALITY_2160P, CamcorderProfile.QUALITY_TIME_LAPSE_2160P);
+ VIDEO_QUALITY_TO_TIMELAPSE.put(CamcorderProfile.QUALITY_VGA , CamcorderProfile.QUALITY_TIME_LAPSE_VGA );
+ VIDEO_QUALITY_TO_TIMELAPSE.put(CamcorderProfile.QUALITY_4KDCI, CamcorderProfile.QUALITY_TIME_LAPSE_4KDCI);
+ }
+
+ public static int getTimeLapseQualityFor(int quality) {
+ return VIDEO_QUALITY_TO_TIMELAPSE.get(quality);
+ }
+
+ private static final HashMap<Integer, Integer>
+ VIDEO_QUALITY_TO_HIGHSPEED = new HashMap<Integer, Integer>();
+ static {
+ VIDEO_QUALITY_TO_HIGHSPEED.put(CamcorderProfile.QUALITY_LOW , CamcorderProfile.QUALITY_HIGH_SPEED_LOW );
+ VIDEO_QUALITY_TO_HIGHSPEED.put(CamcorderProfile.QUALITY_HIGH , CamcorderProfile.QUALITY_HIGH_SPEED_HIGH );
+ VIDEO_QUALITY_TO_HIGHSPEED.put(CamcorderProfile.QUALITY_QCIF , -1 ); // does not exist
+ VIDEO_QUALITY_TO_HIGHSPEED.put(CamcorderProfile.QUALITY_CIF , CamcorderProfile.QUALITY_HIGH_SPEED_CIF );
+ VIDEO_QUALITY_TO_HIGHSPEED.put(CamcorderProfile.QUALITY_480P , CamcorderProfile.QUALITY_HIGH_SPEED_480P );
+ VIDEO_QUALITY_TO_HIGHSPEED.put(CamcorderProfile.QUALITY_720P , CamcorderProfile.QUALITY_HIGH_SPEED_720P );
+ VIDEO_QUALITY_TO_HIGHSPEED.put(CamcorderProfile.QUALITY_1080P, CamcorderProfile.QUALITY_HIGH_SPEED_1080P);
+ VIDEO_QUALITY_TO_HIGHSPEED.put(CamcorderProfile.QUALITY_QVGA , -1 ); // does not exist
+ VIDEO_QUALITY_TO_HIGHSPEED.put(CamcorderProfile.QUALITY_2160P, CamcorderProfile.QUALITY_HIGH_SPEED_2160P);
+ VIDEO_QUALITY_TO_HIGHSPEED.put(CamcorderProfile.QUALITY_VGA , CamcorderProfile.QUALITY_HIGH_SPEED_VGA );
+ VIDEO_QUALITY_TO_HIGHSPEED.put(CamcorderProfile.QUALITY_4KDCI, CamcorderProfile.QUALITY_HIGH_SPEED_4KDCI);
+ }
+
+ public static int getHighSpeedQualityFor(int quality) {
+ return VIDEO_QUALITY_TO_HIGHSPEED.get(quality);
+ }
public CameraSettings(Activity activity, Parameters parameters,
int cameraId, CameraInfo[] cameraInfo) {
@@ -1261,13 +1305,13 @@ public class CameraSettings {
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
private static void getFineResolutionQuality(ArrayList<String> supported,
int cameraId,Parameters parameters) {
-/*
- if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_4kDCI)) {
+
+ if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_4KDCI)) {
if (checkSupportedVideoQuality(parameters,4096,2160)) {
- supported.add(Integer.toString(CamcorderProfile.QUALITY_4kDCI));
+ supported.add(Integer.toString(CamcorderProfile.QUALITY_4KDCI));
}
}
-*/
+
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_2160P)) {
if (checkSupportedVideoQuality(parameters,3840,2160)) {
supported.add(Integer.toString(CamcorderProfile.QUALITY_2160P));
diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java
index 70cfba011..b9bf36d35 100644
--- a/src/com/android/camera/VideoModule.java
+++ b/src/com/android/camera/VideoModule.java
@@ -892,8 +892,35 @@ public class VideoModule implements CameraModule,
mActivity.getString(R.string.pref_video_time_lapse_frame_interval_default));
mTimeBetweenTimeLapseFrameCaptureMs = Integer.parseInt(frameIntervalStr);
mCaptureTimeLapse = (mTimeBetweenTimeLapseFrameCaptureMs != 0);
- // TODO: This should be checked instead directly +1000.
- if (mCaptureTimeLapse) quality += 1000;
+
+ int hfrRate = 0;
+ String highFrameRate = mPreferences.getString(
+ CameraSettings.KEY_VIDEO_HIGH_FRAME_RATE,
+ mActivity. getString(R.string.pref_camera_hfr_default));
+ if (("hfr".equals(highFrameRate.substring(0,3))) ||
+ ("hsr".equals(highFrameRate.substring(0,3)))) {
+ String rate = highFrameRate.substring(3);
+ Log.i(TAG,"HFR :" + highFrameRate + " : rate = " + rate);
+ try {
+ hfrRate = Integer.parseInt(rate);
+ } catch (NumberFormatException nfe) {
+ Log.e(TAG, "Invalid hfr rate " + rate);
+ }
+ }
+
+ int mappedQuality = quality;
+ if (mCaptureTimeLapse) {
+ mappedQuality = CameraSettings.getTimeLapseQualityFor(quality);
+ } else if (hfrRate > 0) {
+ mappedQuality = CameraSettings.getHighSpeedQualityFor(quality);
+ Log.i(TAG,"NOTE: HighSpeed quality (" + mappedQuality + ") for (" + quality + ")");
+ }
+
+ if (CamcorderProfile.hasProfile(mCameraId, mappedQuality)) {
+ quality = mappedQuality;
+ } else {
+ Log.e(TAG,"NOTE: Quality " + mappedQuality + " is not supported ! Will use " + quality);
+ }
mProfile = CamcorderProfile.get(mCameraId, quality);
getDesiredPreviewSize();
qcomReadVideoPreferences();
@@ -909,8 +936,8 @@ public class VideoModule implements CameraModule,
}
private boolean is4KEnabled() {
- if (mProfile.quality == CamcorderProfile.QUALITY_2160P /*||
- mProfile.quality == CamcorderProfile.QUALITY_4kDCI*/) {
+ if (mProfile.quality == CamcorderProfile.QUALITY_2160P ||
+ mProfile.quality == CamcorderProfile.QUALITY_4KDCI) {
return true;
} else {
return false;
@@ -933,6 +960,32 @@ public class VideoModule implements CameraModule,
}
}
+ private boolean isSessionSupportedByEncoder(int w, int h, int fps) {
+ int expectedMBsPerSec = w * h * fps;
+
+ List<VideoEncoderCap> videoEncoders = EncoderCapabilities.getVideoEncoders();
+ for (VideoEncoderCap videoEncoder: videoEncoders) {
+ if (videoEncoder.mCodec == mVideoEncoder) {
+ int maxMBsPerSec = (videoEncoder.mMaxFrameWidth * videoEncoder.mMaxFrameHeight
+ * videoEncoder.mMaxFrameRate);
+ if (expectedMBsPerSec > maxMBsPerSec) {
+ Log.e(TAG,"Selected codec " + mVideoEncoder
+ + " does not support width(" + w
+ + ") X height ("+ h
+ + "@ " + fps +" fps");
+ Log.e(TAG, "Max capabilities: " +
+ "MaxFrameWidth = " + videoEncoder.mMaxFrameWidth + " , " +
+ "MaxFrameHeight = " + videoEncoder.mMaxFrameHeight + " , " +
+ "MaxFrameRate = " + videoEncoder.mMaxFrameRate);
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
boolean isHFREnabled(int videoWidth, int videoHeight) {
if ((null == mPreferences) || (null == mParameters)) {
return false;
@@ -942,7 +995,7 @@ public class VideoModule implements CameraModule,
CameraSettings.KEY_VIDEO_HIGH_FRAME_RATE,
mActivity. getString(R.string.pref_camera_hfr_default));
- if(!("off".equals(HighFrameRate))) {
+ if (!("off".equals(HighFrameRate))) {
Size size = null;
try {
if (isSupported(HighFrameRate.substring(3), mParameters.getSupportedVideoHighFrameRateModes())) {
@@ -967,25 +1020,8 @@ public class VideoModule implements CameraModule,
}
int hfrFps = Integer.parseInt(HighFrameRate.substring(3));
- int inputBitrate = videoWidth * videoHeight * hfrFps;
-
- boolean supported = false;
- List<VideoEncoderCap> videoEncoders = EncoderCapabilities.getVideoEncoders();
- for (VideoEncoderCap videoEncoder: videoEncoders) {
-//TODO: How to handle HFRFrameWidth and HFRFrameHeight
-/* if (videoEncoder.mCodec == mVideoEncoder) {
- int maxBitrate = (videoEncoder.mMaxHFRFrameWidth *
- videoEncoder.mMaxHFRFrameHeight *
- videoEncoder.mMaxHFRMode);
- if (inputBitrate > 0 && inputBitrate <= maxBitrate ) {
- supported = true;
- }
- break;
- }
-*/
- }
- return supported;
+ return isSessionSupportedByEncoder(videoWidth, videoHeight, hfrFps);
}
return false;
@@ -1518,25 +1554,61 @@ public class VideoModule implements CameraModule,
// Unlock the camera object before passing it to media recorder.
mCameraDevice.unlock();
mMediaRecorder.setCamera(mCameraDevice.getCamera());
+
String hfr = mParameters.getVideoHighFrameRate();
- if (!mCaptureTimeLapse && ((hfr == null) || ("off".equals(hfr)))) {
- mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
- mProfile.audioCodec = mAudioEncoder;
- } else {
- mProfile.audioCodec = -1; //not set
+ String hsr = mParameters.get(CameraSettings.KEY_VIDEO_HSR);
+ Log.i(TAG,"NOTE: hfr = " + hfr + " : hsr = " + hsr);
+
+ int captureRate = 0;
+ boolean isHFR = (hfr != null && !hfr.equals("off"));
+ boolean isHSR = (hsr != null && !hsr.equals("off"));
+
+ try {
+ captureRate = isHFR ? Integer.parseInt(hfr) :
+ isHSR ? Integer.parseInt(hsr) : 0;
+ } catch (NumberFormatException nfe) {
+ Log.e(TAG, "Invalid hfr(" + hfr + ") or hsr(" + hsr + ")");
}
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mProfile.videoCodec = mVideoEncoder;
+ mProfile.audioCodec = mAudioEncoder;
mProfile.duration = mMaxVideoDurationInMs;
- mMediaRecorder.setProfile(mProfile);
+ // Set params individually for HFR case, as we do not want to encode audio
+ if ((isHFR || isHSR) && captureRate > 0) {
+ mMediaRecorder.setOutputFormat(mProfile.fileFormat);
+ mMediaRecorder.setVideoFrameRate(mProfile.videoFrameRate);
+ mMediaRecorder.setVideoEncodingBitRate(mProfile.videoBitRate);
+ mMediaRecorder.setVideoEncoder(mProfile.videoCodec);
+ } else {
+ if (!mCaptureTimeLapse) {
+ mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
+ }
+
+ mMediaRecorder.setProfile(mProfile);
+ }
+
mMediaRecorder.setVideoSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
mMediaRecorder.setMaxDuration(mMaxVideoDurationInMs);
if (mCaptureTimeLapse) {
double fps = 1000 / (double) mTimeBetweenTimeLapseFrameCaptureMs;
setCaptureRate(mMediaRecorder, fps);
+ } else if (captureRate > 0) {
+ Log.i(TAG, "Setting capture-rate = " + captureRate);
+ mMediaRecorder.setCaptureRate(captureRate);
+ // for HFR, encoder's target-framerate = capture-rate
+ if (isHSR) {
+ Log.i(TAG, "Setting fps = " + captureRate + " for HSR");
+ mMediaRecorder.setVideoFrameRate(captureRate);
+ }
+ // for HFR, encoder's taget-framerate = 30fps (from profile)
+ if (isHFR) {
+ Log.i(TAG, "Setting fps = 30 for HFR");
+ mMediaRecorder.setVideoFrameRate(30);
+ }
+ // TODO : bitrate correction..check with google
}
setRecordLocation();
@@ -2181,6 +2253,7 @@ public class VideoModule implements CameraModule,
private void qcomSetCameraParameters(){
// add QCOM Parameters here
// Set color effect parameter.
+ Log.i(TAG,"NOTE: qcomSetCameraParameters " + videoWidth + " x " + videoHeight);
String colorEffect = mPreferences.getString(
CameraSettings.KEY_VIDEOCAMERA_COLOR_EFFECT,
mActivity.getString(R.string.pref_camera_coloreffect_default));
@@ -2286,18 +2359,21 @@ public class VideoModule implements CameraModule,
String HighFrameRate = mPreferences.getString(
CameraSettings.KEY_VIDEO_HIGH_FRAME_RATE,
mActivity. getString(R.string.pref_camera_hfr_default));
- if (("hfr".equals(HighFrameRate.substring(0,3))) ||
- ("hsr".equals(HighFrameRate.substring(0,3)))) {
+ boolean isHFR = "hfr".equals(HighFrameRate.substring(0,3));
+ boolean isHSR = "hsr".equals(HighFrameRate.substring(0,3));
+
+ if (isHFR || isHSR) {
String hfrRate = HighFrameRate.substring(3);
- if ("hfr".equals(HighFrameRate.substring(0,3))) {
+ if (isHFR) {
mUnsupportedHFRVideoSize = true;
} else {
mUnsupportedHSRVideoSize = true;
}
String hfrsize = videoWidth+"x"+videoHeight;
- Log.v(TAG, "current set resolution is : "+hfrsize);
+ Log.v(TAG, "current set resolution is : "+hfrsize+ " : Rate is : " + hfrRate );
try {
Size size = null;
+ Log.i(TAG,"supported rate = " + mParameters.getSupportedVideoHighFrameRateModes());
if (isSupported(hfrRate, mParameters.getSupportedVideoHighFrameRateModes())) {
int index = mParameters.getSupportedVideoHighFrameRateModes().indexOf(
hfrRate);
@@ -2305,7 +2381,7 @@ public class VideoModule implements CameraModule,
}
if (size != null) {
if (videoWidth <= size.width && videoHeight <= size.height) {
- if ("hfr".equals(HighFrameRate.substring(0,3))) {
+ if (isHFR) {
mUnsupportedHFRVideoSize = false;
} else {
mUnsupportedHSRVideoSize = false;
@@ -2318,35 +2394,16 @@ public class VideoModule implements CameraModule,
}
int hfrFps = Integer.parseInt(hfrRate);
- int inputBitrate = videoWidth*videoHeight*hfrFps;
-
- //check if codec supports the resolution, otherwise throw toast
- List<VideoEncoderCap> videoEncoders = EncoderCapabilities.getVideoEncoders();
- for (VideoEncoderCap videoEncoder: videoEncoders) {
- if (videoEncoder.mCodec == mVideoEncoder){
-/* TODO:
- int maxBitrate = (videoEncoder.mMaxHFRFrameWidth *
- videoEncoder.mMaxHFRFrameHeight *
- videoEncoder.mMaxHFRMode);
- if (inputBitrate > maxBitrate ) {
- Log.e(TAG,"Selected codec "+mVideoEncoder+
- " does not support HFR " + HighFrameRate + " with "+ videoWidth
- + "x" + videoHeight +" resolution");
- Log.e(TAG, "Codec capabilities: " +
- "mMaxHFRFrameWidth = " + videoEncoder.mMaxHFRFrameWidth + " , " +
- "mMaxHFRFrameHeight = " + videoEncoder.mMaxHFRFrameHeight + " , " +
- "mMaxHFRMode = " + videoEncoder.mMaxHFRMode);
- if ("hfr".equals(HighFrameRate.substring(0,3))) {
- mUnsupportedHFRVideoSize = true;
- } else {
- mUnsupportedHSRVideoSize = true;
- }
- }
- break;
-*/
+
+ if (!isSessionSupportedByEncoder(videoWidth, videoHeight, hfrFps)) {
+ if (isHFR) {
+ mUnsupportedHFRVideoSize = true;
+ } else {
+ mUnsupportedHSRVideoSize = true;
}
}
- if ("hfr".equals(HighFrameRate.substring(0,3))) {
+
+ if (isHFR) {
mParameters.set(CameraSettings.KEY_VIDEO_HSR, "off");
if (mUnsupportedHFRVideoSize) {
mParameters.setVideoHighFrameRate("off");
@@ -2496,6 +2553,7 @@ public class VideoModule implements CameraModule,
forceFlashOffIfSupported(!mPreviewFocused);
videoWidth = mProfile.videoFrameWidth;
videoHeight = mProfile.videoFrameHeight;
+
String recordSize = videoWidth + "x" + videoHeight;
Log.e(TAG,"Video dimension in App->"+recordSize);
if (CameraUtil.isSupported(mParameters, "video-size")) {