• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 android.media.cts;
18 
19 
20 import android.content.pm.PackageManager;
21 import android.hardware.Camera;
22 import android.hardware.Camera.Parameters;
23 import android.hardware.Camera.Size;
24 import android.media.CamcorderProfile;
25 import android.test.AndroidTestCase;
26 import android.util.Log;
27 
28 import java.util.Arrays;
29 import java.util.List;
30 
31 @NonMediaMainlineTest
32 public class CamcorderProfileTest extends AndroidTestCase {
33 
34     private static final String TAG = "CamcorderProfileTest";
35     private static final int MIN_HIGH_SPEED_FPS = 100;
36     private static final Integer[] ALL_SUPPORTED_QUALITIES = {
37         CamcorderProfile.QUALITY_LOW,
38         CamcorderProfile.QUALITY_HIGH,
39         CamcorderProfile.QUALITY_QCIF,
40         CamcorderProfile.QUALITY_CIF,
41         CamcorderProfile.QUALITY_480P,
42         CamcorderProfile.QUALITY_720P,
43         CamcorderProfile.QUALITY_1080P,
44         CamcorderProfile.QUALITY_QVGA,
45         CamcorderProfile.QUALITY_2160P,
46         CamcorderProfile.QUALITY_TIME_LAPSE_LOW,
47         CamcorderProfile.QUALITY_TIME_LAPSE_HIGH,
48         CamcorderProfile.QUALITY_TIME_LAPSE_QCIF,
49         CamcorderProfile.QUALITY_TIME_LAPSE_CIF,
50         CamcorderProfile.QUALITY_TIME_LAPSE_480P,
51         CamcorderProfile.QUALITY_TIME_LAPSE_720P,
52         CamcorderProfile.QUALITY_TIME_LAPSE_1080P,
53         CamcorderProfile.QUALITY_TIME_LAPSE_QVGA,
54         CamcorderProfile.QUALITY_TIME_LAPSE_2160P,
55         CamcorderProfile.QUALITY_HIGH_SPEED_LOW,
56         CamcorderProfile.QUALITY_HIGH_SPEED_HIGH,
57         CamcorderProfile.QUALITY_HIGH_SPEED_480P,
58         CamcorderProfile.QUALITY_HIGH_SPEED_720P,
59         CamcorderProfile.QUALITY_HIGH_SPEED_1080P,
60         CamcorderProfile.QUALITY_HIGH_SPEED_2160P
61     };
62     private static final int LAST_QUALITY = CamcorderProfile.QUALITY_2K;
63     private static final int LAST_TIMELAPSE_QUALITY = CamcorderProfile.QUALITY_TIME_LAPSE_2K;
64     private static final int LAST_HIGH_SPEED_QUALITY = CamcorderProfile.QUALITY_HIGH_SPEED_4KDCI;
65     private static final Integer[] UNKNOWN_QUALITIES = {
66         LAST_QUALITY + 1, // Unknown normal profile quality
67         LAST_TIMELAPSE_QUALITY + 1, // Unknown timelapse profile quality
68         LAST_HIGH_SPEED_QUALITY + 1 // Unknown high speed timelapse profile quality
69     };
70 
71     // Uses get without id if cameraId == -1 and get with id otherwise.
getWithOptionalId(int quality, int cameraId)72     private CamcorderProfile getWithOptionalId(int quality, int cameraId) {
73         if (cameraId == -1) {
74             return CamcorderProfile.get(quality);
75         } else {
76             return CamcorderProfile.get(cameraId, quality);
77         }
78     }
79 
checkProfile(CamcorderProfile profile, List<Size> videoSizes)80     private void checkProfile(CamcorderProfile profile, List<Size> videoSizes) {
81         Log.v(TAG, String.format("profile: duration=%d, quality=%d, " +
82             "fileFormat=%d, videoCodec=%d, videoBitRate=%d, videoFrameRate=%d, " +
83             "videoFrameWidth=%d, videoFrameHeight=%d, audioCodec=%d, " +
84             "audioBitRate=%d, audioSampleRate=%d, audioChannels=%d",
85             profile.duration,
86             profile.quality,
87             profile.fileFormat,
88             profile.videoCodec,
89             profile.videoBitRate,
90             profile.videoFrameRate,
91             profile.videoFrameWidth,
92             profile.videoFrameHeight,
93             profile.audioCodec,
94             profile.audioBitRate,
95             profile.audioSampleRate,
96             profile.audioChannels));
97         assertTrue(profile.duration > 0);
98         assertTrue(Arrays.asList(ALL_SUPPORTED_QUALITIES).contains(profile.quality));
99         assertTrue(profile.videoBitRate > 0);
100         assertTrue(profile.videoFrameRate > 0);
101         assertTrue(profile.videoFrameWidth > 0);
102         assertTrue(profile.videoFrameHeight > 0);
103         assertTrue(profile.audioBitRate > 0);
104         assertTrue(profile.audioSampleRate > 0);
105         assertTrue(profile.audioChannels > 0);
106         assertTrue(isSizeSupported(profile.videoFrameWidth,
107                                    profile.videoFrameHeight,
108                                    videoSizes));
109     }
110 
assertProfileEquals(CamcorderProfile expectedProfile, CamcorderProfile actualProfile)111     private void assertProfileEquals(CamcorderProfile expectedProfile,
112             CamcorderProfile actualProfile) {
113         assertEquals(expectedProfile.duration, actualProfile.duration);
114         assertEquals(expectedProfile.fileFormat, actualProfile.fileFormat);
115         assertEquals(expectedProfile.videoCodec, actualProfile.videoCodec);
116         assertEquals(expectedProfile.videoBitRate, actualProfile.videoBitRate);
117         assertEquals(expectedProfile.videoFrameRate, actualProfile.videoFrameRate);
118         assertEquals(expectedProfile.videoFrameWidth, actualProfile.videoFrameWidth);
119         assertEquals(expectedProfile.videoFrameHeight, actualProfile.videoFrameHeight);
120         assertEquals(expectedProfile.audioCodec, actualProfile.audioCodec);
121         assertEquals(expectedProfile.audioBitRate, actualProfile.audioBitRate);
122         assertEquals(expectedProfile.audioSampleRate, actualProfile.audioSampleRate);
123         assertEquals(expectedProfile.audioChannels, actualProfile.audioChannels);
124     }
125 
checkSpecificProfileDimensions(CamcorderProfile profile, int quality)126     private void checkSpecificProfileDimensions(CamcorderProfile profile, int quality) {
127         Log.v(TAG, String.format("specific profile: quality=%d, width = %d, height = %d",
128                     profile.quality, profile.videoFrameWidth, profile.videoFrameHeight));
129 
130         switch (quality) {
131             case CamcorderProfile.QUALITY_QCIF:
132             case CamcorderProfile.QUALITY_TIME_LAPSE_QCIF:
133                 assertEquals(176, profile.videoFrameWidth);
134                 assertEquals(144, profile.videoFrameHeight);
135                 break;
136 
137             case CamcorderProfile.QUALITY_CIF:
138             case CamcorderProfile.QUALITY_TIME_LAPSE_CIF:
139                 assertEquals(352, profile.videoFrameWidth);
140                 assertEquals(288, profile.videoFrameHeight);
141                 break;
142 
143             case CamcorderProfile.QUALITY_480P:
144             case CamcorderProfile.QUALITY_TIME_LAPSE_480P:
145                 assertTrue(720 == profile.videoFrameWidth ||  // SMPTE 293M/ITU-R Rec. 601
146                            640 == profile.videoFrameWidth ||  // ATSC/NTSC (square sampling)
147                            704 == profile.videoFrameWidth);   // ATSC/NTSC (non-square sampling)
148                 assertEquals(480, profile.videoFrameHeight);
149                 break;
150 
151             case CamcorderProfile.QUALITY_720P:
152             case CamcorderProfile.QUALITY_TIME_LAPSE_720P:
153                 assertEquals(1280, profile.videoFrameWidth);
154                 assertEquals(720, profile.videoFrameHeight);
155                 break;
156 
157             case CamcorderProfile.QUALITY_1080P:
158             case CamcorderProfile.QUALITY_TIME_LAPSE_1080P:
159                 // 1080p could be either 1920x1088 or 1920x1080.
160                 assertEquals(1920, profile.videoFrameWidth);
161                 assertTrue(1088 == profile.videoFrameHeight ||
162                            1080 == profile.videoFrameHeight);
163                 break;
164             case CamcorderProfile.QUALITY_2160P:
165             case CamcorderProfile.QUALITY_TIME_LAPSE_2160P:
166                 assertEquals(3840, profile.videoFrameWidth);
167                 assertEquals(2160, profile.videoFrameHeight);
168                 break;
169             case CamcorderProfile.QUALITY_HIGH_SPEED_480P:
170                 assertTrue(720 == profile.videoFrameWidth ||  // SMPTE 293M/ITU-R Rec. 601
171                 640 == profile.videoFrameWidth ||  // ATSC/NTSC (square sampling)
172                 704 == profile.videoFrameWidth);   // ATSC/NTSC (non-square sampling)
173                 assertEquals(480, profile.videoFrameHeight);
174                 assertTrue(profile.videoFrameRate >= MIN_HIGH_SPEED_FPS);
175                 break;
176             case CamcorderProfile.QUALITY_HIGH_SPEED_720P:
177                 assertEquals(1280, profile.videoFrameWidth);
178                 assertEquals(720, profile.videoFrameHeight);
179                 assertTrue(profile.videoFrameRate >= MIN_HIGH_SPEED_FPS);
180                 break;
181             case CamcorderProfile.QUALITY_HIGH_SPEED_1080P:
182                 // 1080p could be either 1920x1088 or 1920x1080.
183                 assertEquals(1920, profile.videoFrameWidth);
184                 assertTrue(1088 == profile.videoFrameHeight ||
185                            1080 == profile.videoFrameHeight);
186                 assertTrue(profile.videoFrameRate >= MIN_HIGH_SPEED_FPS);
187                 break;
188         }
189     }
190 
191     // Checks if the existing specific profiles have the correct dimensions.
192     // Also checks that the mimimum quality specific profile matches the low profile and
193     // similarly that the maximum quality specific profile matches the high profile.
checkSpecificProfiles( int cameraId, CamcorderProfile low, CamcorderProfile high, int[] specificQualities, List<Size> videoSizes)194     private void checkSpecificProfiles(
195             int cameraId,
196             CamcorderProfile low,
197             CamcorderProfile high,
198             int[] specificQualities,
199             List<Size> videoSizes) {
200 
201         // For high speed levels, low and high quality are optional,skip the test if
202         // they are missing.
203         if (low == null && high == null) {
204             // No profile should be available if low and high are unavailable.
205             for (int quality : specificQualities) {
206                 assertFalse(CamcorderProfile.hasProfile(cameraId, quality));
207             }
208             return;
209         }
210 
211         CamcorderProfile minProfile = null;
212         CamcorderProfile maxProfile = null;
213 
214         for (int i = 0; i < specificQualities.length; i++) {
215             int quality = specificQualities[i];
216             if ((cameraId != -1 && CamcorderProfile.hasProfile(cameraId, quality)) ||
217                 (cameraId == -1 && CamcorderProfile.hasProfile(quality))) {
218                 CamcorderProfile profile = getWithOptionalId(quality, cameraId);
219                 checkSpecificProfileDimensions(profile, quality);
220 
221                 assertTrue(isSizeSupported(profile.videoFrameWidth,
222                                            profile.videoFrameHeight,
223                                            videoSizes));
224 
225                 if (minProfile == null) {
226                     minProfile = profile;
227                 }
228                 maxProfile = profile;
229             }
230         }
231 
232         assertNotNull(minProfile);
233         assertNotNull(maxProfile);
234 
235         Log.v(TAG, String.format("min profile: quality=%d, width = %d, height = %d",
236                     minProfile.quality, minProfile.videoFrameWidth, minProfile.videoFrameHeight));
237         Log.v(TAG, String.format("max profile: quality=%d, width = %d, height = %d",
238                     maxProfile.quality, maxProfile.videoFrameWidth, maxProfile.videoFrameHeight));
239 
240         assertProfileEquals(low, minProfile);
241         assertProfileEquals(high, maxProfile);
242 
243     }
244 
checkGet(int cameraId)245     private void checkGet(int cameraId) {
246         Log.v(TAG, (cameraId == -1)
247                    ? "Checking get without id"
248                    : "Checking get with id = " + cameraId);
249 
250         final List<Size> videoSizes = getSupportedVideoSizes(cameraId);
251 
252         /**
253          * Check all possible supported profiles: get profile should work, and the profile
254          * should be sane. Note that, timelapse and high speed video sizes may not be listed
255          * as supported video sizes from camera, skip the size check.
256          */
257         for (Integer quality : ALL_SUPPORTED_QUALITIES) {
258             if (CamcorderProfile.hasProfile(cameraId, quality) || isProfileMandatory(quality)) {
259                 List<Size> videoSizesToCheck = null;
260                 if (quality >= CamcorderProfile.QUALITY_LOW &&
261                                 quality <= CamcorderProfile.QUALITY_2160P) {
262                     videoSizesToCheck = videoSizes;
263                 }
264                 CamcorderProfile profile = getWithOptionalId(quality, cameraId);
265                 checkProfile(profile, videoSizesToCheck);
266             }
267         }
268 
269         /**
270          * Check unknown profiles: hasProfile() should return false.
271          */
272         for (Integer quality : UNKNOWN_QUALITIES) {
273             assertFalse("Unknown profile quality " + quality + " shouldn't be supported by camera "
274                     + cameraId, CamcorderProfile.hasProfile(cameraId, quality));
275         }
276 
277         // High speed low and high profile are optional,
278         // but they should be both present or missing.
279         CamcorderProfile lowHighSpeedProfile = null;
280         CamcorderProfile highHighSpeedProfile = null;
281         if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_HIGH_SPEED_LOW)) {
282             lowHighSpeedProfile =
283                     getWithOptionalId(CamcorderProfile.QUALITY_HIGH_SPEED_LOW, cameraId);
284         }
285         if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_HIGH_SPEED_HIGH)) {
286             highHighSpeedProfile =
287                     getWithOptionalId(CamcorderProfile.QUALITY_HIGH_SPEED_HIGH, cameraId);
288         }
289         if (lowHighSpeedProfile != null) {
290             assertNotNull("high speed high quality profile should be supported if low" +
291                     " is supported ",
292                     highHighSpeedProfile);
293             checkProfile(lowHighSpeedProfile, null);
294             checkProfile(highHighSpeedProfile, null);
295         } else {
296             assertNull("high speed high quality profile shouldn't be supported if " +
297                     "low is unsupported ", highHighSpeedProfile);
298         }
299 
300         int[] specificProfileQualities = {CamcorderProfile.QUALITY_QCIF,
301                                           CamcorderProfile.QUALITY_QVGA,
302                                           CamcorderProfile.QUALITY_CIF,
303                                           CamcorderProfile.QUALITY_480P,
304                                           CamcorderProfile.QUALITY_720P,
305                                           CamcorderProfile.QUALITY_1080P,
306                                           CamcorderProfile.QUALITY_2160P};
307 
308         int[] specificTimeLapseProfileQualities = {CamcorderProfile.QUALITY_TIME_LAPSE_QCIF,
309                                                    CamcorderProfile.QUALITY_TIME_LAPSE_QVGA,
310                                                    CamcorderProfile.QUALITY_TIME_LAPSE_CIF,
311                                                    CamcorderProfile.QUALITY_TIME_LAPSE_480P,
312                                                    CamcorderProfile.QUALITY_TIME_LAPSE_720P,
313                                                    CamcorderProfile.QUALITY_TIME_LAPSE_1080P,
314                                                    CamcorderProfile.QUALITY_TIME_LAPSE_2160P};
315 
316         int[] specificHighSpeedProfileQualities = {CamcorderProfile.QUALITY_HIGH_SPEED_480P,
317                                                    CamcorderProfile.QUALITY_HIGH_SPEED_720P,
318                                                    CamcorderProfile.QUALITY_HIGH_SPEED_1080P,
319                                                    CamcorderProfile.QUALITY_HIGH_SPEED_2160P};
320 
321         CamcorderProfile lowProfile =
322                 getWithOptionalId(CamcorderProfile.QUALITY_LOW, cameraId);
323         CamcorderProfile highProfile =
324                 getWithOptionalId(CamcorderProfile.QUALITY_HIGH, cameraId);
325         CamcorderProfile lowTimeLapseProfile =
326                 getWithOptionalId(CamcorderProfile.QUALITY_TIME_LAPSE_LOW, cameraId);
327         CamcorderProfile highTimeLapseProfile =
328                 getWithOptionalId(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH, cameraId);
329         checkSpecificProfiles(cameraId, lowProfile, highProfile,
330                 specificProfileQualities, videoSizes);
331         checkSpecificProfiles(cameraId, lowTimeLapseProfile, highTimeLapseProfile,
332                 specificTimeLapseProfileQualities, null);
333         checkSpecificProfiles(cameraId, lowHighSpeedProfile, highHighSpeedProfile,
334                 specificHighSpeedProfileQualities, null);
335     }
336 
testGet()337     public void testGet() {
338         /*
339          * Device may not have rear camera for checkGet(-1).
340          * Checking PackageManager.FEATURE_CAMERA is included or not to decide the flow.
341          * Continue if the feature is included.
342          * Otherwise, exit test.
343          */
344         PackageManager pm = mContext.getPackageManager();
345         if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
346             return;
347         }
348         checkGet(-1);
349     }
350 
testGetWithId()351     public void testGetWithId() {
352         int nCamera = Camera.getNumberOfCameras();
353         for (int cameraId = 0; cameraId < nCamera; cameraId++) {
354             checkGet(cameraId);
355         }
356     }
357 
getSupportedVideoSizes(int cameraId)358     private List<Size> getSupportedVideoSizes(int cameraId) {
359         Camera camera = (cameraId == -1)? Camera.open(): Camera.open(cameraId);
360         Parameters parameters = camera.getParameters();
361         List<Size> videoSizes = parameters.getSupportedVideoSizes();
362         if (videoSizes == null) {
363             videoSizes = parameters.getSupportedPreviewSizes();
364             assertNotNull(videoSizes);
365         }
366         camera.release();
367         return videoSizes;
368     }
369 
isSizeSupported(int width, int height, List<Size> sizes)370     private boolean isSizeSupported(int width, int height, List<Size> sizes) {
371         if (sizes == null) return true;
372 
373         for (Size size: sizes) {
374             if (size.width == width && size.height == height) {
375                 return true;
376             }
377         }
378         Log.e(TAG, "Size (" + width + "x" + height + ") is not supported");
379         return false;
380     }
381 
isProfileMandatory(int quality)382     private boolean isProfileMandatory(int quality) {
383         return (quality == CamcorderProfile.QUALITY_LOW) ||
384                 (quality == CamcorderProfile.QUALITY_HIGH) ||
385                 (quality == CamcorderProfile.QUALITY_TIME_LAPSE_LOW) ||
386                 (quality == CamcorderProfile.QUALITY_TIME_LAPSE_HIGH);
387     }
388 }
389