MTK Camera configureStream 流程
0、前文回顾
前文已经简单说明CameraHalService服务、Serarch Sensor的过程、以及open、close相机的动作。
强力建议熟读Camera3.h Startup and general expected operation sequence
https://www.androidos.net.cn/android/10.0.0_r6/xref/hardware/libhardware/include/hardware/camera3.h
1、camera configureStreams 流程
1.1 相机api简述
as we all know Android Camera API的 步骤
(1)、监听和枚举相机设备
get_number_of_cameras、get_camera_characteristic
(2)、打开设备并连接监听器
connect、open
(3)、配\置目标使用情形的输出(如static 、capture、video等)
configure_stream
(4)、为目标使用情形创建请求 (5)捕获/重复请求和连拍
process_capture_request
(6) 、接受结果metadata和图片数据
proces_capture_result
(7)、切换使用情形时,返回第三步
1.2 原文阅读
* 4. The framework calls camera3_device_t->ops->configure_streams() with a list * of input/output streams to the HAL device.
简单翻译-->
framework调用结构体camera_device方法ops调用结构体camera3_device_ops的configure_streams方法配流,camera3_device_t-> ops-> configure_streams(),并把input stream&output stream 的列表作为参数送到Hal层。
1.3 结构体
hardware/libhardware/include/hardware/camera3.h
camera3_device_ops_t 映射函数指针操作: hardware/libhardware/modules/camera/3_0/Camera.cpp
frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp
status_t Camera3Device::configureStreamsLocked(int operatingMode,
const CameraMetadata& sessionParams, bool notifyRequestThread) {
// Start configuring the streams
ALOGV("%s: Camera %s: Starting stream configuration", __FUNCTION__, mId.string());略...
config.streams = streams.editArray();
// Do the HAL configuration; will potentially touch stream
// max_buffers, usage, and priv fields, as well as data_space and format
// fields for IMPLEMENTATION_DEFINED formats.const camera_metadata_t *sessionBuffer = sessionParams.getAndLock();
res = mInterface->configureStreams(sessionBuffer, &config, bufferSizes);
sessionParams.unlock(sessionBuffer);if (res == BAD_VALUE) {
// HAL rejected this set of streams as unsupported, clean up config
// attempt and return to unconfigured state
CLOGE("Set of requested inputs/outputs not supported by HAL");
cancelStreamsConfigurationLocked();
return BAD_VALUE;
} else if (res != OK) {
// Some other kind of error from configure_streams - this is not
// expected
SET_ERR_L("Unable to configure streams with HAL: %s (%d)",
strerror(-res), res);
return res;
}// Finish all stream configuration immediately.
// TODO: Try to relax this later back to lazy completion, which should be
// fasterif (mInputStream != NULL && mInputStream->isConfiguring()) {
bool streamReConfigured = false;
res = mInputStream->finishConfiguration(&streamReConfigured);
if (res != OK) {
CLOGE("Can't finish configuring input stream %d: %s (%d)",
mInputStream->getId(), strerror(-res), res);
cancelStreamsConfigurationLocked();
if ((res == NO_INIT || res == DEAD_OBJECT) && mInputStream->isAbandoned()) {
return DEAD_OBJECT;
}
return BAD_VALUE;
}
if (streamReConfigured) {
mInterface->onStreamReConfigured(mInputStream->getId());
}
}for (size_t i = 0; i < mOutputStreams.size(); i++) {
sp<Camera3OutputStreamInterface> outputStream = mOutputStreams[i];
if (outputStream->isConfiguring() && !outputStream->isConsumerConfigurationDeferred()) {
bool streamReConfigured = false;
res = outputStream->finishConfiguration(&streamReConfigured);
if (res != OK) {
CLOGE("Can't finish configuring output stream %d: %s (%d)",
outputStream->getId(), strerror(-res), res);
cancelStreamsConfigurationLocked();
if ((res == NO_INIT || res == DEAD_OBJECT) && outputStream->isAbandoned()) {
return DEAD_OBJECT;
}
return BAD_VALUE;
}
if (streamReConfigured) {
mInterface->onStreamReConfigured(outputStream->getId());
}
}
}// Request thread needs to know to avoid using repeat-last-settings protocol
// across configure_streams() calls
if (notifyRequestThread) {
mRequestThread->configurationComplete(mIsConstrainedHighSpeedConfiguration, sessionParams);
}// Update device state
const camera_metadata_t *newSessionParams = sessionParams.getAndLock();
const camera_metadata_t *currentSessionParams = mSessionParams.getAndLock();
bool updateSessionParams = (newSessionParams != currentSessionParams) ? true : false;
sessionParams.unlock(newSessionParams);
mSessionParams.unlock(currentSessionParams);
if (updateSessionParams) {
mSessionParams = sessionParams;
}ALOGV("%s: Camera %s: Stream configuration complete", __FUNCTION__, mId.string());
// tear down the deleted streams after configure streams.
mDeletedStreams.clear();return OK;
}
status_t Camera3Device::HalInterface::configureStreams(const camera_metadata_t *sessionParams,
camera3_stream_configuration *config, const std::vector<uint32_t>& bufferSizes) {
ATRACE_NAME("CameraHal::configureStreams");
略...// See which version of HAL we have
if (mHidlSession_3_5 != nullptr) {
略...
} else if (mHidlSession_3_4 != nullptr) {
// We do; use v3.4 for the call
ALOGV("%s: v3.4 device found", __FUNCTION__);
auto err = mHidlSession_3_4->configureStreams_3_4(
requestedConfiguration3_4, configStream34Cb);
res = postprocConfigStream34(err);
if (res != OK) {
return res;
}
}
略...return res;
}
vendor/mediatek/proprietary/hardware/mtkcam3/main/hal/device/3.x/device/CameraDevice3SessionImpl.cpp
//V3_4
Return<void>
ThisNamespace::
configureStreams_3_3(const V3_2::StreamConfiguration& requestedConfiguration, configureStreams_3_3_cb _hidl_cb)
{
CAM_ULOG_APILIFE_GUARD(MOD_CAMERA_DEVICE);
CAM_TRACE_CALL();::android::status_t status = OK;
String8 const stateTag(String8::format("-> configure (operationMode:%#x)", requestedConfiguration.operationMode));
mStateLog.add(stateTag + " +");WrappedHalStreamConfiguration halStreamConfiguration;
{
::android::Mutex::Autolock _lOpsLock(mOpsLock);int err = NO_INIT;
status = tryRunCommandLocked(getWaitCommandTimeout(), "onConfigureStreamsLocked", [&, this](){
err = onConfigureStreamsLocked(requestedConfiguration, halStreamConfiguration);
});
if ( status == OK ) {
status = err;
}
}_hidl_cb(mapToHidlCameraStatus(status), halStreamConfiguration);
mStateLog.add(stateTag + " - " + (0==status ? "OK" : ::strerror(-status)));
return Void();
}
vendor/mediatek/proprietary/hardware/mtkcam3/main/hal/device/3.x/device/CameraDevice3SessionImpl.cpp
auto
ThisNamespace::
onConfigureStreamsLocked(
const WrappedStreamConfiguration& requestedConfiguration,
WrappedHalStreamConfiguration& halConfiguration
) -> ::android::status_t
{
MY_LOGD("+");
CAM_ULOG_FUNCLIFE_GUARD(MOD_CAMERA_DEVICE);::android::status_t err = OK;
if ( ! waitUntilOpenDoneLocked() ) {
return NO_INIT;
}
//
{
disableRequesting();
flushAndWait();
}
//
//
IAppStreamManager::ConfigAppStreams appStreams;
auto pAppStreamManager = getSafeAppStreamManager();
if ( pAppStreamManager == 0 ) {
MY_LOGE("Bad AppStreamManager");
return NO_INIT;
}
//
err = pAppStreamManager->beginConfigureStreams(requestedConfiguration, halConfiguration, appStreams);
if ( OK != err ) {
MY_LOGE("fail to beginConfigureStreams");
return err;
}
//
//
{
auto pPipelineModel = getSafePipelineModel();
if ( pPipelineModel == 0 ) {
MY_LOGE("Bad PipelineModel");
return NO_INIT;
}
//
auto pParams = std::make_shared<UserConfigurationParams>();
if ( ! pParams ) {
MY_LOGE("Bad UserConfigurationParams");
return NO_INIT;
}
pParams->operationMode = static_cast<uint32_t>(((V3_4::StreamConfiguration&)requestedConfiguration).operationMode);
//read session parameters
if ( ((V3_4::StreamConfiguration&)requestedConfiguration).sessionParams.size() > 0 ) {
// read settings from session parameters
if ( ! mStaticInfo.mMetadataConverter->convertFromHidl(&((V3_4::StreamConfiguration&)requestedConfiguration).sessionParams, pParams->sessionParams) ) {
MY_LOGE("Bad Session parameters");
return -ENODEV;
}
//if (getLogLevel() >= 2) {
mStaticInfo.mMetadataConverter->dumpAll(pParams->sessionParams, 0);
//}
}
//
pParams->pStreamInfoBuilderFactory = pAppStreamManager->getAppStreamInfoBuilderFactory();
//
{
CAM_TRACE_NAME("_CLONE_");
#define _CLONE_(dst, src) \
do { \
dst.clear(); \
for ( size_t j=0; j<src.size(); ++j) { \
dst.emplace( std::make_pair(src.keyAt(j), src.valueAt(j) ) ); \
} \
} while (0) \_CLONE_(pParams->vImageStreams, appStreams.vImageStreams);
_CLONE_(pParams->vMetaStreams, appStreams.vMetaStreams);
_CLONE_(pParams->vMetaStreams_physical, appStreams.vMetaStreams_physical);
_CLONE_(pParams->vMinFrameDuration, appStreams.vMinFrameDuration);
_CLONE_(pParams->vStallFrameDuration, appStreams.vStallFrameDuration);#undef _CLONE_
}
pParams->vPhysicCameras = appStreams.vPhysicCameras;
MY_LOGD("pParams.vPhysicCameras(%zu)", pParams->vPhysicCameras.size());
pParams->configTimestamp = mConfigTimestamp;
//
err = pPipelineModel->configure(pParams); //配置pipeline
if ( OK != err ) {
MY_LOGE("fail to configure pipeline");
return err;
}
}
//
//
err = pAppStreamManager->endConfigureStreams(halConfiguration);
if ( OK != err ) {
MY_LOGE("fail to endConfigureStreams");
return err;
}
//
//
enableRequesting();
MY_LOGD("-");
return OK;
}
vendor/mediatek/proprietary/hardware/mtkcam3/main/hal/device/3.x/app/AppStreamMgr.cpp
auto
AppStreamMgr::
beginConfigureStreams(
const V3_5::StreamConfiguration& requestedConfiguration,
V3_4::HalStreamConfiguration& halConfiguration,
ConfigAppStreams& rStreams
) -> int
{
CAM_ULOGM_FUNCLIFE();MY_LOGD("StreamConfiguration=%s", toString(requestedConfiguration).c_str());
Mutex::Autolock _l(mInterfaceLock);
//
auto err = mConfigHandler->beginConfigureStreams(requestedConfiguration, halConfiguration, rStreams);
//
// An emtpy settings buffer cannot be used as the first submitted request
// after a configure_streams() call.
if ( OK == err ) {
mRequestHandler->reset();
}
//
return err;
}
vendor/mediatek/proprietary/hardware/mtkcam/main/hal/device/3.x/app/AppStreamMgr.ConfigHandler.cpp
简述下这里面干了些啥事
(1)、检测stream
(2)、设置OperationMode
(3)、生成MetaStreamInfo,并把前者加到Stream中
auto
ThisNamespace::
beginConfigureStreams(
const V3_5::StreamConfiguration& requestedConfiguration,
V3_4::HalStreamConfiguration& halConfiguration,
ConfigAppStreams& rStreams
) -> int
{
auto addFrameDuration = [this](auto& rStreams, auto const pStreamInfo) {
for (size_t j = 0; j < mEntryMinDuration.count(); j+=4) {
if (mEntryMinDuration.itemAt(j , Type2Type<MINT64>()) == (MINT64)pStreamInfo->getOriImgFormat() &&
mEntryMinDuration.itemAt(j + 1, Type2Type<MINT64>()) == (MINT64)pStreamInfo->getLandscapeSize().w &&
mEntryMinDuration.itemAt(j + 2, Type2Type<MINT64>()) == (MINT64)pStreamInfo->getLandscapeSize().h)
{
rStreams.vMinFrameDuration.add(
pStreamInfo->getStreamId(),
mEntryMinDuration.itemAt(j + 3, Type2Type<MINT64>())
);
rStreams.vStallFrameDuration.add(
pStreamInfo->getStreamId(),
mEntryStallDuration.itemAt(j + 3, Type2Type<MINT64>())
);
MY_LOGI("[addFrameDuration] format:%" PRId64 " size:%" PRId64 "x%" PRId64 " min_duration:%" PRId64 ", stall_duration:%" PRId64 ,
mEntryMinDuration.itemAt(j, Type2Type<MINT64>()),
mEntryMinDuration.itemAt(j + 1, Type2Type<MINT64>()),
mEntryMinDuration.itemAt(j + 2, Type2Type<MINT64>()),
mEntryMinDuration.itemAt(j + 3, Type2Type<MINT64>()),
mEntryStallDuration.itemAt(j + 3, Type2Type<MINT64>()));
break;
}
}
return;
};
//
//
int err = OK;
err = checkStreams(requestedConfiguration.v3_4.streams);
if ( OK != err ) {
MY_LOGE("checkStreams failed - StreamConfiguration=%s", toString(requestedConfiguration.v3_4).c_str());
return err;
}
//
mFrameHandler->setOperationMode((uint32_t)requestedConfiguration.v3_4.operationMode);
//
{
StreamId_T const streamId = eSTREAMID_END_OF_FWK;
std::string const streamName = "Meta:App:Control";
auto pStreamInfo = createMetaStreamInfo(streamName.c_str(), streamId);
mFrameHandler->addConfigStream(pStreamInfo);rStreams.vMetaStreams.add(streamId, pStreamInfo);
}mspParsedSMVRBatchInfo = extractSMVRBatchInfo(requestedConfiguration.v3_4);
//
halConfiguration.streams.resize(requestedConfiguration.v3_4.streams.size());
rStreams.vImageStreams.setCapacity(requestedConfiguration.v3_4.streams.size());
for ( size_t i = 0; i < requestedConfiguration.v3_4.streams.size(); i++ )
{
const auto& srcStream = requestedConfiguration.v3_4.streams[i];
auto& dstStream = halConfiguration.streams[i];
StreamId_T streamId = srcStream.v3_2.id;
//
sp<AppImageStreamInfo> pStreamInfo = mFrameHandler->getConfigImageStream(streamId);
if ( pStreamInfo == nullptr )
{
pStreamInfo = createImageStreamInfo(srcStream, dstStream);
if ( pStreamInfo == nullptr ) {
MY_LOGE("createImageStreamInfo failed - Stream=%s", toString(srcStream).c_str());
return -ENODEV;
}
mFrameHandler->addConfigStream(pStreamInfo.get(), false/*keepBufferCache*/);
}
else
{
auto generateLogString = [=]() {
return String8::format("streamId:%d type(%d:%d) "
"size(%dx%d:%dx%d) format(%d:%d) dataSpace(%d:%d) "
"usage(%#" PRIx64 ":%#" PRIx64 ")",
srcStream.v3_2.id, pStreamInfo->getStream().v3_2.streamType, srcStream.v3_2.streamType,
pStreamInfo->getStream().v3_2.width, pStreamInfo->getStream().v3_2.height, srcStream.v3_2.width, srcStream.v3_2.height,
pStreamInfo->getStream().v3_2.format, srcStream.v3_2.format,
pStreamInfo->getStream().v3_2.dataSpace, srcStream.v3_2.dataSpace,
pStreamInfo->getStream().v3_2.usage, srcStream.v3_2.usage
);
};MY_LOGI("stream re-configuration: %s", generateLogString().c_str());
// refer to google default wrapper implementation:
// width/height/format must not change, but usage/rotation might need to change
bool check1 = (srcStream.v3_2.streamType == pStreamInfo->getStream().v3_2.streamType
&& srcStream.v3_2.width == pStreamInfo->getStream().v3_2.width
&& srcStream.v3_2.height == pStreamInfo->getStream().v3_2.height
// && srcStream.v3_2.dataSpace == pStreamInfo->getStream().v3_2.dataSpace
);
bool check2 = true || (srcStream.v3_2.format == pStreamInfo->getStream().v3_2.format
||(srcStream.v3_2.format == (PixelFormat)pStreamInfo->getImgFormat() &&
PixelFormat::IMPLEMENTATION_DEFINED == pStreamInfo->getStream().v3_2.format)
//||(pStreamInfo->getStream().v3_2.format == real format of srcStream.v3_2.format &&
// PixelFormat::IMPLEMENTATION_DEFINED == srcStream.v3_2.format)
);
if ( ! check1 || ! check2 ) {
MY_LOGE("stream configuration changed! %s", generateLogString().c_str());
return -ENODEV;
}// If usage is chaged, it implies that
// the real format (flexible yuv/implementation_defined)
// and the buffer layout may change.
// In this case, should HAL and Frameworks have to cleanup the buffer handle cache?
if ( pStreamInfo->getStream().v3_2.usage != srcStream.v3_2.usage ) {
MY_LOGW("stream usage changed! %s", generateLogString().c_str());
MY_LOGW("shall HAL and Frameworks have to clear buffer handle cache?");
}// Create a new stream to override the old one, since usage/rotation might need to change.
pStreamInfo = createImageStreamInfo(srcStream, dstStream);
mFrameHandler->addConfigStream(pStreamInfo.get(), true/*keepBufferCache*/);
}// check hidl_stream contain physic id or not.
if(srcStream.physicalCameraId.size() != 0)
{
auto& sensorList = rStreams.vPhysicCameras;
MINT32 vid = std::stoi((std::string)srcStream.physicalCameraId);
auto pcId = MAKE_HalLogicalDeviceList()->getDeviceIdByVID(vid);
MY_LOGD("pcid(%d:%s)", pcId, ((std::string)srcStream.physicalCameraId).c_str());
auto iter = std::find(
sensorList.begin(),
sensorList.end(),
pcId);
if(iter == sensorList.end())
{
sensorList.push_back(pcId);
//physical settings
String8 const streamName = String8::format("Meta:App:Physical_%s", ((std::string)srcStream.physicalCameraId).c_str());
StreamId_T const streamId = eSTREAMID_BEGIN_OF_PHYSIC_ID + (int64_t)pcId;
auto pMetaStreamInfo = createMetaStreamInfo(streamName.c_str(), streamId, pcId);
mFrameHandler->addConfigStream(pMetaStreamInfo);
rStreams.vMetaStreams_physical.add(pcId, pMetaStreamInfo);
}
}rStreams.vImageStreams.add(streamId, pStreamInfo);
addFrameDuration(rStreams, pStreamInfo);MY_LOGD_IF(getLogLevel()>=2, "Stream: id:%d streamType:%d %dx%d format:0x%x usage:0x%" PRIx64 " dataSpace:0x%x rotation:%d",
srcStream.v3_2.id, srcStream.v3_2.streamType, srcStream.v3_2.width, srcStream.v3_2.height,
srcStream.v3_2.format, srcStream.v3_2.usage, srcStream.v3_2.dataSpace, srcStream.v3_2.rotation);
}
#ifdef MERLINCOMMON_DIFF_720P
if(requestedConfiguration.v3_4.streams.size() >= 2)
{
uint32_t EIS_ON_720P = 0x8104; //operationmode for eis on 720P video ispprofile
uint32_t EIS_OFF_720P = 0xf110; //operationmode for eis off 720p video ispprofile
uint32_t EIS_ON_DEFAULT = 0x8004; //operationmode for default eis on (1080P)video ispprofile
uint32_t EIS_OFF_DEFAULT = 0xf010; //operationmode for default eis off (1080P)video ispprofile
uint32_t DEC_720P = 1280; //width to decide if 720P
uint32_t operation = (uint32_t)requestedConfiguration.v3_4.operationMode;
uint32_t videoWidth = (uint32_t)requestedConfiguration.v3_4.streams[1].v3_2.width; //format 35 size
uint32_t videoWidth1 = (uint32_t)requestedConfiguration.v3_4.streams[0].v3_2.width; //format 34 capture size
MY_LOGD("operationmode %d videoWidth is %d videoWidth1 is %d",operation,videoWidth,videoWidth1);
if((videoWidth == videoWidth1) && (videoWidth == DEC_720P))
{
if(operation == EIS_OFF_DEFAULT)
{
MY_LOGD("720P close eis operationmode 0xf110");
mFrameHandler->setOperationMode(EIS_OFF_720P);
}
else if(operation == EIS_ON_DEFAULT)
{
MY_LOGD("720P open eis operationmode 0x8104");
mFrameHandler->setOperationMode(EIS_ON_720P);
}
}
}
#endif#ifdef LANCELOTCOMMON_VIDEO_CAPTURE_DIFF_720P
if(requestedConfiguration.v3_4.streams.size() >= 2){
uint32_t operation = (uint32_t)requestedConfiguration.v3_4.operationMode;
uint32_t videoWidth = (uint32_t)requestedConfiguration.v3_4.streams[1].v3_2.width; //format 35 size
uint32_t videoWidth1 = (uint32_t)requestedConfiguration.v3_4.streams[0].v3_2.width; //format 34 capture size
MY_LOGD("operationmode %d videoWidth is %d videoWidth1 is %d",operation,videoWidth,videoWidth1);
if((videoWidth == videoWidth1) && (videoWidth == 1280)){
mFrameHandler->setOperationMode(0x810a);
}
}
#endif
//
return OK;
}
vendor/mediatek/proprietary/hardware/mtkcam3/main/hal/device/3.x/app/AppStreamMgr.FrameHandler.cpp
这块有一些具体的函数就不继续罗列了
2、结语
代码熟练度还不够溜,MTK Code细节不够火候,还需继续深入。我会不定期分享,以便查漏补缺,相互学习。奥里给!!!