/* ******************************************************************************** * eyesee framework module * * (c) Copyright 2010-2018, Allwinner Microelectronic Co., Ltd. * All Rights Reserved * * File : EyeseeUSBCamera.cpp * Version: V1.0 * By : * Date : 2018-01-11 * Description: ******************************************************************************** */ #include #include #include #include #include #include #include #include "EyeseeUSBCamera.h" #include "VdecFrameManager.h" #include "UvcChannel.h" namespace EyeseeLinux { int EyeseeUSBCamera::mCameraCounter = 0; class UvcChannel; static bool JudgeCompressedCaptureFormat(UVC_CAPTURE_FORMAT format) { bool bCompressed = false; //if capture format is compressed, e.g mjpeg, h264, set true; switch(format) { case UVC_YUY2: case UVC_NV12: bCompressed = false; break; case UVC_H264: case UVC_MJPEG: bCompressed = true; break; default: aloge("fatal error! unknown capture format[0x%x]!", format); bCompressed = false; break; } return bCompressed; } static int decideMaxScaleRatio(int maxRatio, PAYLOAD_TYPE_E eCodecFormat) { #if (defined(MPPCFG_CHIP_AW1721) || defined(MPPCFG_CHIP_AW1816) || defined(MPPCFG_CHIP_AW1886)) switch(eCodecFormat) { case PT_H264: case PT_H265: { if (maxRatio > 2) { alogd("limit ScaleDownRatio[%d]->[2] of CodecFormat[0x%x]", maxRatio, eCodecFormat); maxRatio = 2; } break; } case PT_JPEG: case PT_MJPEG: { if (maxRatio > 5) { alogd("limit ScaleDownRatio[%d]->[5] of CodecFormat[0x%x]", maxRatio, eCodecFormat); maxRatio = 5; } break; } default: { aloge("fatal error! unknown CodecFormat[0x%x]", eCodecFormat); if (maxRatio > 2) { alogd("limit ScaleDownRatio[%d]->[2] of CodecFormat[0x%x]", maxRatio, eCodecFormat); maxRatio = 2; } break; } } #else aloge("fatal error! unknown chip"); if (maxRatio > 2) { alogd("limit ScaleDownRatio[%d]->[2] of CodecFormat[0x%x]", maxRatio, eCodecFormat); maxRatio = 2; } #endif return maxRatio; } class EyeseeUSBCameraContext : public DataListener , public NotifyListener { public: EyeseeUSBCameraContext(EyeseeUSBCamera *pCamera); ~EyeseeUSBCameraContext(); virtual void postData(int msgType, int chnId, const std::shared_ptr& dataPtr, size_t dataSize); virtual void notify(int msgType, int chnId, int ext1, int ext2); private: EyeseeUSBCamera *mpCamera; Mutex mLock; }; EyeseeUSBCameraContext::EyeseeUSBCameraContext(EyeseeUSBCamera *pCamera) : mpCamera(pCamera) { } EyeseeUSBCameraContext::~EyeseeUSBCameraContext() { } void EyeseeUSBCameraContext::postData(int msgType, int chnId, const std::shared_ptr& dataPtr, size_t dataSize) { EyeseeUSBCamera::postEventFromNative(mpCamera, msgType, chnId, (int)dataSize, 0, &dataPtr); } void EyeseeUSBCameraContext::notify(int msgType, int chnId, int ext1, int ext2) { EyeseeUSBCamera::postEventFromNative(mpCamera, msgType, chnId, ext1, ext2, NULL); } void EyeseeUSBCamera::postEventFromNative(EyeseeUSBCamera *pCam, int what, int arg1, int arg2, int arg3, const std::shared_ptr* pDataPtr) { if (pCam == NULL) { aloge("fatal error! pCam == NULL"); return; } CallbackMessage msg; msg.what = what; msg.arg1 = arg1; msg.arg2 = arg2; msg.extArgs.push_back(arg3); //msg.obj = obj; if(pDataPtr) { msg.mDataPtr = std::const_pointer_cast(*pDataPtr); } pCam->mpEventHandler->post(msg); } EyeseeUSBCamera::EventHandler::EventHandler(EyeseeUSBCamera *pCam) : mpCamera(pCam) { } void EyeseeUSBCamera::EventHandler::handleMessage(const CallbackMessage &msg) { switch (msg.what) { case CAMERA_MSG_COMPRESSED_IMAGE: { AutoMutex lock(mpCamera->mSetTakePictureCallbackLock); UvcChn chnId = (UvcChn)msg.arg1; std::map::iterator it = mpCamera->mTakePictureCallback.find(chnId); if(it == mpCamera->mTakePictureCallback.end()) { aloge("fatal error, why not find chnId[%d]", chnId); return; } if (it->second.mpJpegCallback) { if(msg.mDataPtr) { if(msg.mDataPtr->getPointer() != NULL) { const void *pData = msg.mDataPtr->getPointer(); int nSize = msg.arg2; it->second.mpJpegCallback->onPictureTaken(chnId, pData, nSize, mpCamera); } } } return; } case CAMERA_MSG_POSTVIEW_FRAME: { AutoMutex lock(mpCamera->mSetTakePictureCallbackLock); UvcChn chnId = (UvcChn)msg.arg1; std::map::iterator it = mpCamera->mTakePictureCallback.find(chnId); if(it == mpCamera->mTakePictureCallback.end()) { aloge("fatal error, why not find chnId[%d]", chnId); return; } if (it->second.mpPostviewCallback) { if(msg.mDataPtr) { if(msg.mDataPtr->getPointer() != NULL) { //int chnId = msg.arg1; const void *pData = msg.mDataPtr->getPointer(); int nSize = msg.arg2; it->second.mpPostviewCallback->onPictureTaken(chnId, pData, nSize, mpCamera); } } } return; } case CAMERA_MSG_ERROR: aloge("Channel %d error %d", msg.arg1, msg.arg2); if (mpCamera->mpErrorCallback != NULL) { mpCamera->mpErrorCallback->onError((UvcChn)msg.arg1, (CameraMsgErrorType)msg.arg2, mpCamera); } return; case CAMERA_MSG_INFO: { UvcChn chnId = (UvcChn)msg.arg1; CameraMsgInfoType what = (CameraMsgInfoType)msg.arg2; int extra = 0; if(msg.extArgs.size() > 0) { extra = msg.extArgs[0]; } if (mpCamera->mpInfoCallback != NULL) { mpCamera->mpInfoCallback->onInfo(chnId, what, extra, mpCamera); } return; } default: { aloge("Channel %d Unknown message type %d", msg.arg1, msg.what); return; } } } EyeseeUSBCamera::USBCameraProxy::USBCameraProxy(EyeseeUSBCamera *pUSBCameraParam) { mpUSBCamera = pUSBCameraParam; } status_t EyeseeUSBCamera::USBCameraProxy::startRecording(int chnId, CameraRecordingProxyListener *pListener, int recorderId) { return mpUSBCamera->startRecording((UvcChn)chnId, pListener, recorderId); } status_t EyeseeUSBCamera::USBCameraProxy::stopRecording(int chnId, int recorderId) { return mpUSBCamera->stopRecording((UvcChn)chnId, recorderId); } void EyeseeUSBCamera::USBCameraProxy::releaseRecordingFrame(int chnId, uint32_t frameIndex) { mpUSBCamera->releaseRecordingFrame((UvcChn)chnId, frameIndex); } status_t EyeseeUSBCamera::USBCameraProxy::setChannelDisplay(int chnId, int hlay) { aloge("this is what, is funy???"); return UNKNOWN_ERROR; } status_t EyeseeUSBCamera::USBCameraProxy::getParameters(int chnId, CameraParameters ¶m) { return mpUSBCamera->getParameters((UvcChn)chnId, param); } status_t EyeseeUSBCamera::USBCameraProxy::setParameters(int chnId, CameraParameters ¶m) { return mpUSBCamera->setParameters((UvcChn)chnId, param); } EyeseeUSBCamera::EyeseeUSBCamera() :mCameraId(mCameraCounter++) { clearConfig(); mpErrorCallback = NULL; mpInfoCallback = NULL; mTakePictureCallback.clear(); mUvcChnList.clear(); mpEventHandler = new EventHandler(this); mpNativeContext = new EyeseeUSBCameraContext(this); mCurrentState = State::IDLE; } EyeseeUSBCamera::~EyeseeUSBCamera() { AutoMutex autoMutex(mLock); if(mCurrentState != State::IDLE) { aloge("called in wrong state 0x%x", mCurrentState); } if (mpNativeContext != NULL) { delete mpNativeContext; mpNativeContext = NULL; } if(!mUvcChnList.empty()) { aloge("fatal error! uvcChn list is not empty!"); } if (mpEventHandler != NULL) { delete mpEventHandler; mpEventHandler = NULL; } clearConfig(); } status_t EyeseeUSBCamera::getUSBCameraCaptureParam(USBCameraCaptureParam &CaptureParam) const { CaptureParam = mCaptureParam; return NO_ERROR; } status_t EyeseeUSBCamera::setUSBCameraCaptureParam(const USBCameraCaptureParam &CaptureParam) { AutoMutex autoMutex(mLock); if(State::IDLE != mCurrentState) { alogw("Be careful! usb camera param can only be set in idle state!"); return PERMISSION_DENIED; } mCaptureParam = CaptureParam; mbCaptureFlag = true; return NO_ERROR; } status_t EyeseeUSBCamera::getUSBCameraVdecParam(USBCameraVdecParam &VdecParam) const { VdecParam = mVdecParam; return NO_ERROR; } status_t EyeseeUSBCamera::setUSBCameraVdecParam(const USBCameraVdecParam &VdecParam) { AutoMutex autoMutex(mLock); if(State::IDLE != mCurrentState) { alogw("Be careful! usb camera param can only be set in idle state!"); return PERMISSION_DENIED; } mVdecParam = VdecParam; mbVdecFlag = true; return NO_ERROR; } CameraRecordingProxy* EyeseeUSBCamera::getRecordingProxy() { return new USBCameraProxy(this); } status_t EyeseeUSBCamera::prepareDevice() { AutoMutex autoMutex(mLock); if(mCurrentState != State::IDLE) { aloge("called in wrong state 0x%x", mCurrentState); return INVALID_OPERATION; } if(!mbCaptureFlag) { aloge("error,you must set capture param!!!"); return INVALID_OPERATION; } int Ret = NO_ERROR; Ret = openUSBCamera(); if(Ret != NO_ERROR) { aloge("fatal error, can not open %s usbcamera, 0x%x", mCaptureParam.mpUsbCam_DevName, Ret); return Ret; } if(mbVdecFlag && JudgeCompressedCaptureFormat(mCaptureParam.mUsbCam_CapPixelformat)) { //create uvc virtual channel. mVirtualUvcChnForVdec = 0; while(mVirtualUvcChnForVdec < UVC_MAX_CHN_NUM) { Ret = AW_MPI_UVC_CreateVirChn((UVC_DEV)mUvcDev.c_str(), mVirtualUvcChnForVdec); if(SUCCESS == Ret) { break; } else if(ERR_UVC_EXIST == Ret) { mVirtualUvcChnForVdec++; } else { aloge("the %s usbcamera fail to create virchn[%d], 0x%x", mUvcDev, mVirtualUvcChnForVdec, Ret); mVirtualUvcChnForVdec++; } } if(UVC_MAX_CHN_NUM == mVirtualUvcChnForVdec) { aloge("fatal error! the %s usbcamera fail to create virchn.", mUvcDev); return UNKNOWN_ERROR; } Ret = openVdecDevice(); if(Ret != NO_ERROR) { aloge("fatal error, can not create %s usbcamera vdecchn[%d], 0x%x", mCaptureParam.mpUsbCam_DevName, mVdecChn, Ret); return Ret; } MPP_CHN_S UvcChn = {MOD_ID_UVC, (int)mUvcDev.c_str(), mVirtualUvcChnForVdec}; MPP_CHN_S VdecChn = {MOD_ID_VDEC, 0, mVdecChn}; Ret = AW_MPI_SYS_Bind(&UvcChn, &VdecChn); if(Ret != SUCCESS) { aloge("can not bind uvcchn[%d] and vdecchn[%d], 0x%x", mVirtualUvcChnForVdec, mVdecChn, Ret); return UNKNOWN_ERROR; } //create vdec frame manager mpVdecFrameManager = new VdecFrameManager(mVdecChn, mbVdecSubOutputFlag); if(NULL == mpVdecFrameManager) { aloge("fatal error! malloc fail!"); } } mCurrentState = State::PREPARED; return NO_ERROR; } status_t EyeseeUSBCamera::startDevice() { AutoMutex autoMutex(mLock); if(mCurrentState != State::PREPARED) { aloge("called in wrong state 0x%x", mCurrentState); return INVALID_OPERATION; } int Ret = NO_ERROR; if(mbVdecFlag && JudgeCompressedCaptureFormat(mCaptureParam.mUsbCam_CapPixelformat)) { Ret = AW_MPI_VDEC_StartRecvStream(mVdecChn); if(Ret != SUCCESS) { aloge("fatal error! the %s usbcamera can not start vdecchn[%d], 0x%x", mUvcDev, mVdecChn, Ret); return UNKNOWN_ERROR; } Ret = AW_MPI_UVC_StartRecvPic((UVC_DEV)mUvcDev.c_str(), mVirtualUvcChnForVdec); if(Ret != SUCCESS) { aloge("fatal error! the %s usbcamera can not start uvcchn[%d], 0x%x", mUvcDev, mVirtualUvcChnForVdec, Ret); return UNKNOWN_ERROR; } status_t eRet; eRet = mpVdecFrameManager->start(); if(eRet != NO_ERROR) { aloge("fatal error! check code!"); } } Ret = AW_MPI_UVC_EnableDevice((UVC_DEV)mUvcDev.c_str()); if(Ret != SUCCESS) { aloge("the %s usbcamera can not enable, 0x%x", mUvcDev, Ret); return Ret; } mCurrentState = State::STARTED; return NO_ERROR; } status_t EyeseeUSBCamera::stopDevice() { AutoMutex autoMutex(mLock); if(mCurrentState != State::STARTED) { aloge("called in wrong state 0x%x", mCurrentState); return INVALID_OPERATION; } int Ret = SUCCESS; if(mbVdecFlag && JudgeCompressedCaptureFormat(mCaptureParam.mUsbCam_CapPixelformat)) { status_t eRet = mpVdecFrameManager->stop(); if(eRet != NO_ERROR) { aloge("fatal error! check code!"); } Ret = AW_MPI_UVC_StopRecvPic((UVC_DEV)mUvcDev.c_str(), mVirtualUvcChnForVdec); if(Ret != SUCCESS) { aloge("%s usbcamera can not stop uvcchn[%d], 0x%x", mUvcDev.c_str(), mVirtualUvcChnForVdec, Ret); return UNKNOWN_ERROR; } Ret = AW_MPI_VDEC_StopRecvStream(mVdecChn); if(Ret != SUCCESS) { aloge("%s usbcamera can not stop vdecchn[%d], 0x%x", mUvcDev, mVdecChn, Ret); return UNKNOWN_ERROR; } } mCurrentState = State::PREPARED; return NO_ERROR; } status_t EyeseeUSBCamera::releaseDevice() { AutoMutex autoMutex(mLock); if(mCurrentState != State::PREPARED) { aloge("called in wrong state 0x%x", mCurrentState); return INVALID_OPERATION; } if(mbVdecFlag && JudgeCompressedCaptureFormat(mCaptureParam.mUsbCam_CapPixelformat)) { if(mpVdecFrameManager) { delete mpVdecFrameManager; mpVdecFrameManager = NULL; } AW_MPI_VDEC_DestroyChn(mVdecChn); mVdecChn = MM_INVALID_CHN; AW_MPI_UVC_DestroyVirChn((UVC_DEV)mUvcDev.c_str(), mVirtualUvcChnForVdec); mVirtualUvcChnForVdec = MM_INVALID_CHN; } ERRORTYPE Ret = AW_MPI_UVC_DisableDevice((UVC_DEV)mUvcDev.c_str()); if(Ret != NO_ERROR) { aloge("fatal error! check code!"); } Ret = AW_MPI_UVC_DestroyDevice((UVC_DEV)mUvcDev.c_str()); if(Ret != NO_ERROR) { aloge("fatal error! check code!"); } mUvcDev = ""; clearConfig(); mCurrentState = State::IDLE; return NO_ERROR; } UvcChannel *EyeseeUSBCamera::searchUvcChannel_l(UvcChn chnId) { for (auto& i : mUvcChnList) { if (i.mChnId == chnId) { return i.mpChannel; } } return NULL; } UvcChannel *EyeseeUSBCamera::searchUvcChannel(UvcChn chnId) { AutoMutex lock(mUvcChnListLock); return searchUvcChannel_l(chnId); } status_t EyeseeUSBCamera::openChannel(UvcChn chnId) { AutoMutex autoMutex(mLock); if(mCurrentState != State::STARTED) { aloge("called in wrong state 0x%x", mCurrentState); return INVALID_OPERATION; } UvcChannel *pChannel = searchUvcChannel(chnId); if (pChannel != NULL) { aloge("channel %d is opened!", chnId); return ALREADY_EXISTS; } //decide if permit create uvcChn. bool bPermit = false; if(UvcChn::UvcMainChn == chnId) { bPermit = true; } else if(UvcChn::VdecMainChn == chnId) { if(mbVdecFlag && JudgeCompressedCaptureFormat(mCaptureParam.mUsbCam_CapPixelformat)) { bPermit = true; } } else if(UvcChn::VdecSubChn == chnId) { if(mbVdecFlag && JudgeCompressedCaptureFormat(mCaptureParam.mUsbCam_CapPixelformat)) { if(mbVdecSubOutputFlag) { bPermit = true; } } } else { aloge("fatal error! wrong uvcChn[%d]!", chnId); } if(false == bPermit) { return PERMISSION_DENIED; } AutoMutex lock(mUvcChnListLock); UvcChannelInfo chnInfo; chnInfo.mpChannel = new UvcChannel(mUvcDev, mCameraId, chnId, mpVdecFrameManager); chnInfo.mChnId = chnId; mUvcChnList.push_back(chnInfo); CameraParameters chnParams; chnInfo.mpChannel->getParameters(chnParams); if(UvcChn::UvcMainChn == chnId) { SIZE_S videoSize = {mUvcDevAttr.mUvcVideo_Width, mUvcDevAttr.mUvcVideo_Height}; chnParams.setVideoSize(videoSize); alogd("uvcChn[%d] videoSize[%dx%d]", chnId, videoSize.Width, videoSize.Height); chnParams.setPreviewFrameRate(mUvcDevAttr.mUvcVideo_Fps); chnParams.setPreviewFormat(map_V4L2_PIX_FMT_to_PIXEL_FORMAT_E(mUvcDevAttr.mPixelformat)); chnParams.setVideoBufferNumber(mUvcDevAttr.mUvcVideo_BufCnt); } else if(UvcChn::VdecMainChn == chnId) { SIZE_S videoSize = {mVdecChnAttr.mPicWidth, mVdecChnAttr.mPicHeight}; chnParams.setVideoSize(videoSize); SIZE_S videoBufSize = {AWALIGN(mVdecChnAttr.mPicWidth, 32), AWALIGN(mVdecChnAttr.mPicHeight, 32)}; chnParams.setVideoBufSizeOut(videoBufSize); alogd("uvcChn[%d] videoSize[%dx%d], bufSize[%dx%d]", chnId, videoSize.Width, videoSize.Height, videoBufSize.Width, videoBufSize.Height); chnParams.setPreviewFrameRate(mUvcDevAttr.mUvcVideo_Fps); chnParams.setPreviewFormat(mVdecChnAttr.mOutputPixelFormat); chnParams.setVideoBufferNumber(5); } else if(UvcChn::VdecSubChn == chnId) { unsigned int mSubPicWidth = AWALIGN((unsigned int)ceil((float)mVdecChnAttr.mPicWidth/pow(2, mVdecChnAttr.mSubPicWidthRatio)), 2); unsigned int mSubPicHeight = AWALIGN((unsigned int)ceil((float)mVdecChnAttr.mPicHeight/pow(2, mVdecChnAttr.mSubPicHeightRatio)), 2); SIZE_S videoSize = {mSubPicWidth, mSubPicHeight}; chnParams.setVideoSize(videoSize); SIZE_S videoBufSize = {AWALIGN(mSubPicWidth, 32), AWALIGN(mSubPicHeight, 32)}; chnParams.setVideoBufSizeOut(videoBufSize); alogd("uvcChn[%d], videoSize[%dx%d], bufSize[%dx%d]", chnId, videoSize.Width, videoSize.Height, videoBufSize.Width, videoBufSize.Height); chnParams.setPreviewFrameRate(mUvcDevAttr.mUvcVideo_Fps); chnParams.setPreviewFormat(mVdecChnAttr.mSubOutputPixelFormat); chnParams.setVideoBufferNumber(5); } chnParams.setColorSpace(V4L2_COLORSPACE_JPEG); chnParams.setPreviewRotation(0); chnParams.setZoomSupported(true); chnParams.setZoom(0); chnParams.setMaxZoom(10); chnInfo.mpChannel->setParameters(chnParams); chnInfo.mpChannel->setDataListener(mpNativeContext); chnInfo.mpChannel->setNotifyListener(mpNativeContext); return NO_ERROR; } status_t EyeseeUSBCamera::prepareChannel(UvcChn chnId) { AutoMutex autoMutex(mLock); if(mCurrentState != State::STARTED) { aloge("called in wrong state 0x%x", mCurrentState); return INVALID_OPERATION; } UvcChannel *pChannel = searchUvcChannel(chnId); if (pChannel == NULL) { aloge("channel %d is not exist!", chnId); return NO_INIT; } status_t ret = pChannel->prepare(); if (ret != NO_ERROR) { aloge("prepare channel error!"); return ret; } return NO_ERROR; } status_t EyeseeUSBCamera::startChannel(UvcChn chnId) { AutoMutex autoMutex(mLock); if(mCurrentState != State::STARTED) { aloge("called in wrong state 0x%x", mCurrentState); return INVALID_OPERATION; } UvcChannel *pChannel = searchUvcChannel(chnId); if (pChannel == NULL) { aloge("channel %d is not exist!", chnId); return NO_INIT; } status_t ret = pChannel->startChannel(); if(ret != NO_ERROR) { aloge("fatal error! uvcChn[%d] start fail[0x%x]", chnId, ret); } return ret; } status_t EyeseeUSBCamera::stopChannel(UvcChn chnId) { AutoMutex autoMutex(mLock); if(mCurrentState != State::STARTED) { aloge("called in wrong state 0x%x", mCurrentState); return INVALID_OPERATION; } UvcChannel *pChannel = searchUvcChannel(chnId); if (pChannel == NULL) { aloge("channel %d is not exist!", chnId); return NO_INIT; } return pChannel->stopChannel(); } status_t EyeseeUSBCamera::releaseChannel(UvcChn chnId) { AutoMutex autoMutex(mLock); if(mCurrentState != State::STARTED) { aloge("called in wrong state 0x%x", mCurrentState); return INVALID_OPERATION; } UvcChannel *pChannel = searchUvcChannel(chnId); if (pChannel == NULL) { aloge("channel %d is not exist!", chnId); return NO_INIT; } AutoMutex lock(mUvcChnListLock); status_t ret = pChannel->release(); return ret; } status_t EyeseeUSBCamera::closeChannel(UvcChn chnId) { AutoMutex autoMutex(mLock); if(mCurrentState != State::STARTED) { aloge("called in wrong state 0x%x", mCurrentState); return INVALID_OPERATION; } bool found = false; { AutoMutex lock(mUvcChnListLock); for (auto it = mUvcChnList.begin(); it != mUvcChnList.end(); ++it) { if (it->mChnId == chnId) { delete it->mpChannel; mUvcChnList.erase(it); found = true; break; } } } if (!found) { aloge("channel %d is not exist!", chnId); return INVALID_OPERATION; } return NO_ERROR; } status_t EyeseeUSBCamera::setParameters(UvcChn chnId, CameraParameters ¶m) { UvcChannel *pChannel = searchUvcChannel(chnId); if (pChannel == NULL) { alogd("channel %d is not exist!", chnId); return NO_INIT; } return pChannel->setParameters(param); } status_t EyeseeUSBCamera::getParameters(UvcChn chnId, CameraParameters ¶m) { UvcChannel *pChannel = searchUvcChannel(chnId); if (pChannel == NULL) { alogd("Be careful! channel %d is not exist!", chnId); return NO_INIT; } return pChannel->getParameters(param); } status_t EyeseeUSBCamera::setChannelDisplay(UvcChn chnId, VO_LAYER VoLayer) { AutoMutex autoMutex(mLock); UvcChannel *pChannel = searchUvcChannel(chnId); if (pChannel == NULL) { aloge("channel %d is not exist!", chnId); return NO_INIT; } return pChannel->setPreviewDisplay(VoLayer); } bool EyeseeUSBCamera::previewEnabled(UvcChn chnId) { UvcChannel *pChannel = searchUvcChannel(chnId); if (pChannel == NULL) { aloge("channel %d is not exist!", chnId); return false; } return pChannel->isPreviewEnabled(); } status_t EyeseeUSBCamera::startRender(UvcChn chnId) { UvcChannel *pChannel = searchUvcChannel(chnId); if (pChannel == NULL) { aloge("channel %d is not exist!", chnId); return NO_INIT; } return pChannel->startRender(); } status_t EyeseeUSBCamera::stopRender(UvcChn chnId) { UvcChannel *pChannel = searchUvcChannel(chnId); if (pChannel == NULL) { aloge("channel %d is not exist!", chnId); return NO_INIT; } return pChannel->stopRender(); } void EyeseeUSBCamera::releaseRecordingFrame(UvcChn chnId, uint32_t index) { UvcChannel *pChannel = searchUvcChannel(chnId); if (pChannel == NULL) { aloge("channel %d is not exist!", chnId); return; } pChannel->releaseFrame(index); } status_t EyeseeUSBCamera::startRecording(UvcChn chnId, CameraRecordingProxyListener *pCb, int recorderId) { UvcChannel *pChannel = searchUvcChannel(chnId); if (pChannel == NULL) { aloge("channel %d is not exist!", chnId); return NO_INIT; } return pChannel->startRecording(pCb, recorderId); } status_t EyeseeUSBCamera::stopRecording(UvcChn chnId, int recorderId) { UvcChannel *pChannel = searchUvcChannel(chnId); if (pChannel == NULL) { aloge("channel %d is not exist!", chnId); return NO_INIT; } return pChannel->stopRecording(recorderId); } void EyeseeUSBCamera::setErrorCallback(ErrorCallback *pCb) { mpErrorCallback = pCb; } void EyeseeUSBCamera::setInfoCallback(InfoCallback *pCb) { mpInfoCallback = pCb; } status_t EyeseeUSBCamera::takePicture(UvcChn chnId, PictureCallback *pPostview, PictureCallback *pJpeg, PictureRegionCallback *pPicRegion) { AutoMutex lock(mSetTakePictureCallbackLock); alogv("takePicture"); std::map::iterator it = mTakePictureCallback.find(chnId); if(it == mTakePictureCallback.end()) { TakePictureCallback Temp; Temp.mpPostviewCallback = pPostview; Temp.mpJpegCallback = pJpeg; Temp.mpPictureRegionCallback = pPicRegion; std::pair::iterator, bool> insertRet = mTakePictureCallback.insert(std::make_pair(chnId, Temp)); if(insertRet.second != true) { aloge("fatal error! insert std::pair fail!"); return UNKNOWN_ERROR; } /*if((it = mTakePictureCallback.find(chnId)) == mTakePictureCallback.end()) { aloge("fatal error!"); return UNKNOWN_ERROR; }*/ } else { it->second.mpPostviewCallback = pPostview; it->second.mpJpegCallback = pJpeg; it->second.mpPictureRegionCallback = pPicRegion; } // If callback is not set, do not send me callbacks. unsigned int msgType = 0; status_t ret = NO_ERROR; //EyeseeCameraContext *context = (EyeseeCameraContext*)mpNativeContext; if (pPostview != NULL) { msgType |= CAMERA_MSG_POSTVIEW_FRAME; } if (pJpeg != NULL) { msgType |= CAMERA_MSG_COMPRESSED_IMAGE; } #if 0 /* * When CAMERA_MSG_RAW_IMAGE is requested, if the raw image callback * buffer is available, CAMERA_MSG_RAW_IMAGE is enabled to get the * notification _and_ the data; otherwise, CAMERA_MSG_RAW_IMAGE_NOTIFY * is enabled to receive the callback notification but no data. */ if (msgType & CAMERA_MSG_RAW_IMAGE) { alogv("Enable raw image callback buffer"); if (!context->isRawImageCallbackBufferAvailable()) { alogv("Enable raw image notification, since no callback buffer exists"); msgType &= ~CAMERA_MSG_RAW_IMAGE; msgType |= CAMERA_MSG_RAW_IMAGE_NOTIFY; } } #endif UvcChannel *pChannel = searchUvcChannel(chnId); if (pChannel == NULL) { aloge("channel %d is not exist!", chnId); return NO_INIT; } bool bCanTakePic = true; if(pChannel->getChannelId() == UvcChn::UvcMainChn) { if(JudgeCompressedCaptureFormat(mUvcDevAttr.mPixelformat)) { if(pPostview!=NULL) { aloge("fatal error! compressed format can't generate postview picture!"); bCanTakePic = false; } } } if(bCanTakePic) { return pChannel->takePicture(msgType, pPicRegion); } else { return BAD_VALUE; } } status_t EyeseeUSBCamera::openUSBCamera() { mUvcDev = mCaptureParam.mpUsbCam_DevName; int Ret = AW_MPI_UVC_CreateDevice((UVC_DEV)mUvcDev.c_str()); if(Ret != SUCCESS) { aloge("the %s usbcamera device can not create!", mUvcDev); return UNKNOWN_ERROR; } AW_MPI_UVC_GetDeviceAttr((UVC_DEV)mUvcDev.c_str(), &mUvcDevAttr); mUvcDevAttr.mPixelformat = mCaptureParam.mUsbCam_CapPixelformat; mUvcDevAttr.mUvcVideo_Width = mCaptureParam.mUsbCam_CapWidth; mUvcDevAttr.mUvcVideo_Height = mCaptureParam.mUsbCam_CapHeight; mUvcDevAttr.mUvcVideo_Fps = mCaptureParam.mUsbCam_CapFps; mUvcDevAttr.mUvcVideo_BufCnt = mCaptureParam.mUsbCam_CapBufCnt; Ret = AW_MPI_UVC_SetDeviceAttr((UVC_DEV)mUvcDev.c_str(), &mUvcDevAttr); if(Ret != SUCCESS) { aloge("the %s usbcamera device can not set device attr!", mUvcDev); return UNKNOWN_ERROR; } //get final UVC_ATTR_S. AW_MPI_UVC_GetDeviceAttr((UVC_DEV)mUvcDev.c_str(), &mUvcDevAttr); alogd("uvc capture final format[0x%x],[%dx%d],fps[%d]", mUvcDevAttr.mPixelformat, mUvcDevAttr.mUvcVideo_Width, mUvcDevAttr.mUvcVideo_Height, mUvcDevAttr.mUvcVideo_Fps); return NO_ERROR; } status_t EyeseeUSBCamera::openVdecDevice() { if(mUvcDevAttr.mPixelformat != UVC_MJPEG && mUvcDevAttr.mPixelformat != UVC_H264) { aloge("the %s usbcamera capture pixelformat do not support vdec!", mUvcDev); return INVALID_OPERATION; } if(mUvcDevAttr.mPixelformat == UVC_MJPEG) { mVdecChnAttr.mType = PT_MJPEG; } else if(mUvcDevAttr.mPixelformat == UVC_H264) { mVdecChnAttr.mType = PT_H264; } mVdecChnAttr.mBufSize = mVdecParam.mUsbCam_VdecBufSize; mVdecChnAttr.mPriority = mVdecParam.mUsbCam_VdecPriority; mVdecChnAttr.mPicWidth = mVdecParam.mUsbCam_VdecPicWidth; mVdecChnAttr.mPicHeight = mVdecParam.mUsbCam_VdecPicHeight; mVdecChnAttr.mInitRotation = mVdecParam.mUsbCam_VdecInitRotation; mVdecChnAttr.mOutputPixelFormat = mVdecParam.mUsbCam_VdecOutputPixelFormat; mVdecChnAttr.mExtraFrameNum = mVdecParam.mUsbCam_VdecExtraFrameNum; mVdecChnAttr.mVdecVideoAttr.mMode = VIDEO_MODE_FRAME; mVdecChnAttr.mVdecVideoAttr.mSupportBFrame = 1; mVdecChnAttr.mSubPicEnable = mVdecParam.mUsbCam_VdecSubPicEnable; mVdecChnAttr.mSubOutputPixelFormat = mVdecParam.mUsbCam_VdecSubOutputPixelFormat; if(mVdecChnAttr.mSubPicEnable) { if(mVdecParam.mUsbCam_VdecSubPicWidth > 0 && mVdecParam.mUsbCam_VdecSubPicHeight > 0) { // ratio = log2(Main / Sub) = (log10(Main)) / (log10(Sub)) : old version std C++ before C++11 // log2() : C++11 int SubRatio = ceil(log2(static_cast(mUvcDevAttr.mUvcVideo_Width) / mVdecParam.mUsbCam_VdecSubPicWidth)); mVdecChnAttr.mSubPicWidthRatio = decideMaxScaleRatio(SubRatio, mVdecChnAttr.mType); SubRatio = ceil(log2(static_cast(mUvcDevAttr.mUvcVideo_Height) / mVdecParam.mUsbCam_VdecSubPicHeight)); mVdecChnAttr.mSubPicHeightRatio = decideMaxScaleRatio(SubRatio, mVdecChnAttr.mType); if(mVdecChnAttr.mSubPicWidthRatio > mVdecChnAttr.mSubPicHeightRatio) { mVdecChnAttr.mSubPicHeightRatio = mVdecChnAttr.mSubPicWidthRatio; } else { mVdecChnAttr.mSubPicWidthRatio = mVdecChnAttr.mSubPicHeightRatio; } alogd("sub picture scale ratio w[%d]h[%d]", mVdecChnAttr.mSubPicWidthRatio, mVdecChnAttr.mSubPicHeightRatio); if(mVdecChnAttr.mSubPicWidthRatio <= 0) { alogd("Be careful! why VdecSubPicSize[%dx%d] < uvcVideoSize[%dx%d]", mVdecParam.mUsbCam_VdecSubPicWidth, mVdecParam.mUsbCam_VdecSubPicHeight, mUvcDevAttr.mUvcVideo_Width, mUvcDevAttr.mUvcVideo_Height); mVdecChnAttr.mSubPicEnable = FALSE; } } else { aloge("fatal error, the vdec subwidth[%d], subheight[%d]", mVdecParam.mUsbCam_VdecSubPicWidth, mVdecParam.mUsbCam_VdecSubPicHeight); mVdecChnAttr.mSubPicWidthRatio = 0; mVdecChnAttr.mSubPicHeightRatio = 0; mVdecChnAttr.mSubPicEnable = FALSE; } } else { mVdecChnAttr.mSubPicWidthRatio = 0; mVdecChnAttr.mSubPicHeightRatio = 0; } if(mVdecChnAttr.mSubPicEnable) { mbVdecSubOutputFlag = true; } else { mbVdecSubOutputFlag = false; } //verify param, make vencChnAttr picwidth and picHeight equal to vdec output buffer size. if(mVdecChnAttr.mSubPicEnable) { mVdecChnAttr.mPicWidth = mUvcDevAttr.mUvcVideo_Width; mVdecChnAttr.mPicHeight = mUvcDevAttr.mUvcVideo_Height; } else { if(0 == mVdecChnAttr.mPicWidth || 0 == mVdecChnAttr.mPicHeight) { mVdecChnAttr.mPicWidth = mUvcDevAttr.mUvcVideo_Width; mVdecChnAttr.mPicHeight = mUvcDevAttr.mUvcVideo_Height; } int SubRatioW = 0; if(mVdecChnAttr.mPicWidth < mUvcDevAttr.mUvcVideo_Width) { SubRatioW = ceil(log2(static_cast(mUvcDevAttr.mUvcVideo_Width)/mVdecChnAttr.mPicWidth)); } int SubRatioH = 0; if(mVdecChnAttr.mPicHeight < mUvcDevAttr.mUvcVideo_Height) { SubRatioH = ceil(log2(static_cast(mUvcDevAttr.mUvcVideo_Height)/mVdecChnAttr.mPicHeight)); } int SubRatio = SubRatioW>SubRatioH?SubRatioW:SubRatioH; mVdecChnAttr.mPicWidth = AWALIGN((unsigned int)ceil((float)mUvcDevAttr.mUvcVideo_Width/pow(2, SubRatio)), 32); mVdecChnAttr.mPicHeight = AWALIGN((unsigned int)ceil((float)mUvcDevAttr.mUvcVideo_Height/pow(2, SubRatio)), 32); } mVdecChn = 0; while(mVdecChn < VDEC_MAX_CHN_NUM) { int Ret = AW_MPI_VDEC_CreateChn(mVdecChn, &mVdecChnAttr); if(SUCCESS == Ret) { break; } else if(ERR_VDEC_EXIST == Ret) { mVdecChn++; } else { aloge("the %s usbcamera fail to create vdecchn[%d], 0x%x", mUvcDev, mVdecChn, Ret); mVdecChn++; } } if(VDEC_MAX_CHN_NUM == mVdecChn) { aloge("the %s usbcamera fail to create virchn.", mUvcDev); return UNKNOWN_ERROR; } //AW_MPI_VDEC_GetChnAttr(mVdecChn, &mVdecChnAttr); //feedback vdecattr MPPCallbackInfo cbInfo; cbInfo.cookie = (void*)this; cbInfo.callback = (MPPCallbackFuncType)&MPPVdecCallback; AW_MPI_VDEC_RegisterCallback(mVdecChn, &cbInfo); return NO_ERROR; } void EyeseeUSBCamera::clearConfig() { mCaptureParam.mpUsbCam_DevName.clear(); mCaptureParam.mUsbCam_CapPixelformat = UVC_YUY2; mCaptureParam.mUsbCam_CapWidth = 0; mCaptureParam.mUsbCam_CapHeight = 0; mCaptureParam.mUsbCam_CapFps = 0; mCaptureParam.mUsbCam_CapBufCnt = 0; mbCaptureFlag = false; mUvcDev = ""; memset(&mUvcDevAttr, 0, sizeof mUvcDevAttr); mVirtualUvcChnForVdec = MM_INVALID_CHN; mVdecParam.mUsbCam_VdecBufSize = 0; mVdecParam.mUsbCam_VdecPriority = 0; mVdecParam.mUsbCam_VdecPicWidth = 0; mVdecParam.mUsbCam_VdecPicHeight = 0; mVdecParam.mUsbCam_VdecInitRotation = ROTATE_NONE; mVdecParam.mUsbCam_VdecOutputPixelFormat = MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420; mVdecParam.mUsbCam_VdecSubPicEnable = false; mVdecParam.mUsbCam_VdecSubPicWidth = 0; mVdecParam.mUsbCam_VdecSubPicHeight = 0; mVdecParam.mUsbCam_VdecSubOutputPixelFormat = MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420; mVdecParam.mUsbCam_VdecExtraFrameNum = 0; mbVdecFlag = false; mbVdecSubOutputFlag = false; mVdecChn = MM_INVALID_CHN; memset(&mVdecChnAttr, 0, sizeof mVdecChnAttr); } ERRORTYPE EyeseeUSBCamera::MPPVdecCallback(void *cookie, MPP_CHN_S *pChn, MPP_EVENT_TYPE event, void *pEventData) { ERRORTYPE ret = SUCCESS; if(MOD_ID_VDEC != pChn->mModId) { aloge("fatal error! need implement!"); return ERR_VDEC_ILLEGAL_PARAM; } EyeseeUSBCamera *pCamera = (EyeseeUSBCamera*)cookie; switch(event) { case MPP_EVENT_VDEC_NOTIFY_NO_FRAME_BUFFER: { status_t eRet = pCamera->mpVdecFrameManager->VdecNotifyNoFrameBuffer(); if(eRet != NO_ERROR) { //alogd("Be careful! vdec frame manager has no frame to return!"); ret = ERR_VDEC_BUF_EMPTY; } else { ret = SUCCESS; } break; } default: { alogd("ignore event[0x%x] from channel[0x%x][0x%x][0x%x]!", event, pChn->mModId, pChn->mDevId, pChn->mChnId); break; } } return ret; } };