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 import android.content.pm.PackageManager;
20 import android.hardware.Camera;
21 import android.hardware.Camera.Parameters;
22 import android.hardware.Camera.Size;
23 import android.hardware.cts.helpers.CameraUtils;
24 import android.media.CamcorderProfile;
25 import android.media.EncoderProfiles;
26 import android.media.MediaCodecInfo;
27 import android.media.MediaFormat;
28 import android.media.MediaRecorder;
29 import android.test.AndroidTestCase;
30 import android.util.Log;
31 
32 import java.util.Arrays;
33 import java.util.List;
34 
35 @NonMediaMainlineTest
36 public class CamcorderProfileTest extends AndroidTestCase {
37 
38     private static final String TAG = "CamcorderProfileTest";
39     private static final int MIN_HIGH_SPEED_FPS = 100;
40     private static final Integer[] ALL_SUPPORTED_QUALITIES = {
41         CamcorderProfile.QUALITY_LOW,
42         CamcorderProfile.QUALITY_HIGH,
43         CamcorderProfile.QUALITY_QCIF,
44         CamcorderProfile.QUALITY_CIF,
45         CamcorderProfile.QUALITY_480P,
46         CamcorderProfile.QUALITY_720P,
47         CamcorderProfile.QUALITY_1080P,
48         CamcorderProfile.QUALITY_QVGA,
49         CamcorderProfile.QUALITY_2160P,
50         CamcorderProfile.QUALITY_VGA,
51         CamcorderProfile.QUALITY_4KDCI,
52         CamcorderProfile.QUALITY_QHD,
53         CamcorderProfile.QUALITY_2K,
54         CamcorderProfile.QUALITY_8KUHD,
55 
56         CamcorderProfile.QUALITY_TIME_LAPSE_LOW,
57         CamcorderProfile.QUALITY_TIME_LAPSE_HIGH,
58         CamcorderProfile.QUALITY_TIME_LAPSE_QCIF,
59         CamcorderProfile.QUALITY_TIME_LAPSE_CIF,
60         CamcorderProfile.QUALITY_TIME_LAPSE_480P,
61         CamcorderProfile.QUALITY_TIME_LAPSE_720P,
62         CamcorderProfile.QUALITY_TIME_LAPSE_1080P,
63         CamcorderProfile.QUALITY_TIME_LAPSE_QVGA,
64         CamcorderProfile.QUALITY_TIME_LAPSE_2160P,
65         CamcorderProfile.QUALITY_TIME_LAPSE_VGA,
66         CamcorderProfile.QUALITY_TIME_LAPSE_4KDCI,
67         CamcorderProfile.QUALITY_TIME_LAPSE_QHD,
68         CamcorderProfile.QUALITY_TIME_LAPSE_2K,
69         CamcorderProfile.QUALITY_TIME_LAPSE_8KUHD,
70 
71         CamcorderProfile.QUALITY_HIGH_SPEED_LOW,
72         CamcorderProfile.QUALITY_HIGH_SPEED_HIGH,
73         CamcorderProfile.QUALITY_HIGH_SPEED_480P,
74         CamcorderProfile.QUALITY_HIGH_SPEED_720P,
75         CamcorderProfile.QUALITY_HIGH_SPEED_1080P,
76         CamcorderProfile.QUALITY_HIGH_SPEED_2160P,
77         CamcorderProfile.QUALITY_HIGH_SPEED_CIF,
78         CamcorderProfile.QUALITY_HIGH_SPEED_VGA,
79         CamcorderProfile.QUALITY_HIGH_SPEED_4KDCI,
80     };
81     private static final int LAST_QUALITY = CamcorderProfile.QUALITY_8KUHD;
82     private static final int LAST_TIMELAPSE_QUALITY = CamcorderProfile.QUALITY_TIME_LAPSE_8KUHD;
83     private static final int LAST_HIGH_SPEED_QUALITY = CamcorderProfile.QUALITY_HIGH_SPEED_4KDCI;
84     private static final Integer[] UNKNOWN_QUALITIES = {
85         LAST_QUALITY + 1, // Unknown normal profile quality
86         LAST_TIMELAPSE_QUALITY + 1, // Unknown timelapse profile quality
87         LAST_HIGH_SPEED_QUALITY + 1 // Unknown high speed timelapse profile quality
88     };
89 
90     // Uses get without id if cameraId == -1 and get with id otherwise.
getWithOptionalId(int quality, int cameraId)91     private CamcorderProfile getWithOptionalId(int quality, int cameraId) {
92         if (cameraId == -1) {
93             return CamcorderProfile.get(quality);
94         } else {
95             return CamcorderProfile.get(cameraId, quality);
96         }
97     }
98 
checkProfile(CamcorderProfile profile, List<Size> videoSizes)99     private void checkProfile(CamcorderProfile profile, List<Size> videoSizes) {
100         Log.v(TAG, String.format("profile: duration=%d, quality=%d, " +
101             "fileFormat=%d, videoCodec=%d, videoBitRate=%d, videoFrameRate=%d, " +
102             "videoFrameWidth=%d, videoFrameHeight=%d, audioCodec=%d, " +
103             "audioBitRate=%d, audioSampleRate=%d, audioChannels=%d",
104             profile.duration,
105             profile.quality,
106             profile.fileFormat,
107             profile.videoCodec,
108             profile.videoBitRate,
109             profile.videoFrameRate,
110             profile.videoFrameWidth,
111             profile.videoFrameHeight,
112             profile.audioCodec,
113             profile.audioBitRate,
114             profile.audioSampleRate,
115             profile.audioChannels));
116         assertTrue(profile.duration > 0);
117         assertTrue(Arrays.asList(ALL_SUPPORTED_QUALITIES).contains(profile.quality));
118         assertTrue(profile.videoBitRate > 0);
119         assertTrue(profile.videoFrameRate > 0);
120         assertTrue(profile.videoFrameWidth > 0);
121         assertTrue(profile.videoFrameHeight > 0);
122         assertTrue(profile.audioBitRate > 0);
123         assertTrue(profile.audioSampleRate > 0);
124         assertTrue(profile.audioChannels > 0);
125         assertTrue(isSizeSupported(profile.videoFrameWidth,
126                                    profile.videoFrameHeight,
127                                    videoSizes));
128     }
129 
checkAllProfiles(EncoderProfiles allProfiles, CamcorderProfile profile, List<Size> videoSizes)130     private void checkAllProfiles(EncoderProfiles allProfiles, CamcorderProfile profile,
131                                   List<Size> videoSizes) {
132         Log.v(TAG, String.format("profile: duration=%d, quality=%d, " +
133             "fileFormat=%d, videoCodec=%d, videoBitRate=%d, videoFrameRate=%d, " +
134             "videoFrameWidth=%d, videoFrameHeight=%d, audioCodec=%d, " +
135             "audioBitRate=%d, audioSampleRate=%d, audioChannels=%d",
136             profile.duration,
137             profile.quality,
138             profile.fileFormat,
139             profile.videoCodec,
140             profile.videoBitRate,
141             profile.videoFrameRate,
142             profile.videoFrameWidth,
143             profile.videoFrameHeight,
144             profile.audioCodec,
145             profile.audioBitRate,
146             profile.audioSampleRate,
147             profile.audioChannels));
148         // generic fields must match the corresponding CamcorderProfile
149         assertEquals(profile.duration, allProfiles.getDefaultDurationSeconds());
150         assertEquals(profile.fileFormat, allProfiles.getRecommendedFileFormat());
151         boolean first = true;
152         for (EncoderProfiles.VideoProfile videoProfile : allProfiles.getVideoProfiles()) {
153             if (first) {
154                 // the first profile must be the default profile which must match
155                 // the corresponding CamcorderProfile
156                 assertEquals(profile.videoCodec, videoProfile.getCodec());
157                 assertEquals(profile.videoBitRate, videoProfile.getBitrate());
158                 assertEquals(profile.videoFrameRate, videoProfile.getFrameRate());
159                 first = false;
160             }
161             // all profiles must be the same size
162             assertEquals(profile.videoFrameWidth, videoProfile.getWidth());
163             assertEquals(profile.videoFrameHeight, videoProfile.getHeight());
164             assertTrue(videoProfile.getMediaType() != null);
165             switch (videoProfile.getCodec()) {
166               // don't validate profile for regular codecs as vendors may use vendor specific profile
167             case MediaRecorder.VideoEncoder.H263:
168                 assertEquals(MediaFormat.MIMETYPE_VIDEO_H263, videoProfile.getMediaType());
169                 break;
170             case MediaRecorder.VideoEncoder.H264:
171                 assertEquals(MediaFormat.MIMETYPE_VIDEO_AVC, videoProfile.getMediaType());
172                 break;
173             case MediaRecorder.VideoEncoder.MPEG_4_SP:
174                 assertEquals(MediaFormat.MIMETYPE_VIDEO_MPEG4, videoProfile.getMediaType());
175                 break;
176             case MediaRecorder.VideoEncoder.VP8:
177                 assertEquals(MediaFormat.MIMETYPE_VIDEO_VP8, videoProfile.getMediaType());
178                 break;
179             case MediaRecorder.VideoEncoder.HEVC:
180                   assertEquals(MediaFormat.MIMETYPE_VIDEO_HEVC, videoProfile.getMediaType());
181                   break;
182             }
183             // Cannot validate profile as vendors may use vendor specific profile. Just read it.
184             int codecProfile = videoProfile.getProfile();
185         }
186         first = true;
187         for (EncoderProfiles.AudioProfile audioProfile : allProfiles.getAudioProfiles()) {
188             if (first) {
189                 // the first profile must be the default profile which must match
190                 // the corresponding CamcorderProfile
191                 assertEquals(profile.audioCodec, audioProfile.getCodec());
192                 assertEquals(profile.audioBitRate, audioProfile.getBitrate());
193                 assertEquals(profile.audioSampleRate, audioProfile.getSampleRate());
194                 assertEquals(profile.audioChannels, audioProfile.getChannels());
195                 first = false;
196             }
197             assertTrue(audioProfile.getMediaType() != null);
198             switch (audioProfile.getCodec()) {
199             // don't validate profile for regular codecs as vendors may use vendor specific profile
200             case MediaRecorder.AudioEncoder.AMR_NB:
201                 assertEquals(MediaFormat.MIMETYPE_AUDIO_AMR_NB, audioProfile.getMediaType());
202                 break;
203             case MediaRecorder.AudioEncoder.AMR_WB:
204                 assertEquals(MediaFormat.MIMETYPE_AUDIO_AMR_WB, audioProfile.getMediaType());
205                 break;
206             case MediaRecorder.AudioEncoder.AAC:
207                 assertEquals(MediaFormat.MIMETYPE_AUDIO_AAC, audioProfile.getMediaType());
208                 break;
209             case MediaRecorder.AudioEncoder.HE_AAC:
210                 assertEquals(MediaFormat.MIMETYPE_AUDIO_AAC, audioProfile.getMediaType());
211                 assertEquals(MediaCodecInfo.CodecProfileLevel.AACObjectHE,
212                              audioProfile.getProfile());
213                 break;
214             case MediaRecorder.AudioEncoder.AAC_ELD:
215                 assertEquals(MediaFormat.MIMETYPE_AUDIO_AAC, audioProfile.getMediaType());
216                 assertEquals(MediaCodecInfo.CodecProfileLevel.AACObjectELD,
217                              audioProfile.getProfile());
218                 break;
219             case MediaRecorder.AudioEncoder.VORBIS:
220                 assertEquals(MediaFormat.MIMETYPE_AUDIO_VORBIS, audioProfile.getMediaType());
221                 break;
222             case MediaRecorder.AudioEncoder.OPUS:
223                 assertEquals(MediaFormat.MIMETYPE_AUDIO_OPUS, audioProfile.getMediaType());
224                 break;
225             default:
226                 // there may be some extended profiles we don't know about and that's OK
227                 break;
228             }
229         }
230     }
231 
assertProfileEquals(CamcorderProfile expectedProfile, CamcorderProfile actualProfile)232     private void assertProfileEquals(CamcorderProfile expectedProfile,
233             CamcorderProfile actualProfile) {
234         assertEquals(expectedProfile.duration, actualProfile.duration);
235         assertEquals(expectedProfile.fileFormat, actualProfile.fileFormat);
236         assertEquals(expectedProfile.videoCodec, actualProfile.videoCodec);
237         assertEquals(expectedProfile.videoBitRate, actualProfile.videoBitRate);
238         assertEquals(expectedProfile.videoFrameRate, actualProfile.videoFrameRate);
239         assertEquals(expectedProfile.videoFrameWidth, actualProfile.videoFrameWidth);
240         assertEquals(expectedProfile.videoFrameHeight, actualProfile.videoFrameHeight);
241         assertEquals(expectedProfile.audioCodec, actualProfile.audioCodec);
242         assertEquals(expectedProfile.audioBitRate, actualProfile.audioBitRate);
243         assertEquals(expectedProfile.audioSampleRate, actualProfile.audioSampleRate);
244         assertEquals(expectedProfile.audioChannels, actualProfile.audioChannels);
245     }
246 
checkSpecificProfileDimensions(CamcorderProfile profile, int quality)247     private void checkSpecificProfileDimensions(CamcorderProfile profile, int quality) {
248         Log.v(TAG, String.format("specific profile: quality=%d, width = %d, height = %d",
249                     profile.quality, profile.videoFrameWidth, profile.videoFrameHeight));
250 
251         switch (quality) {
252             case CamcorderProfile.QUALITY_QCIF:
253             case CamcorderProfile.QUALITY_TIME_LAPSE_QCIF:
254                 assertEquals(176, profile.videoFrameWidth);
255                 assertEquals(144, profile.videoFrameHeight);
256                 break;
257 
258             case CamcorderProfile.QUALITY_CIF:
259             case CamcorderProfile.QUALITY_TIME_LAPSE_CIF:
260                 assertEquals(352, profile.videoFrameWidth);
261                 assertEquals(288, profile.videoFrameHeight);
262                 break;
263 
264             case CamcorderProfile.QUALITY_480P:
265             case CamcorderProfile.QUALITY_TIME_LAPSE_480P:
266                 assertTrue(720 == profile.videoFrameWidth ||  // SMPTE 293M/ITU-R Rec. 601
267                            640 == profile.videoFrameWidth ||  // ATSC/NTSC (square sampling)
268                            704 == profile.videoFrameWidth);   // ATSC/NTSC (non-square sampling)
269                 assertEquals(480, profile.videoFrameHeight);
270                 break;
271 
272             case CamcorderProfile.QUALITY_720P:
273             case CamcorderProfile.QUALITY_TIME_LAPSE_720P:
274                 assertEquals(1280, profile.videoFrameWidth);
275                 assertEquals(720, profile.videoFrameHeight);
276                 break;
277 
278             case CamcorderProfile.QUALITY_1080P:
279             case CamcorderProfile.QUALITY_TIME_LAPSE_1080P:
280                 // 1080p could be either 1920x1088 or 1920x1080.
281                 assertEquals(1920, profile.videoFrameWidth);
282                 assertTrue(1088 == profile.videoFrameHeight ||
283                            1080 == profile.videoFrameHeight);
284                 break;
285             case CamcorderProfile.QUALITY_2K:
286             case CamcorderProfile.QUALITY_TIME_LAPSE_2K:
287                 // 2K could be either 2048x1088 or 2048x1080
288                 assertEquals(2048, profile.videoFrameWidth);
289                 assertTrue(1088 == profile.videoFrameHeight ||
290                            1080 == profile.videoFrameHeight);
291                 break;
292             case CamcorderProfile.QUALITY_QHD:
293             case CamcorderProfile.QUALITY_TIME_LAPSE_QHD:
294                 assertEquals(2560, profile.videoFrameWidth);
295                 assertEquals(1440, profile.videoFrameHeight);
296                 break;
297             case CamcorderProfile.QUALITY_2160P:
298             case CamcorderProfile.QUALITY_TIME_LAPSE_2160P:
299                 assertEquals(3840, profile.videoFrameWidth);
300                 assertEquals(2160, profile.videoFrameHeight);
301                 break;
302             case CamcorderProfile.QUALITY_HIGH_SPEED_480P:
303                 assertTrue(720 == profile.videoFrameWidth ||  // SMPTE 293M/ITU-R Rec. 601
304                 640 == profile.videoFrameWidth ||  // ATSC/NTSC (square sampling)
305                 704 == profile.videoFrameWidth);   // ATSC/NTSC (non-square sampling)
306                 assertEquals(480, profile.videoFrameHeight);
307                 assertTrue(profile.videoFrameRate >= MIN_HIGH_SPEED_FPS);
308                 break;
309             case CamcorderProfile.QUALITY_HIGH_SPEED_720P:
310                 assertEquals(1280, profile.videoFrameWidth);
311                 assertEquals(720, profile.videoFrameHeight);
312                 assertTrue(profile.videoFrameRate >= MIN_HIGH_SPEED_FPS);
313                 break;
314             case CamcorderProfile.QUALITY_HIGH_SPEED_1080P:
315                 // 1080p could be either 1920x1088 or 1920x1080.
316                 assertEquals(1920, profile.videoFrameWidth);
317                 assertTrue(1088 == profile.videoFrameHeight ||
318                            1080 == profile.videoFrameHeight);
319                 assertTrue(profile.videoFrameRate >= MIN_HIGH_SPEED_FPS);
320                 break;
321         }
322     }
323 
324     // Checks if the existing specific profiles have the correct dimensions.
325     // Also checks that the mimimum quality specific profile matches the low profile and
326     // similarly that the maximum quality specific profile matches the high profile.
checkSpecificProfiles( int cameraId, CamcorderProfile low, CamcorderProfile high, int[] specificQualities, List<Size> videoSizes)327     private void checkSpecificProfiles(
328             int cameraId,
329             CamcorderProfile low,
330             CamcorderProfile high,
331             int[] specificQualities,
332             List<Size> videoSizes) {
333 
334         // For high speed levels, low and high quality are optional,skip the test if
335         // they are missing.
336         if (low == null && high == null) {
337             // No profile should be available if low and high are unavailable.
338             for (int quality : specificQualities) {
339                 assertFalse(CamcorderProfile.hasProfile(cameraId, quality));
340             }
341             return;
342         }
343 
344         CamcorderProfile minProfile = null;
345         CamcorderProfile maxProfile = null;
346 
347         for (int i = 0; i < specificQualities.length; i++) {
348             int quality = specificQualities[i];
349             if ((cameraId != -1 && CamcorderProfile.hasProfile(cameraId, quality)) ||
350                 (cameraId == -1 && CamcorderProfile.hasProfile(quality))) {
351                 CamcorderProfile profile = getWithOptionalId(quality, cameraId);
352                 checkSpecificProfileDimensions(profile, quality);
353 
354                 assertTrue(isSizeSupported(profile.videoFrameWidth,
355                                            profile.videoFrameHeight,
356                                            videoSizes));
357 
358                 if (minProfile == null) {
359                     minProfile = profile;
360                 }
361                 maxProfile = profile;
362             }
363         }
364 
365         assertNotNull(minProfile);
366         assertNotNull(maxProfile);
367 
368         Log.v(TAG, String.format("min profile: quality=%d, width = %d, height = %d",
369                     minProfile.quality, minProfile.videoFrameWidth, minProfile.videoFrameHeight));
370         Log.v(TAG, String.format("max profile: quality=%d, width = %d, height = %d",
371                     maxProfile.quality, maxProfile.videoFrameWidth, maxProfile.videoFrameHeight));
372 
373         assertProfileEquals(low, minProfile);
374         assertProfileEquals(high, maxProfile);
375 
376     }
377 
checkGet(int cameraId)378     private void checkGet(int cameraId) {
379         Log.v(TAG, (cameraId == -1)
380                    ? "Checking get without id"
381                    : "Checking get with id = " + cameraId);
382 
383         final List<Size> videoSizes = getSupportedVideoSizes(cameraId);
384 
385         /**
386          * Check all possible supported profiles: get profile should work, and the profile
387          * should be sane. Note that, timelapse and high speed video sizes may not be listed
388          * as supported video sizes from camera, skip the size check.
389          */
390         for (Integer quality : ALL_SUPPORTED_QUALITIES) {
391             if (CamcorderProfile.hasProfile(cameraId, quality) || isProfileMandatory(quality)) {
392                 List<Size> videoSizesToCheck = null;
393                 if (quality >= CamcorderProfile.QUALITY_LOW &&
394                                 quality <= CamcorderProfile.QUALITY_2K) {
395                     videoSizesToCheck = videoSizes;
396                 }
397                 CamcorderProfile profile = getWithOptionalId(quality, cameraId);
398                 checkProfile(profile, videoSizesToCheck);
399                 if (cameraId >= 0) {
400                     EncoderProfiles allProfiles =
401                         CamcorderProfile.getAll(String.valueOf(cameraId), quality);
402                     checkAllProfiles(allProfiles, profile, videoSizesToCheck);
403                 }
404             }
405         }
406 
407         /**
408          * Check unknown profiles: hasProfile() should return false.
409          */
410         for (Integer quality : UNKNOWN_QUALITIES) {
411             assertFalse("Unknown profile quality " + quality + " shouldn't be supported by camera "
412                     + cameraId, CamcorderProfile.hasProfile(cameraId, quality));
413         }
414 
415         // High speed low and high profile are optional,
416         // but they should be both present or missing.
417         CamcorderProfile lowHighSpeedProfile = null;
418         CamcorderProfile highHighSpeedProfile = null;
419         if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_HIGH_SPEED_LOW)) {
420             lowHighSpeedProfile =
421                     getWithOptionalId(CamcorderProfile.QUALITY_HIGH_SPEED_LOW, cameraId);
422         }
423         if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_HIGH_SPEED_HIGH)) {
424             highHighSpeedProfile =
425                     getWithOptionalId(CamcorderProfile.QUALITY_HIGH_SPEED_HIGH, cameraId);
426         }
427         if (lowHighSpeedProfile != null) {
428             assertNotNull("high speed high quality profile should be supported if low" +
429                     " is supported ",
430                     highHighSpeedProfile);
431             checkProfile(lowHighSpeedProfile, null);
432             checkProfile(highHighSpeedProfile, null);
433         } else {
434             assertNull("high speed high quality profile shouldn't be supported if " +
435                     "low is unsupported ", highHighSpeedProfile);
436         }
437 
438         int[] specificProfileQualities = {CamcorderProfile.QUALITY_QCIF,
439                                           CamcorderProfile.QUALITY_QVGA,
440                                           CamcorderProfile.QUALITY_CIF,
441                                           CamcorderProfile.QUALITY_480P,
442                                           CamcorderProfile.QUALITY_720P,
443                                           CamcorderProfile.QUALITY_1080P,
444                                           CamcorderProfile.QUALITY_2K,
445                                           CamcorderProfile.QUALITY_QHD,
446                                           CamcorderProfile.QUALITY_2160P};
447 
448         int[] specificTimeLapseProfileQualities = {CamcorderProfile.QUALITY_TIME_LAPSE_QCIF,
449                                                    CamcorderProfile.QUALITY_TIME_LAPSE_QVGA,
450                                                    CamcorderProfile.QUALITY_TIME_LAPSE_CIF,
451                                                    CamcorderProfile.QUALITY_TIME_LAPSE_480P,
452                                                    CamcorderProfile.QUALITY_TIME_LAPSE_720P,
453                                                    CamcorderProfile.QUALITY_TIME_LAPSE_1080P,
454                                                    CamcorderProfile.QUALITY_TIME_LAPSE_2K,
455                                                    CamcorderProfile.QUALITY_TIME_LAPSE_QHD,
456                                                    CamcorderProfile.QUALITY_TIME_LAPSE_2160P};
457 
458         int[] specificHighSpeedProfileQualities = {CamcorderProfile.QUALITY_HIGH_SPEED_480P,
459                                                    CamcorderProfile.QUALITY_HIGH_SPEED_720P,
460                                                    CamcorderProfile.QUALITY_HIGH_SPEED_1080P,
461                                                    CamcorderProfile.QUALITY_HIGH_SPEED_2160P};
462 
463         CamcorderProfile lowProfile =
464                 getWithOptionalId(CamcorderProfile.QUALITY_LOW, cameraId);
465         CamcorderProfile highProfile =
466                 getWithOptionalId(CamcorderProfile.QUALITY_HIGH, cameraId);
467         CamcorderProfile lowTimeLapseProfile =
468                 getWithOptionalId(CamcorderProfile.QUALITY_TIME_LAPSE_LOW, cameraId);
469         CamcorderProfile highTimeLapseProfile =
470                 getWithOptionalId(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH, cameraId);
471         checkSpecificProfiles(cameraId, lowProfile, highProfile,
472                 specificProfileQualities, videoSizes);
473         checkSpecificProfiles(cameraId, lowTimeLapseProfile, highTimeLapseProfile,
474                 specificTimeLapseProfileQualities, null);
475         checkSpecificProfiles(cameraId, lowHighSpeedProfile, highHighSpeedProfile,
476                 specificHighSpeedProfileQualities, null);
477     }
478 
testGet()479     public void testGet() {
480         /*
481          * Device may not have rear camera for checkGet(-1).
482          * Checking PackageManager.FEATURE_CAMERA is included or not to decide the flow.
483          * Continue if the feature is included.
484          * Otherwise, exit test.
485          */
486         PackageManager pm = mContext.getPackageManager();
487         if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
488             return;
489         }
490         checkGet(-1);
491     }
492 
testGetWithId()493     public void testGetWithId() {
494         int nCamera = Camera.getNumberOfCameras();
495         for (int cameraId = 0; cameraId < nCamera; cameraId++) {
496             boolean isExternal = false;
497             try {
498                 isExternal = CameraUtils.isExternal(mContext, cameraId);
499             } catch (Exception e) {
500                 Log.e(TAG, "Unable to query external camera: " + e);
501             }
502 
503             if (!isExternal) {
504                 checkGet(cameraId);
505             }
506         }
507     }
508 
getSupportedVideoSizes(int cameraId)509     private List<Size> getSupportedVideoSizes(int cameraId) {
510         Camera camera = (cameraId == -1)? Camera.open(): Camera.open(cameraId);
511         Parameters parameters = camera.getParameters();
512         List<Size> videoSizes = parameters.getSupportedVideoSizes();
513         if (videoSizes == null) {
514             videoSizes = parameters.getSupportedPreviewSizes();
515             assertNotNull(videoSizes);
516         }
517         camera.release();
518         return videoSizes;
519     }
520 
isSizeSupported(int width, int height, List<Size> sizes)521     private boolean isSizeSupported(int width, int height, List<Size> sizes) {
522         if (sizes == null) return true;
523 
524         for (Size size: sizes) {
525             if (size.width == width && size.height == height) {
526                 return true;
527             }
528         }
529         Log.e(TAG, "Size (" + width + "x" + height + ") is not supported");
530         return false;
531     }
532 
isProfileMandatory(int quality)533     private boolean isProfileMandatory(int quality) {
534         return (quality == CamcorderProfile.QUALITY_LOW) ||
535                 (quality == CamcorderProfile.QUALITY_HIGH) ||
536                 (quality == CamcorderProfile.QUALITY_TIME_LAPSE_LOW) ||
537                 (quality == CamcorderProfile.QUALITY_TIME_LAPSE_HIGH);
538     }
539 }
540