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