前言
Camera架構本身內容就很多,因此在GMS中關於Camera的測試項很多,CTS/CTSV/ITS(ctsv中)/GTS/CTS-ON-GSI/VTS中都存在相關測試模塊。測試了與Camera相關的所有功能。
遇到問題該如何處理?
一時總結不全,不斷完善中
經驗
camera問題可能功能問題、也可能效果,大部分是配置問題。camera參數非常多而且很多之間存在相互關聯,某處參數修改可能影響與之關聯的參數。
簡單記錄下一般如何處理
根據報錯直接修改
有些報錯很明顯的,直接看報錯就能定位到問題,如果camera相關比較熟悉的話 直接修改。
如:
The static info key 'android.hotPixel.availableHotPixelModes' FAST and HIGH_QUALITY mode must both present or both not present
android.hotPixel.availableHotPixelModes這個配置中FAST和HIGH_QUALITY要同時存在或者不存在。
在mtk平台正確的類似下面:
CONFIG_METADATA_BEGIN(MTK_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES)
CONFIG_ENTRY_VALUE(MTK_HOT_PIXEL_MODE_FAST, MUINT8)
CONFIG_ENTRY_VALUE(MTK_HOT_PIXEL_MODE_HIGH_QUALITY, MUINT8)
CONFIG_METADATA_END()
查看相關代碼
CTS源碼在工程目錄下的cts/目錄中(不過這里的一般比較老,主要參考下面網址查看),很容易找到源碼(CTS-ON-GSI也基本可以參考CTS的代碼)。然后根據報錯,找到問題點。
由於工具總是不斷更新,有些地方可能和現有工程不一樣,參考下面地址找到對應代碼:
一個非常有用的網址(幾乎包含了android相關的各種、各個版本源碼):
https://android.googlesource.com/
如:
cts各個版本(Tags能直接看出來)源碼在:https://android.googlesource.com/platform/cts/
VTS:https://android.googlesource.com/platform/test/vts/
部分工具沒有源碼,一般能通過反編譯工具中的apk,基本也能看出邏輯,找出問題。
導出手機中camera參數
通過下面命令,可以導出手機中camera相關的參數。
查看文件,可以看出手機中的camera參數配置,檢查時候生效,是否正常和報錯一致。
adb shell dumpsys media.camera -v 1 > xxx.log
基本檢查確認
一些camera的基本檢查 配置。
16倍數
分辨率的配置一般是16的倍數,如720x1280,其中720 1280都是16的倍數。
基本支持的檢查,每個攝像頭最好單獨確認下
- 是否支持閃光燈。
- 是否支持自動對焦AF,若支持AF 通過預覽查看是否調好。
- 清楚camera的resolution,配置的分辨率長寬不要超過resolution的長寬。如gc5025 resolution是2592x1944,則分辨率最大為2592x1944。
- 預覽、拍照是否正常,顏色正常。
通過比較
- 同一平台某個攝像頭若過過GMS,基本可以直接拷貝過來使用(或跑前比較下)。
- 同一平台若某個攝像頭沒有過過,可以參考其他平台過過的該顆攝像頭,也可以參考過過的類似的攝像頭(如gc5035可以參考下gc5025)。
其他
幾個常量記錄
記錄幾個報錯中的常量,方便通過報錯直接了解, 而不需要再次從工程中查看后才知道。
profile ID
報錯類似:
Test failed for camera 0: Video size 1280x720 for profile ID 5 must be one of the camera device supported video size!
這里的profile ID 5表示什么呢?
就是某個分辨率對應的錄像質量等級,這里就是后攝1280x720對應的720P必須要支持。若缺少就添加上。
//AndroidQ: cts/ RecordingTest.java
private static final int[] mCamcorderProfileList = {
CamcorderProfile.QUALITY_HIGH, //1
CamcorderProfile.QUALITY_2160P,//8
CamcorderProfile.QUALITY_1080P,//6
CamcorderProfile.QUALITY_720P,//5
CamcorderProfile.QUALITY_480P,//4
CamcorderProfile.QUALITY_CIF,//3
CamcorderProfile.QUALITY_QCIF,//2
CamcorderProfile.QUALITY_QVGA,//7
CamcorderProfile.QUALITY_LOW,//0
};
//framework/base CamcorderProfile.java
public static final int QUALITY_HIGH = 1;
/**
* Quality level corresponding to the 2160p (3840x2160) resolution.
*/
public static final int QUALITY_2160P = 8;
/**
* Quality level corresponding to the 1080p (1920 x 1080) resolution.
* Note that the vertical resolution for 1080p can also be 1088,
* instead of 1080 (used by some vendors to avoid cropping during
* video playback).
*/
public static final int QUALITY_1080P = 6;
/**
* Quality level corresponding to the 720p (1280 x 720) resolution.
*/
public static final int QUALITY_720P = 5;
/**
* Quality level corresponding to the 480p (720 x 480) resolution.
* Note that the horizontal resolution for 480p can also be other
* values, such as 640 or 704, instead of 720.
*/
public static final int QUALITY_480P = 4;
/**
* Quality level corresponding to the cif (352 x 288) resolution.
*/
public static final int QUALITY_CIF = 3;
/**
* Quality level corresponding to the qcif (176 x 144) resolution.
*/
public static final int QUALITY_QCIF = 2;
/**
* Quality level corresponding to the QVGA (320x240) resolution.
*/
public static final int QUALITY_QVGA = 7;
/**
* Quality level corresponding to the lowest available resolution.
*/
public static final int QUALITY_LOW = 0;
format
報錯類似:
//framework/base ImageFormat.java
public static final int YUY2 = 0x14;//20
public static final int RAW_SENSOR = 0x20;//32
public static final int PRIVATE = 0x22;//34
public static final int YUV_420_888 = 0x23;//35
public static final int RAW_PRIVATE = 0x24;//36
public static final int YUV_422_888 = 0x27;//39
public static final int YUV_444_888 = 0x28;//40
public static final int JPEG = 0x100;//256
關於metadata中配置的格式定義(與上述報錯對應參考):
//framework/base StreamConfigurationMap.java
// from system/core/include/system/graphics.h
private static final int HAL_PIXEL_FORMAT_RAW16 = 0x20;//32
private static final int HAL_PIXEL_FORMAT_BLOB = 0x21;//33
private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;//34
private static final int HAL_PIXEL_FORMAT_YCbCr_420_888 = 0x23;//35
private static final int HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24;//36
private static final int HAL_PIXEL_FORMAT_RAW10 = 0x25;//37
private static final int HAL_PIXEL_FORMAT_RAW12 = 0x26;//38
static int imageFormatToInternal(int format) {
switch (format) {
case ImageFormat.JPEG:
case ImageFormat.DEPTH_POINT_CLOUD:
case ImageFormat.DEPTH_JPEG:
case ImageFormat.HEIC:
return HAL_PIXEL_FORMAT_BLOB;
case ImageFormat.DEPTH16:
return HAL_PIXEL_FORMAT_Y16;
case ImageFormat.RAW_DEPTH:
return HAL_PIXEL_FORMAT_RAW16;
default:
return format;
}
}
public static int imageFormatToPublic(int format) {
switch (format) {
case HAL_PIXEL_FORMAT_BLOB:
return ImageFormat.JPEG;
case ImageFormat.JPEG:
throw new IllegalArgumentException(
"ImageFormat.JPEG is an unknown internal format");
default:
return format;
}
}
幾個camera常見報錯記錄
android.hardware.camera2.cts.RecordingTest#xxxxx
報錯類似:
Camera 0: Video duration doesn't match: recorded 2564.000000ms, expected [4640.000000,6960.000488]ms.
一般解決:
第一種修改media profiles對應Camera,對應fail項size的frameRate和drvier輸出的幀率一致;
第二種修改drvier對應video size的幀率和media profiles一致。
另:media profiles的文件在手機中的位置(可以直接修改push驗證,也可以確認修改是否正確生效):
/vendor/etc/media_profiles_V1_0.xml
看下源碼:
下面以android.hardware.camera2.cts.RecordingTest#testBasicRecording為例:
//工程中的源碼,應該是10_R1的
public void testBasicRecording() throws Exception {
doBasicRecording(/*useVideoStab*/false);
}
private void doBasicRecording(boolean useVideoStab) throws Exception {
doBasicRecording(useVideoStab, false);
}
private void doBasicRecording(boolean useVideoStab, boolean useIntermediateSurface)
throws Exception {
for (int i = 0; i < mCameraIds.length; i++) {
......
basicRecordingTestByCamera(mCamcorderProfileList, useVideoStab,
useIntermediateSurface);
......
}
}
private void basicRecordingTestByCamera(int[] camcorderProfileList, boolean useVideoStab,
boolean useIntermediateSurface) throws Exception {
......
for (int profileId : camcorderProfileList) {
......
float frameDurationMs = 1000.0f / profile.videoFrameRate;//注意這里
float durationMs = 0.f;
if (useIntermediateSurface) {
durationMs = mQueuer.getQueuedCount() * frameDurationMs;
} else {
durationMs = resultListener.getTotalNumFrames() * frameDurationMs;//走這,here
}
......
// Validation.
validateRecording(videoSz, durationMs, frameDurationMs, FRMDRP_RATE_TOLERANCE);
}
......
}
private void validateRecording(
Size sz, float expectedDurationMs, float expectedFrameDurationMs,
float frameDropTolerance) throws Exception {
validateRecording(sz,
expectedDurationMs, /*fixed FPS recording*/0.f,
expectedFrameDurationMs, /*fixed FPS recording*/0.f,
frameDropTolerance);
}
private void validateRecording(
Size sz,
float expectedDurationMinMs, // Min duration (maxFps)
float expectedDurationMaxMs, // Max duration (minFps). 0.f for fixed fps recording
float expectedFrameDurationMinMs, // maxFps
float expectedFrameDurationMaxMs, // minFps. 0.f for fixed fps recording
float frameDropTolerance) throws Exception {
......
if (expectedDurationMaxMs == 0.f) {
expectedDurationMaxMs = expectedDurationMinMs;
}
MediaExtractor extractor = new MediaExtractor();
try {
......
// TODO: Don't skip this one for video snapshot on LEGACY
assertTrue(String.format(
"Camera %s: Video duration doesn't match: recorded %fms, expected [%f,%f]ms.",
mCamera.getId(), duration,
expectedDurationMinMs * (1.f - DURATION_MARGIN),
expectedDurationMaxMs * (1.f + DURATION_MARGIN)),
duration > expectedDurationMinMs * (1.f - DURATION_MARGIN) &&
duration < expectedDurationMaxMs * (1.f + DURATION_MARGIN));
......
} finally {
......
}
}
