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