如果您觉得有用,请在文末支持一下,您的支持是对我最大的鼓励
《Android Q 之MTK代码分析(一)--Camera Hal3 Service》
《Android Q 之MTK代码分析(二)--Camera Hal3 Search Sensor》
《Android Q 之MTK代码分析(三)--Camera Hal3 Open/Close》
《Android Q 之MTK代码分析(四)--Camera Hal3 configure_Streams》
《Android Q 之MTK代码分析(五)--Camera Hal3 process_capture_request》
《Android Q 之MTK代码分析(六)--Camera Hal3 process_capture_result》
0、前文回顾
前文已经简单说明CameraHalService服务、Serarch Sensor、open的过程 的动作。
在这期间,CameraService、CameraProviderManager、CameraHalService、CamereaProvider、CameraDeviceManager
简单回顾下:
1、CameraService
frameworks/av/services/camera/libcameraservice/CameraService.cpp
08-26 11:30:28. 4144 4144 I CameraService: CameraService started (pid=4144) 08-26 11:30:28. 4144 4144 I CameraService: CameraService process starting
讯享网
/*这里打印的“开始延迟”是对HAL从开始运行所需时间的估计进程创建,将自己注册为HAL。实际的启动时间可能更长
因为进程可能还没有加入线程池,所以它可能还没有准备好加入处理事务*/
讯享网08-26 11:30:28. 4144 4144 I HidlServiceManagement: Registered android.frameworks.cameraservice.service@2.1::ICameraService/default (start delay of 129ms)
2、CameraHalService
vendor/mediatek/proprietary/hardware/mtkcam3/main/hal/service/service.cpp
08-26 11:30:28. 4145 4145 I camerahalserver: Camera HAL Server is starting..., ADV_CAM_SUPPORT(0)
3、Serarch sensor
讯享网08-26 11:30:28. 4145 4145 I mtkcam-devicemgr: [initialize] + 08-26 11:30:28. 4145 4145 D MtkCam/Util/LogicalDevice: (4145)[searchDevices] Create logical device map 08-26 11:30:28. 4145 4145 D MtkCam/HalSensorList: [searchSensors] searchSensors // set mclk 08-26 11:30:28. 4145 4145 D SeninfDrvImp: [setMclk][setMclk]pcEn(1), clkPol(0), mMclkUser[0](1), TimestampClk(0), freq(24), mclkIdx 0 08-26 11:30:28. 4145 4145 D MtkCam/HalSensorList: [enumerateSensor_Locked] impSearchSensor search to 4 08-26 11:30:28. 4145 4145 D ImgSensorDrv: [searchSensor]SENSOR search start 08-26 11:30:28. 4145 4145 D ImgSensorDrv: [searchSensor]set sensor driver id =1 08-26 11:30:28. 4145 4145 D ImgSensorDrv: [searchSensor]sensorIdx 0 found <0x560d45/ov13b10_qtech_mipi_raw/SENSOR_DRVNAME_OV13B10_QTECH_MIPI_RAW> 08-26 11:30:28. 4145 4145 D ImgSensorDrv: [getInfo2]prv w=0x838,h=0x618 08-26 11:30:28. 4145 4145 D ImgSensorDrv: [getInfo2]cap w=0x1070,h=0xc30 08-26 11:30:28. 4145 4145 D ImgSensorDrv: [getInfo2]vd w=0x1070,h=0xc30 08-26 11:30:28. 4145 4145 D ImgSensorDrv: [getInfo2]pre GrapX=0x0,GrapY=0x0 08-26 11:30:28. 4145 4145 D MtkCam/HalSensorList: [getRawInfo] SensorOutputDataFormat: 0, ImageSensor Type: 0 // build sensor meta 08-26 11:30:28. 4145 4145 D MtkCam/HalSensorList: [buildSensorMetadata] impBuildSensorInfo start! 08-26 11:30:28. 4145 4145 D MtkCam/HalSensorList: [buildSensorMetadata] impBuildSensorInfo end! 08-26 11:30:28. 4145 4145 I MtkCam/HalSensorList: [impBuildStaticInfo_v1] <load custom folder> 08-26 11:30:28. 4145 4145 I MtkCam/HalSensorList: STATIC_COMMON: [CAMERA]:1; [CONTROL_AE]:1; [CONTROL_AF]:1; [CONTROL_AWB]:1; [TUNING]:1; [FLASHLIGHT]:1; [SENSOR]:2; [LENS]:0; 08-26 11:30:28. 4145 4145 I MtkCam/HalSensorList: STATIC_PLATFORM: [MODULE]:8; [LENS]:8; 08-26 11:30:28. 4145 4145 I MtkCam/HalSensorList: STATIC_PROJECT: [MODULE]:0; [LENS]:0; 08-26 11:30:28. 4145 4145 D MtkCam/HalSensorList: [updateAFData] MTK_LENS_INFO_MINIMUM_FOCUS_DISTANCE: 20.000000, add AF modes & regions 08-26 11:30:28. 4145 4145 D MtkCam/HalSensorList: [buildStaticInfo] MTK_SENSOR_INFO_ACTIVE_ARRAY_REGION(0, 0, 4208, 3120) 08-26 11:30:28. 4145 4145 D MtkCam/HalSensorList: [buildStaticInfo] MTK_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE(0, 0, 4208, 3120) 08-26 11:30:28. 4145 4145 I MtkCam/HalSensorList: [impBuildStaticInfo_v1_overwrite] <load custom folder - overwrite> 08-26 11:30:28. 4145 4145 I MtkCam/HalSensorList: STATIC_PLATFORM: [MOD_OVERWRITE]:8; 08-26 11:30:28. 4145 4145 I MtkCam/HalSensorList: STATIC_PROJECT: [MOD_OVERWRITE]:0; /*这块会search 到5次sensor*/ 08-26 11:30:29.077172 4145 4145 D MtkCam/Util/LogicalDevice: (4145)[createDeviceMap] sensorNum : 5 08-26 11:30:33. 4145 4145 I mtkcam-devicemgr: [initialize] - // 08-26 11:30:33. 4144 4147 I CameraProviderManager: Connecting to new camera provider: internal/0, isRemote? 1 08-26 11:30:33. 4144 4147 I CameraProviderManager: Enumerating new camera device: device@3.6/internal/0 08-26 11:30:33. 4145 4164 D mtkcam-dev3: 0[CameraDevice3Impl::getResourceCost] Camera Device 0: resourceCost 100, conflict to [device@3.6/internal/5] 08-26 11:30:38. 4145 4145 I mtkcam-dev3: 0[CameraDevice3Impl::open] open camera3 device (device@3.6/internal/0) systraceLevel(1) instanceId(0) vid(0) 08-26 11:30:38. 4145 4145 I mtkcam-AppStreamMgr: [initialize] FMQ request size : , result size :
强力建议熟读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)、切换使用情形时,返回第三步

