1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.messaging.ui.mediapicker; 18 19 import android.hardware.Camera; 20 import android.media.CamcorderProfile; 21 import android.media.MediaRecorder; 22 import android.net.Uri; 23 import android.os.ParcelFileDescriptor; 24 25 import com.android.messaging.Factory; 26 import com.android.messaging.datamodel.MediaScratchFileProvider; 27 import com.android.messaging.util.ContentType; 28 import com.android.messaging.util.SafeAsyncTask; 29 30 import java.io.FileNotFoundException; 31 import java.io.IOException; 32 33 class MmsVideoRecorder extends MediaRecorder { 34 private static final float VIDEO_OVERSHOOT_SLOP = .85F; 35 36 private static final int BITS_PER_BYTE = 8; 37 38 // We think user will expect to be able to record videos at least this long 39 private static final long MIN_DURATION_LIMIT_SECONDS = 25; 40 41 /** The uri where video is being recorded to */ 42 private Uri mTempVideoUri; 43 44 private ParcelFileDescriptor mVideoFD; 45 46 /** The settings used for video recording */ 47 private final CamcorderProfile mCamcorderProfile; 48 MmsVideoRecorder(final Camera camera, final int cameraIndex, final int orientation, final int maxMessageSize)49 public MmsVideoRecorder(final Camera camera, final int cameraIndex, final int orientation, 50 final int maxMessageSize) 51 throws FileNotFoundException { 52 mCamcorderProfile = 53 CamcorderProfile.get(cameraIndex, CamcorderProfile.QUALITY_LOW); 54 mTempVideoUri = MediaScratchFileProvider.buildMediaScratchSpaceUri( 55 ContentType.getExtension(getContentType())); 56 57 // The video recorder can sometimes return a file that's larger than the max we 58 // say we can handle. Try to handle that overshoot by specifying an 85% limit. 59 final long sizeLimit = (long) (maxMessageSize * VIDEO_OVERSHOOT_SLOP); 60 61 // The QUALITY_LOW profile might not be low enough to allow for video of a reasonable 62 // minimum duration. Adjust a/v bitrates to allow at least MIN_DURATION_LIMIT video 63 // to be recorded. 64 int audioBitRate = mCamcorderProfile.audioBitRate; 65 int videoBitRate = mCamcorderProfile.videoBitRate; 66 final double initialDurationLimit = sizeLimit * BITS_PER_BYTE 67 / (double) (audioBitRate + videoBitRate); 68 if (initialDurationLimit < MIN_DURATION_LIMIT_SECONDS) { 69 // Reduce the suggested bitrates. These bitrates are only requests, if implementation 70 // can't actually hit these goals it will still record video at higher rate and stop when 71 // it hits the size limit. 72 final double bitRateAdjustmentFactor = initialDurationLimit / MIN_DURATION_LIMIT_SECONDS; 73 audioBitRate *= bitRateAdjustmentFactor; 74 videoBitRate *= bitRateAdjustmentFactor; 75 } 76 77 setCamera(camera); 78 setOrientationHint(orientation); 79 setAudioSource(MediaRecorder.AudioSource.CAMCORDER); 80 setVideoSource(MediaRecorder.VideoSource.CAMERA); 81 setOutputFormat(mCamcorderProfile.fileFormat); 82 mVideoFD = Factory.get().getApplicationContext().getContentResolver() 83 .openFileDescriptor(mTempVideoUri, "w"); 84 setOutputFile(mVideoFD.getFileDescriptor()); 85 86 // Copy settings from CamcorderProfile to MediaRecorder 87 setAudioEncodingBitRate(audioBitRate); 88 setAudioChannels(mCamcorderProfile.audioChannels); 89 setAudioEncoder(mCamcorderProfile.audioCodec); 90 setAudioSamplingRate(mCamcorderProfile.audioSampleRate); 91 setVideoEncodingBitRate(videoBitRate); 92 setVideoEncoder(mCamcorderProfile.videoCodec); 93 setVideoFrameRate(mCamcorderProfile.videoFrameRate); 94 setVideoSize( 95 mCamcorderProfile.videoFrameWidth, mCamcorderProfile.videoFrameHeight); 96 setMaxFileSize(sizeLimit); 97 } 98 getVideoUri()99 Uri getVideoUri() { 100 return mTempVideoUri; 101 } 102 getVideoWidth()103 int getVideoWidth() { 104 return mCamcorderProfile.videoFrameWidth; 105 } 106 getVideoHeight()107 int getVideoHeight() { 108 return mCamcorderProfile.videoFrameHeight; 109 } 110 cleanupTempFile()111 void cleanupTempFile() { 112 final Uri tempUri = mTempVideoUri; 113 SafeAsyncTask.executeOnThreadPool(new Runnable() { 114 @Override 115 public void run() { 116 Factory.get().getApplicationContext().getContentResolver().delete( 117 tempUri, null, null); 118 } 119 }); 120 mTempVideoUri = null; 121 } 122 getContentType()123 String getContentType() { 124 if (mCamcorderProfile.fileFormat == OutputFormat.MPEG_4) { 125 return ContentType.VIDEO_MP4; 126 } else { 127 // 3GPP is the only other video format with a constant in OutputFormat 128 return ContentType.VIDEO_3GPP; 129 } 130 } 131 closeVideoFileDescriptor()132 public void closeVideoFileDescriptor() { 133 if (mVideoFD != null) { 134 try { 135 mVideoFD.close(); 136 } catch (IOException e) { 137 // Ignore 138 } 139 mVideoFD = null; 140 } 141 } 142 } 143