使用场景:在会议平台上经常使用摄像头会议视频,市场上摄像头也是各式各样,2K、4K的都很多,还有一些网络摄像头。
遇到问题:插上摄像头,软件打开摄像头,画面显示花屏或者黑屏。
问题分析:通过抓取log分析,怀疑是摄像头分辨率跟上层软件设置的分辨率不匹配,也可能是分辨率过大导致内存溢出。
代码修改:
文件路径:vendor/mstar/hardware/camera/HAL/CameraHardware.cpp? ? 不一样的平台路径存在差异,本人使用的是Mstar平台。
1、在该文件下有个tryCameraSupportedSize()函数,该函数可获取当前摄像头所支持的分辨率。
/**
try camera supported size
*/
void CameraHardware::tryCameraSupportedSize() {
const char *ResolutionSize[] = {"1920x1080", "1280x720", "640x480", "352x288", "384x216", "320x240", "176x144"};
int count = 0;
int ImageFormat;
mCameraSupportedSize = new char[60];
mVideoSupportedSize = new char[60];
mVideoSupportedSize[0] = '\0';
mHighQualityPreviewSizeForVideo = new char[10];
for (int i = 0 ; i < sizeof(ResolutionSize)/sizeof(char *); i++) {
char *end;
int width = (int)strtol(ResolutionSize[i], &end, 10);
int height = (int)strtol(end+1, &end, 10);
//if (width == WIDTH_1080P && (!checkVideoSupported1080p() || !mJpegDecoder.is1080pSupport())) {
if (width == WIDTH_1080P && (!mJpegDecoder.is1080pSupport())) {
i++;
width = (int)strtol(ResolutionSize[i], &end, 10);
height = (int)strtol(end+1, &end, 10);
}
#if YUV_DATA_ONLY
ImageFormat = V4L2_PIX_FMT_YUYV;
#else
if (width >= WIDTH_720P) {
ImageFormat = V4L2_PIX_FMT_MJPEG;
} else {
ImageFormat = V4L2_PIX_FMT_YUYV;
}
#endif
if (!(mCamera->tryParameters(width, height, ImageFormat))) {
if (count == 0) {
mWidth = width;
mHeight = height;
if (width >= WIDTH_720P) {
m720pSupported = true;
}
sprintf(mHighQualityPreviewSizeForVideo, "%s", ResolutionSize[i]);
sprintf(mCameraSupportedSize, "%s", ResolutionSize[i]);
maxIndex = i; //add by jude for 用于获取最大分辨率
} else {
sprintf(mCameraSupportedSize, "%s,%s", mCameraSupportedSize, ResolutionSize[i]);
}
if (mVideoSupportedSize[0] == '\0') {
sprintf(mVideoSupportedSize, "%s", ResolutionSize[i]);
} else {
sprintf(mVideoSupportedSize, "%s,%s", mVideoSupportedSize, ResolutionSize[i]);
}
count++;
} else {
// always add video size 352x288 and 176x144 for CTS
if ((width == 352 && height == 288) || (width == 176 && height == 144)) {
if (mVideoSupportedSize[0] == '\0') {
sprintf(mVideoSupportedSize, "%s", ResolutionSize[i]);
} else {
sprintf(mVideoSupportedSize, "%s,%s", mVideoSupportedSize, ResolutionSize[i]);
}
}
}
}
ALOGI("---Camera Supported Size list: %s", mCameraSupportedSize);
//获取最大分辨率
if(maxIndex == 0){
maxWidth = 1920;
maxHeight = 1080;
}else if(maxIndex == 1){
maxWidth = 1280;
maxHeight = 720;
}else if(maxIndex == 2){
maxWidth = 640;
maxHeight = 480;
}else{
maxWidth = 1280;
maxHeight = 720;
}
tempWidth = maxWidth;
tempHeight = maxHeight;
ALOGI("---Camera maxWidth==: %d", maxWidth);
ALOGI("---Camera maxHeigh==: %d", maxHeight);
}
2、获取到最大分辨率后,在设置摄像头参数。CameraHardware.cpp文件中有个setParameters()函数,该函数直接设置camera各项参数。首先获取上层apk设置的预览窗大小getPreviewSize();其次通过之前获取的最大分辨率设置camera的mImageFormat;然后若上层设置的预览窗大小在camera的支持分辨率下,则设置预览窗大小为上层设置的;若不在camera支持范围,则强制设置为camera支持的分辨率。
/**
@brief Set the camera parameters.
@param[in] params Camera parameters to configure the camera
@return NO_ERROR
@todo Define error codes
*/
int CameraHardware::setParameters(const char* parameters) {
unsigned int i;
int width, height;
int min_fps, max_fps;
Vector<Size> sizes;
CameraParameters params;
String8 str_params(parameters);
params.unflatten(str_params);
status_t ret = NO_ERROR;
bool tempPreviewEnabled = mPreviewEnabled;
mPreviewEnabled = false;
Mutex::Autolock lock(mLock);
//Mutex::Autolock lock(mTakePictureLock);
params.getSupportedPreviewSizes(sizes);
params.getPreviewSize(&width, &height);
params.getPreviewFpsRange(&min_fps ,&max_fps);
if (min_fps < 0 || max_fps < 0)
return BAD_VALUE;
else if ((max_fps - min_fps) < 0)
return BAD_VALUE;
if (width < 0 || height < 0)
return BAD_VALUE;
if (strcmp("invalid",params.get(CameraParameters::KEY_FOCUS_MODE)) == 0)
return BAD_VALUE;
if (strcmp("invalid",params.get(CameraParameters::KEY_FLASH_MODE)) == 0)
return BAD_VALUE;
mParameters = params;
//Add some camera parameter logs for debug
//ALOGD("%s - CameraParameters::KEY_FLASH_MODE is %s", __FUNCTION__, mParameters.get(CameraParameters::KEY_FLASH_MODE));
//ALOGD("%s - CameraParameters::KEY_AUTO_EXPOSURE_LOCK is %s", __FUNCTION__, mParameters.get(CameraParameters::KEY_AUTO_EXPOSURE_LOCK));
width = mParameters.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH);
height = mParameters.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT);
mThumbnailWidth = width;
mThumbnailHeight = height;
mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, mThumbnailWidth);
mParameters.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, mThumbnailHeight);
//获取预览窗的分辨率
mParameters.getSupportedPreviewSizes(sizes);
mParameters.getPreviewSize(&width, &height);
//ALOGI("===getPreviewSize to %d, %d",width,height);
//通过最大分辨率设置camera的图像格式
if ((maxWidth >= WIDTH_720P) && (maxHeight >= HEIGHT_720P)) {
//ALOGE("===Is 720P , change V4L2_PIX_FMT_MJPEG ");
mImageFormat = V4L2_PIX_FMT_MJPEG;
} else {
mImageFormat = V4L2_PIX_FMT_YUYV;
}
if(width <= 640 && height <= 480){
tempWidth = 640;
tempHeight = 480;
}
//ALOGI("===MaxSize to %d, %d",maxWidth,maxHeight);
width = tempWidth;
height = tempHeight;
for (i = 0; i < sizes.size(); i++)
if (width == sizes[i].width && height == sizes[i].height)
break;
if (i == sizes.size()) {
params.getPreferredPreviewSizeForVideo(&width, &height);
if ((width <= 0) || (height <= 0))
mParameters.getPreviewSize(&width, &height);
ALOGI("Change preview size to %dx%d", width, height);
}
//Modify by jude for some camera can't work, 20200912
mParameters.setPreviewSize(width, height);
ALOGI("===setPreviewSize to %d, %d",width,height);
//end jude
if (mWidth == width && mHeight == height) {
mPreviewEnabled = tempPreviewEnabled;
return NO_ERROR;
}
//If change the camera preview size, mPreviewLock should be lock
Mutex::Autolock previewlock(mPreviewLock);
mPreviewEnabled = tempPreviewEnabled;
mWidth = width;
mHeight = height;
//Some Cameras cannot open/close so quickly
usleep(1000 * 100);
mCamera->StopStreaming();
mCamera->Uninit();
mCamera->Close();
if (mPreviewMemory)
mPreviewMemory->release(mPreviewMemory);
ret = mCamera->Open(mCameraDev);
if (ret == -1) {
ALOGE("Camera device open failed.");
}
ret = mCamera->setParameters(mWidth, mHeight, mImageFormat);
if (ret) {
ALOGE("Camera setParameters failed: %s", strerror(errno));
}
ret = mCamera->Init();
if (ret) {
ALOGE("Camera Init failed: %s", strerror(errno));
}
ret = mCamera->StartStreaming();
if (ret) {
ALOGE("Camera StartStreaming failed: %s", strerror(errno));
}
if (strcmp(mParameters.getPreviewFormat(), CameraParameters::PIXEL_FORMAT_YUV420SP) == 0 ) {
// YUV420SP
mPreviewFrameSize = mWidth * mHeight * 3 / 2;
} else if (strcmp(mParameters.getPreviewFormat(), CameraParameters::PIXEL_FORMAT_YUV420P) == 0) {
mPreviewFrameSize = calculateYUV420PSize(mWidth, mHeight);
} else {
// YUV422
mPreviewFrameSize = mWidth * mHeight * 2;
}
mPreviewMemory = mRequestMemory(-1, mPreviewFrameSize, 1, mCallbackCookie);
ALOGI("jude===mPreviewFrameSize to %d", mPreviewFrameSize);
ALOGI("jude===mPreviewMemory alloc %x", (unsigned int)mPreviewMemory);
mBounds.left = 0;
mBounds.top = 0;
mBounds.right = mWidth;
mBounds.bottom = mHeight;
return NO_ERROR;
}
|