* 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层。


camera3_device_ops_t 映射函数指针操作: hardware/libhardware/modules/camera/3_0/Camera.cpp


讯享网Return<void> CameraDeviceSession::configureStreams( const StreamConfiguration& requestedConfiguration, ICameraDeviceSession::configureStreams_cb _hidl_cb) { Status status = initStatus(); HalStreamConfiguration outStreams; ATRACE_BEGIN("camera3->configure_streams"); status_t ret = mDevice->ops->configure_streams(mDevice, &stream_list); ATRACE_END(); }
frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp
status_t Camera3Device::configureStreamsLocked(int operatingMode, const CameraMetadata& sessionParams, bool notifyRequestThread) { //配流开始log ALOGV("%s: Camera %s: Starting stream configuration", __FUNCTION__, mId.string()); 略... //创建buffer const camera_metadata_t *sessionBuffer = sessionParams.getAndLock(); res = mInterface->configureStreams(sessionBuffer, &config, bufferSizes); //这里还有重新配流的代码,省略 // Update device state const camera_metadata_t *newSessionParams = sessionParams.getAndLock(); 省略部分代码 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"); 略... auto err = mHidlSession_3_4->configureStreams_3_4( requestedConfiguration3_4, configStream34Cb); 略... 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) { 省略部分代码 err = onConfigureStreamsLocked(requestedConfiguration, halStreamConfiguration); }
vendor/mediatek/proprietary/hardware/mtkcam3/main/hal/device/3.x/device/CameraDevice3SessionImpl.cpp
auto ThisNamespace:: onConfigureStreamsLocked( const WrappedStreamConfiguration& requestedConfiguration, WrappedHalStreamConfiguration& halConfiguration ) -> ::android::status_t { IAppStreamManager::ConfigAppStreams appStreams; auto pAppStreamManager = getSafeAppStreamManager(); err = pAppStreamManager->beginConfigureStreams(requestedConfiguration, halConfiguration, appStreams); auto pPipelineModel = getSafePipelineModel(); err = pPipelineModel->configure(pParams); //配置pipeline err = pAppStreamManager->endConfigureStreams(halConfiguration); }
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 { auto err = mConfigHandler->beginConfigureStreams(requestedConfiguration, halConfiguration, rStreams); }
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 { 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; mFrameHandler->setOperationMode((uint32_t)requestedConfiguration.v3_4.operationMode); std::string const streamName = "Meta:App:Control"; auto pStreamInfo = createMetaStreamInfo(streamName.c_str(), streamId); mFrameHandler->addConfigStream(pStreamInfo); rStreams.vMetaStreams.add(streamId, pStreamInfo); } sp<AppImageStreamInfo> pStreamInfo = mFrameHandler->getConfigImageStream(streamId); mFrameHandler->addConfigStream(pStreamInfo.get(), false/*keepBufferCache*/); //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); } } }
vendor/mediatek/proprietary/hardware/mtkcam3/main/hal/device/3.x/app/AppStreamMgr.FrameHandler.cpp
这块有一些具体的函数就不继续罗列了
图略
讯享网2、log 08-26 11:30:38. 4145 4164 D mtkcam-dev3: [0-session::onConfigureStreamsLocked] + 08-26 11:30:38. 4145 4164 D mtkcam-dev3: [0-session::onConfigureStreamsLocked] - 08-26 11:30:38. 4145 4164 D mtkcam-AppStreamMgr: [beginConfigureStreams] StreamConfiguration= {.v3_4 = {.streams = [3]{ {.v3_2 ={.id = 0, .streamType = OUTPUT, .width = 1920, .height = 1080, .format = IMPLEMENTATION_DEFINED, .usage = CPU_READ_NEVER | CPU_WRITE_NEVER | GPU_TEXTURE (0x100), .dataSpace = UNKNOWN | STANDARD_UNSPECIFIED | TRANSFER_UNSPECIFIED | RANGE_UNSPECIFIED (0), .rotation = ROTATION_0}, .physicalCameraId = "", .bufferSize = 0}, {.v3_2 = {.id = 1, .streamType = OUTPUT, .width = 4096, .height = 2304, .format = BLOB, .usage = CPU_READ_NEVER | CPU_READ_RARELY | CPU_READ_OFTEN | CPU_WRITE_NEVER (0x3), .dataSpace = UNKNOWN | STANDARD_UNSPECIFIED | STANDARD_BT601_625 | TRANSFER_UNSPECIFIED | TRANSFER_LINEAR | TRANSFER_SRGB | TRANSFER_SMPTE_170M | RANGE_UNSPECIFIED | RANGE_FULL | V0_JFIF (0x8c20000), .rotation = ROTATION_0}, .physicalCameraId = "", .bufferSize = }, {.v3_2 = {.id = 2, .streamType = OUTPUT, .width = 176, .height = 144, .format = YCBCR_420_888, .usage = CPU_READ_NEVER | CPU_READ_RARELY | CPU_READ_OFTEN | CPU_WRITE_NEVER (0x3), (mva=0x0/sec=0/prot=0/alpha=1:0xff/blend=0002/dim=0/fmt=4868/range=1()/x=0 y=65 w=1080 h=1 s=1088,66 -> x=0 y=0 w=1080 h=1/layer_type=0 ext_layer=-1 ds=0 fbdc=0) ! 08-26 11:30:38. 4145 4164 W mtkcam-AppStreamMgr: [0-ConfigHandler::checkStream] framework stream dataspace:0x08c20000(V0_JFIF|STANDARD_BT601_625|TRANSFER_SMPTE_170M|RANGE_FULL) {.v3_2 = {.id = 1, .streamType = OUTPUT, .width = 4096, .height = 2304, .format = BLOB, .usage = CPU_READ_NEVER | CPU_READ_RARELY | CPU_READ_OFTEN | CPU_WRITE_NEVER (0x3), .dataSpace = UNKNOWN | STANDARD_UNSPECIFIED | STANDARD_BT601_625 | TRANSFER_UNSPECIFIED | TRANSFER_LINEAR | TRANSFER_SRGB | TRANSFER_SMPTE_170M | RANGE_UNSPECIFIED | RANGE_FULL | V0_JFIF (0x8c20000), .rotation = ROTATION_0}, .physicalCameraId = "", .bufferSize = } 08-26 11:30:38. 4145 4164 W mtkcam-AppStreamMgr: [0-ConfigHandler::checkStream] framework stream dataspace:0x08c20000(V0_JFIF|STANDARD_BT601_625|TRANSFER_SMPTE_170M|RANGE_FULL) {.v3_2 = {.id = 2, .streamType = OUTPUT, .width = 176, .height = 144, .format = YCBCR_420_888, .usage = CPU_READ_NEVER | CPU_READ_RARELY | CPU_READ_OFTEN | CPU_WRITE_NEVER (0x3), .dataSpace = UNKNOWN | STANDARD_UNSPECIFIED | STANDARD_BT601_625 | TRANSFER_UNSPECIFIED | TRANSFER_LINEAR | TRANSFER_SRGB | TRANSFER_SMPTE_170M | RANGE_UNSPECIFIED | RANGE_FULL | V0_JFIF (0x8c20000), .rotation = ROTATION_0}, .physicalCameraId = "", .bufferSize = 0} 08-26 11:30:38. 4145 4164 I mtkcam-AppStreamMgr: [0-FrameHandler::setOperationMode] operationMode change: 0xffffffff -> 0 08-26 11:30:38. 4145 4164 I mtkcam-AppStreamMgr: [0-ConfigHandler::operator()] [addFrameDuration] format:34 size:1920x1080 min_duration:, stall_duration:0 08-26 11:30:38. 4145 4164 D mtkcam-AppStreamMgr: [0-ConfigHandler::beginConfigureStreams] Stream: id:0 streamType:0 1920x1080 format:0x22 usage:0x100 dataSpace:0x0 rotation:0 08-26 11:30:38. 4145 4164 D mtkcam-AppStreamMgr: [0-ConfigHandler::createImageStreamInfo] isSecureCameraDevice=0 usageForHal=0x0x20033 usageForHalClient=0x0x3 08-26 11:30:38. 4145 4164 D mtkcam-AppStreamMgr: [0-ConfigHandler::createImageStreamInfo] grallocRequest.format=33, grallocRequest.usage = 0x20033 08-26 11:30:38. 4145 4164 I mtkcam-AppStreamMgr: [0-ConfigHandler::createImageStreamInfo] BLOB with widthInPixels(), heightInPixels(1), bufferSize() 08-26 11:30:38. 4145 4164 I mtkcam-AppStreamMgr: stream id len : 0 08-26 11:30:38. 4145 4164 D mtkcam-AppStreamMgr: [0-ConfigHandler::createImageStreamInfo] rStream.v_32.usage(0x3) 08-26 11:30:38. 4145 4164 D mtkcam-AppStreamMgr: rStream-Info(sid=0x1, format=0x21, usage=0x3, StreamType::OUTPUT=0x0, streamType=0x0) 08-26 11:30:38. 4145 4164 D mtkcam-AppStreamMgr: grallocStaticInfo(format=0x21) 08-26 11:30:38. 4145 4164 D mtkcam-AppStreamMgr: HalStream-info(producerUsage= 0x20033, consumerUsage= 0, overrideFormat=0x21 ) 08-26 11:30:38. 4145 4164 D mtkcam-AppStreamMgr: Blob-info(imgFmt=0x2300, allocImgFmt=0x21, allocBufPlanes(size=1, sizeInBytes=, rowStrideInBytes=) 08-26 11:30:38. 4145 4164 D mtkcam-AppStreamMgr: Misc-info(usageForAllocator=0x20033, NSCam::BufferUsage::PROT_CAMERA_BIDIRECTIONAL=0x64000) NSCam::BufferUsage::E2E_HDR=0x) 08-26 11:30:38. 4145 4164 D mtkcam-AppStreamMgr: creationInfo(secureInfo=0x0) 08-26 11:30:38. 4145 4164 I mtkcam-AppStreamMgr: [0-ConfigHandler::operator()] [addFrameDuration] format:33 size:4096x2304 min_duration:, stall_duration: 08-26 11:30:38. 4145 4164 D mtkcam-AppStreamMgr: [0-ConfigHandler::beginConfigureStreams] Stream: id:1 streamType:0 4096x2304 format:0x21 usage:0x3 dataSpace:0x8c20000 rotation:0 08-26 11:30:38. 4145 4164 D mtkcam-AppStreamMgr: [0-ConfigHandler::createImageStreamInfo] isSecureCameraDevice=0 usageForHal=0x0x20033 usageForHalClient=0x0x3 08-26 11:30:38. 4145 4164 D mtkcam-AppStreamMgr: [0-ConfigHandler::createImageStreamInfo] grallocRequest.format=35, grallocRequest.usage = 0x20033 08-26 11:30:38. 4145 4164 I mtkcam-AppStreamMgr: [0-ConfigHandler::operator()] [addFrameDuration] format:35 size:176x144 min_duration:, stall_duration:0 08-26 11:30:38. 4145 4164 D mtkcam-AppStreamMgr: [0-ConfigHandler::beginConfigureStreams] Stream: id:2 streamType:0 176x144 format:0x23 usage:0x3 dataSpace:0x8c20000 rotation:0 08-26 11:30:38. 4145 4164 D mtkcam-AppStreamMgr: [0-ConfigHandler::beginConfigureStreams] operationmode 0 videoWidth is 4096 videoWidth1 is 1920 08-26 11:30:38. 4145 4164 D mtkcam-dev3: [0-session::onConfigureStreamsLocked] pParams.vPhysicCameras(0) 08-26 11:30:38. 4145 4164 D mtkcam-dev3: [0-session::onConfigureStreamsLocked] pImageStreamBufferProvider 0x0 08-26 11:30:38. 4145 4164 D mtkcam-dev3: [0-session::onConfigureStreamsLocked] - 08-26 11:30:38. 4145 4164 I mtkcam-dev3: [0-session::tryRunCommandLocked] Run command onConfigureStreamsLocked -

这块是设置上层下发的流的格式。
2.1 config stage log
2.1.1 PipelineModelSessionFactory log
log具体含义,看《MTK_camera_pipeline_framework.pdf》
02-04 11:25:35.639 921 921 D mtkcam-PipelineModelSession-Factory: [convertToUserConfiguration] APP set init frame : 1, if not be zero, force it to be 4 02-04 11:25:35.641 921 921 I mtkcam-PipelineModelSession-Factory: [convertToUserConfiguration] force 3rd flow 02-04 11:25:35.641 921 921 I mtkcam-PipelineModelSession-Factory: [convertToUserConfiguration] dual cam device(s:0,path:1) forceFeatureMode(1) pack jpeg(0) physical(0) s(16) c(1) 02-04 11:25:33.979 921 11876 D mtkcam-PipelineModelSession-Factory: [parseAppStreamInfo] ispTuningDataEnable(0) StreamId(0) ConsumerUsage(2304) size(1440,1080) yuv_isp_tuning_data_size(1280,720) raw_isp_tuning_data_size(2560,1920) 02-04 11:25:33.979 921 11876 D mtkcam-PipelineModelSession-Factory: [parseAppStreamInfo] ispTuningDataEnable(0) StreamId(0x2) ConsumerUsage(3) size(1440,1080) yuv_isp_tuning_data_size(1280,720) raw_isp_tuning_data_size(2560,1920) 02-04 11:25:35.643 921 921 I mtkcam-PipelineModelSession-Factory: [decidePipelineModelSession] Vsdof StreamId: pStreamInfo->getStreamId() size(1440,1080) :StreamSize yuv_isp_tuning_data_size(1280,720) :Tuning data size raw_isp_tuning_data_size(2560,1920) :Tuning data size Vsdof : PipelineModelSession类型为 Zoom
//todo后面还有很多log
3、结语
代码熟练度还不够溜,MTK Code细节不够火候,还需继续深入。我会不定期分享,以便查漏补缺,相互学习。奥里给!!!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/68383.html