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
17package com.android.messaging.ui.mediapicker;
18
19import android.hardware.Camera;
20import android.media.CamcorderProfile;
21import android.media.MediaRecorder;
22import android.net.Uri;
23
24import com.android.messaging.Factory;
25import com.android.messaging.datamodel.MediaScratchFileProvider;
26import com.android.messaging.util.ContentType;
27import com.android.messaging.util.SafeAsyncTask;
28
29import java.io.FileNotFoundException;
30
31class MmsVideoRecorder extends MediaRecorder {
32    private static final float VIDEO_OVERSHOOT_SLOP = .85F;
33
34    private static final int BITS_PER_BYTE = 8;
35
36    // We think user will expect to be able to record videos at least this long
37    private static final long MIN_DURATION_LIMIT_SECONDS = 25;
38
39    /** The uri where video is being recorded to */
40    private Uri mTempVideoUri;
41
42    /** The settings used for video recording */
43    private final CamcorderProfile mCamcorderProfile;
44
45    public MmsVideoRecorder(final Camera camera, final int cameraIndex, final int orientation,
46            final int maxMessageSize)
47            throws FileNotFoundException {
48        mCamcorderProfile =
49                CamcorderProfile.get(cameraIndex, CamcorderProfile.QUALITY_LOW);
50        mTempVideoUri = MediaScratchFileProvider.buildMediaScratchSpaceUri(
51                ContentType.getExtension(getContentType()));
52
53        // The video recorder can sometimes return a file that's larger than the max we
54        // say we can handle. Try to handle that overshoot by specifying an 85% limit.
55        final long sizeLimit = (long) (maxMessageSize * VIDEO_OVERSHOOT_SLOP);
56
57        // The QUALITY_LOW profile might not be low enough to allow for video of a reasonable
58        // minimum duration.  Adjust a/v bitrates to allow at least MIN_DURATION_LIMIT video
59        // to be recorded.
60        int audioBitRate = mCamcorderProfile.audioBitRate;
61        int videoBitRate = mCamcorderProfile.videoBitRate;
62        final double initialDurationLimit = sizeLimit * BITS_PER_BYTE
63                / (double) (audioBitRate + videoBitRate);
64        if (initialDurationLimit < MIN_DURATION_LIMIT_SECONDS) {
65            // Reduce the suggested bitrates.  These bitrates are only requests, if implementation
66            // can't actually hit these goals it will still record video at higher rate and stop when
67            // it hits the size limit.
68            final double bitRateAdjustmentFactor = initialDurationLimit / MIN_DURATION_LIMIT_SECONDS;
69            audioBitRate *= bitRateAdjustmentFactor;
70            videoBitRate *= bitRateAdjustmentFactor;
71        }
72
73        setCamera(camera);
74        setOrientationHint(orientation);
75        setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
76        setVideoSource(MediaRecorder.VideoSource.CAMERA);
77        setOutputFormat(mCamcorderProfile.fileFormat);
78        setOutputFile(
79                Factory.get().getApplicationContext().getContentResolver().openFileDescriptor(
80                        mTempVideoUri, "w").getFileDescriptor());
81
82        // Copy settings from CamcorderProfile to MediaRecorder
83        setAudioEncodingBitRate(audioBitRate);
84        setAudioChannels(mCamcorderProfile.audioChannels);
85        setAudioEncoder(mCamcorderProfile.audioCodec);
86        setAudioSamplingRate(mCamcorderProfile.audioSampleRate);
87        setVideoEncodingBitRate(videoBitRate);
88        setVideoEncoder(mCamcorderProfile.videoCodec);
89        setVideoFrameRate(mCamcorderProfile.videoFrameRate);
90        setVideoSize(
91                mCamcorderProfile.videoFrameWidth, mCamcorderProfile.videoFrameHeight);
92        setMaxFileSize(sizeLimit);
93    }
94
95    Uri getVideoUri() {
96        return mTempVideoUri;
97    }
98
99    int getVideoWidth() {
100        return mCamcorderProfile.videoFrameWidth;
101    }
102
103    int getVideoHeight() {
104        return mCamcorderProfile.videoFrameHeight;
105    }
106
107    void cleanupTempFile() {
108        final Uri tempUri = mTempVideoUri;
109        SafeAsyncTask.executeOnThreadPool(new Runnable() {
110            @Override
111            public void run() {
112                Factory.get().getApplicationContext().getContentResolver().delete(
113                        tempUri, null, null);
114            }
115        });
116        mTempVideoUri = null;
117    }
118
119    String getContentType() {
120        if (mCamcorderProfile.fileFormat == OutputFormat.MPEG_4) {
121            return ContentType.VIDEO_MP4;
122        } else {
123            // 3GPP is the only other video format with a constant in OutputFormat
124            return ContentType.VIDEO_3GPP;
125        }
126    }
127}
128