http://blog.youkuaiyun.com/tankai19880619/article/details/17120827
一、应用程序
1.Camera应用使用的参数对象
frameworks/base/core/java/android/hardware/Camera.java- public class Parameters {
- }
2.使用
Camera拍照预览:
packages/apps/Camera/src/com/android/camera/CameraModule.java
- mInitialParams = mCameraDevice.getParameters();
- mInitialParams.getSupportedPreviewSizes();
- mInitialParams.setPreviewSize(maxSize.width,maxSize.height);
- mInitialParams.setPictureSize(maxSize.width,maxSize.height);
- mCameraDevice.setParameters(mInitialParams);
packages/apps/Camera/src/com/android/camera/VideoModule.java
- InitialParams = vCameraDevice.getParameters();
- vInitialParams.getSupportedVideoSizes();
- mParameters.setPreviewSize();
- vCameraDevice.setParameters(mParameters);
二、MediaRecorder
1.CameraSource使用的参数对象frameworks/av/camera/CameraParameters.cpp
- void CameraParameters::getVideoSize(int *width, int *height) const{
- }
2.使用
frameworks/av/media/libstagefright/CameraSource.cpp
- status_t CameraSource::checkVideoSize(
- const CameraParameters& params,
- int32_t width, int32_t height) {
- params.getVideoSize(&frameWidthActual, &frameHeightActual);
- if (frameWidthActual != width || frameHeightActual != height) {
- ALOGE("Failed to set video frame size to %dx%d. " "The actual video size is %dx%d ", width, height, frameWidthActual, frameHeightActual);
- }
- }
1.CameraHAL使用的参数对象
frameworks/av/camera/CameraParameters.cpp2.使用
hardware/amlogic/camera/CameraHal.cpp
- int CameraHal::setParameters(const CameraParameters& params){
- //add by tank for CameraSource video recorder
- mParameters.setVideoSize(w,h);
- //end tan 2013-12-3
- // Handle RECORDING_HINT to Set/Reset Video Mode Parameters
- }
Android之Camera拍照
http://blog.youkuaiyun.com/tankai19880619/article/details/17147125
一、看看调用时序图
1.拍照命令时序图
2.拍照数据回调时序图
二、看看源码分析
hardware/amlogic/camera/CameraHal.cpp
- status_t CameraHal::takePicture( ){
- ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_IMAGE_CAPTURE, (int) &mStartCapture);
- }
调用父类方法:
hardware/amlogic/camera/BaseCameraAdapter.cpp
- status_t BaseCameraAdapter::sendCommand(CameraCommands operation, int value1, int value2, int value3){
- switch ( operation ) {
- case CameraAdapter::CAMERA_START_IMAGE_CAPTURE:
- ret = takePicture();
- }
- }
调用子类方法:
hardware/amlogic/camera/V4LCameraAdapter/V4LCameraAdapter.cpp
- status_t V4LCameraAdapter::takePicture(){
- if (createThread(beginPictureThread, this) == false)
- return -1;
- }
- /*static*/ int V4LCameraAdapter::beginPictureThread(void *cookie){
- V4LCameraAdapter *c = (V4LCameraAdapter *)cookie;
- return c->pictureThread();
- }
- int V4LCameraAdapter::pictureThread(){
- ret = sendFrameToSubscribers(&frame);
- }
调用父类方法:
hardware/amlogic/camera/BaseCameraAdapter.cpp
- status_t BaseCameraAdapter::sendFrameToSubscribers(CameraFrame *frame){
- ret = __sendFrameToSubscribers(frame, &mImageSubscribers, CameraFrame::IMAGE_FRAME);
- /*
- //如上callback的设置
- hardware/amlogic/camera/CameraHal.cpp
- status_t CameraHal::initialize(CameraProperties::Properties* properties){
- mAppCallbackNotifier->setEventProvider(eventMask, mCameraAdapter);
- mAppCallbackNotifier->setFrameProvider(mCameraAdapter);
- }
- hardware/amlogic/camera/AppCallbackNotifier.cpp
- void AppCallbackNotifier::setFrameProvider(FrameNotifier *frameNotifier){
- mFrameProvider = new FrameProvider(frameNotifier, this, frameCallbackRelay);
- mFrameProvider->enableFrameNotification(CameraFrame::IMAGE_FRAME);
- mFrameProvider->enableFrameNotification(CameraFrame::RAW_FRAME);
- }
- hardware/amlogic/camera/inc/CamerHal.h
- class FrameProvider{
- public:
- FrameProvider(FrameNotifier *fn, void* cookie, frame_callback frameCallback)
- :mFrameNotifier(fn), mCookie(cookie),mFrameCallback(frameCallback) { }
- }
- hardware/amlogic/camera/CameraHalUtilClasses.cpp
- int FrameProvider::enableFrameNotification(int32_t frameTypes){
- mFrameNotifier->enableMsgType(frameTypes<<MessageNotifier::FRAME_BIT_FIELD_POSITION
- , mFrameCallback
- , NULL
- , mCookie);
- }
- hardware/amlogic/camera/BaseCameraAdapter.cpp
- void BaseCameraAdapter::enableMsgType(int32_t msgs, frame_callback callback, event_callback eventCb, void* cookie){
- if ( CameraFrame::PREVIEW_FRAME_SYNC == msgs ){
- mFrameSubscribers.add((int) cookie, callback);
- }
- else if ( CameraFrame::IMAGE_FRAME == msgs){
- mImageSubscribers.add((int) cookie, callback);
- }
- else if ( CameraFrame::RAW_FRAME == msgs){
- mRawSubscribers.add((int) cookie, callback);
- }
- }
- //以下callback就是frameCallbackRelay
- //callbak-》subscribers-》mImageSubscribers-》mImageSubscribers.add((int) cookie, callback)-》mFrameCallback-》frameCallbackRelay
- */
- }
- status_t BaseCameraAdapter::__sendFrameToSubscribers(CameraFrame* frame,
- KeyedVector<int, frame_callback> *subscribers,
- CameraFrame::FrameType frameType){
- callback = (frame_callback) subscribers->valueAt(k);
- callback(frame);
- }
该回调函数即是:
hardware/amlogic/camera/AppCallbackNotifier.cpp
- void AppCallbackNotifier::frameCallbackRelay(CameraFrame* caFrame){
- appcbn->frameCallback(caFrame);
- }
- void AppCallbackNotifier::frameCallback(CameraFrame* caFrame){
- msg.command = AppCallbackNotifier::NOTIFIER_CMD_PROCESS_FRAME;
- msg.arg1 = frame;
- mFrameQ.put(&msg);
- }
- void AppCallbackNotifier::notifyFrame(){
- mFrameQ.get(&msg);
- sp<Encoder_libjpeg> encoder = new Encoder_libjpeg(main_jpeg, tn_jpeg,
- AppCallbackNotifierEncoderCallback,
- (CameraFrame::FrameType)frame->mFrameType,
- this,raw_picture,exif_data);
- }
补充——拍照是声音的回调如下:
frameworks/av/services/camera/libcameraservice/CameraClient.cpp
- void CameraClient::handleShutter(void) {
- mCameraService->playSound(CameraService::SOUND_SHUTTER);
- }
- //mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/system/media/audio/ui/camera_click.ogg");
- void CameraService::playSound(sound_kind kind) {
- }
frameworks/base/data/sounds/OriginalAudio.mk
- $(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg
frameworks/base/data/sounds/effects/camera_click.ogg
三、项目问题
拍照后,应用程序不调用startPreview导致预览界面不再刷新:
1.看看预览部分CameraHAL的处理
hardware/amlogic/camera/V4LCameraAdapter/V4LCameraAdapter.cpp
- int V4LCameraAdapter::previewThread(){
- frame.mFrameMask |= CameraFrame::PREVIEW_FRAME_SYNC;
- ret = sendFrameToSubscribers(&frame);
- }
- status_t BaseCameraAdapter::sendFrameToSubscribers(CameraFrame *frame){
- ret = __sendFrameToSubscribers(frame, &mFrameSubscribers, CameraFrame::PREVIEW_FRAME_SYNC);
- }
- status_t BaseCameraAdapter::__sendFrameToSubscribers(CameraFrame* frame,
- KeyedVector<int, frame_callback> *subscribers,
- CameraFrame::FrameType frameType){
- while(k<subscribers->size()){
- callback = (frame_callback) subscribers->valueAt(k);
- for(uint32_t i = 0; i<subscribers_ref.size();i++){
- if((frame->mCookie == ( void * ) subscribers_ref.keyAt(i))&&(subscribers_ref.valueAt(i) == 0)){
- subscribers_ref.replaceValueFor((uint32_t)frame->mCookie,1);
- //CAMHAL_LOGDB("Frame callbback is available, cookie:0x%x, callback:0x%x",(uint32_t)frame->mCookie,(uint32_t)callback);
- callback(frame);
- k = 0;
- is_find = true;
- break;
- }
- }
- }
- /*
- //如上callback的设置
- hardware/amlogic/camera/CameraHal.cpp
- //设置APP回调函数
- status_t CameraHal::initialize(CameraProperties::Properties* properties){
- mAppCallbackNotifier->setEventProvider(eventMask, mCameraAdapter);
- mAppCallbackNotifier->setFrameProvider(mCameraAdapter);
- }
- //设置刷屏回调函数
- status_t CameraHal::setPreviewWindow(struct preview_stream_ops *window){
- mDisplayAdapter->setFrameProvider(mCameraAdapter);
- mDisplayAdapter->setErrorHandler(mAppCallbackNotifier.get());
- ret = mDisplayAdapter->setPreviewWindow(window);
- }
- status_t CameraHal::startPreview(){
- ret = mDisplayAdapter->enableDisplay(width, height, NULL, isS3d ? &s3dParams : NULL);
- }
- //设置APP回调函数
- hardware/amlogic/camera/AppCallbackNotifier.cpp
- void AppCallbackNotifier::setFrameProvider(FrameNotifier *frameNotifier){
- mFrameProvider = new FrameProvider(frameNotifier, this, frameCallbackRelay);
- mFrameProvider->enableFrameNotification(CameraFrame::IMAGE_FRAME);
- mFrameProvider->enableFrameNotification(CameraFrame::RAW_FRAME);
- }
- //设置刷屏回调函数
- hardware/amlogic/camera/ANativeWindowDisplayAdapter.cpp
- int ANativeWindowDisplayAdapter::setFrameProvider(FrameNotifier *frameProvider){
- mFrameProvider = new FrameProvider(frameProvider, this, frameCallbackRelay);
- }
- int ANativeWindowDisplayAdapter::enableDisplay(int width, int height, struct timeval *refTime, S3DParameters *s3dParams){
- mFrameProvider->enableFrameNotification(CameraFrame::PREVIEW_FRAME_SYNC);
- }
- //最终设置地方
- hardware/amlogic/camera/inc/CamerHal.h
- class FrameProvider{
- public:
- FrameProvider(FrameNotifier *fn, void* cookie, frame_callback frameCallback)
- :mFrameNotifier(fn), mCookie(cookie),mFrameCallback(frameCallback) { }
- }
- hardware/amlogic/camera/CameraHalUtilClasses.cpp
- int FrameProvider::enableFrameNotification(int32_t frameTypes){
- mFrameNotifier->enableMsgType(frameTypes<<MessageNotifier::FRAME_BIT_FIELD_POSITION
- , mFrameCallback
- , NULL
- , mCookie);
- }
- hardware/amlogic/camera/BaseCameraAdapter.cpp
- void BaseCameraAdapter::enableMsgType(int32_t msgs, frame_callback callback, event_callback eventCb, void* cookie){
- if ( CameraFrame::PREVIEW_FRAME_SYNC == msgs ){
- mFrameSubscribers.add((int) cookie, callback);
- }
- else if ( CameraFrame::IMAGE_FRAME == msgs){
- mImageSubscribers.add((int) cookie, callback);
- }
- else if ( CameraFrame::RAW_FRAME == msgs){
- mRawSubscribers.add((int) cookie, callback);
- }
- }
- */
如上callback即是ANativeWindowDisplayAdapter.cpp/AppCallbackNotifier.cpp中的frameCallbackRelay,我们分析预览画面只需要关心ANativeWindowDisplayAdapter.cpp(AppCallbackNotifier.cpp是例如拍照和录像,需要将数据送给APP):
hardware/amlogic/camera/ANativeWindowDisplayAdapter.cpp- void ANativeWindowDisplayAdapter::frameCallbackRelay(CameraFrame* caFrame){
- da->frameCallback(caFrame);
- }
- void ANativeWindowDisplayAdapter::frameCallback(CameraFrame* caFrame){
- PostFrame(df);
- }
- status_t ANativeWindowDisplayAdapter::PostFrame(ANativeWindowDisplayAdapter::DisplayFrame &dispFrame){
- LOGD("TK----->>>>mPaused is %d\n",mPaused);//add by tankai
- if ( mDisplayState == ANativeWindowDisplayAdapter::DISPLAY_STARTED &&
- (!mPaused || CameraFrame::CameraFrame::SNAPSHOT_FRAME == dispFrame.mType) &&
- !mSuspend){
- ret = mANativeWindow->enqueue_buffer(mANativeWindow, mBufferHandleMap[i]);
- mFramesWithCameraAdapterMap.removeItem((int) dispFrame.mBuffer);
- }
- else{
- ret = mANativeWindow->cancel_buffer(mANativeWindow, mBufferHandleMap[i]);
- mFramesWithCameraAdapterMap.removeItem((int) dispFrame.mBuffer);
- }
- }
从如上可以看出:mPaused为true表示暂停刷屏,mPaused为false表示开始刷屏;我们的问题就出在这里。
hardware/camera/CameraHal.cpp- status_t CameraHal::startPreview(){
- if( (mDisplayAdapter.get() != NULL) && ( !mPreviewEnabled ) && ( mDisplayPaused ) ){
- CAMHAL_LOGDA("Preview is in paused state");
- mDisplayPaused = false;
- mPreviewEnabled = true;
- if ( NO_ERROR == ret ){
- ret = mDisplayAdapter->pauseDisplay(mDisplayPaused); //重新开始预览
- /*
- hardware/amlogic/camera/ANativeWindowDisplayAdapter.cpp
- status_t ANativeWindowDisplayAdapter::pauseDisplay(bool pause){
- mPaused = pause;
- }
- */
- if ( NO_ERROR != ret ){
- CAMHAL_LOGEB("Display adapter resume failed %x", ret);
- }
- }
- //restart preview callbacks
- if(mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME){
- mAppCallbackNotifier->enableMsgType (CAMERA_MSG_PREVIEW_FRAME);
- }
- return ret;
- }
- }
- //拍照时将mPaused置为false,暂停刷屏:
- status_t CameraHal::takePicture( ){
- if (NO_ERROR == ret &&
- NULL != mDisplayAdapter.get() && burst < 1) {
- if (mCameraAdapter->getState() != CameraAdapter::VIDEO_STATE) {
- mDisplayPaused = true;
- mPreviewEnabled = false;
- ret = mDisplayAdapter->pauseDisplay(mDisplayPaused); //暂停预览
- /*
- hardware/amlogic/camera/ANativeWindowDisplayAdapter.cpp
- status_t ANativeWindowDisplayAdapter::pauseDisplay(bool pause){
- mPaused = pause;
- }
- */
- // since preview is paused we should stop sending preview frames too
- if(mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME) {
- mAppCallbackNotifier->disableMsgType (mMsgEnabled & CAMERA_MSG_POSTVIEW_FRAME);
- CAMHAL_LOGDA("disable MSG_PREVIEW_FRAME");
- }
- }
- #if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS
- mDisplayAdapter->setSnapshotTimeRef(&mStartCapture);
- #endif
- }
- }
应用层在take_picture之后主动调用startpreview将mPaused改为false;
如果不需要应用主动调用,则需要在HAL将startpreview设为false。
Android之Camera预览过程中插拔摄像头节点后移
http://blog.youkuaiyun.com/tankai19880619/article/details/17259257
现象:
在使用Camera Preview时;热插拔摄像头会导致设备节点由/dev/video0变为/dev/video1,或者插入多个video设备时,会变为/dev/video1、/dev/video2......。
一、首先看设备节点的创建
drivers/media/video/uvc/uvc_driver.c
- static int uvc_probe(struct usb_interface *intf,
- const struct usb_device_id *id){
- if (v4l2_device_register(&intf->dev, &dev->vdev) < 0)
- goto error;
- }
drivers/media/video/v4l2-devices.c
- int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)
- {
- err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, sd->owner);
- }
drivers/media/video/v4l2-dev.c
- int __video_register_device(struct video_device *vdev, int type, int nr,
- int warn_if_nr_in_use, struct module *owner){
- int nr = -1; int minor_cnt = 64;
- nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt); //设备节点名,即“/dev/video*”
- vdev->num = nr;
- devnode_set(vdev); //该vdev->numd对应的符号被置为1
- /*
- devnode_set(vdev); //该vdev->numd对应的符号被置为1
- devnode_clear(vdev); //该vdev->numd对应的符号被置为0
- */
- name_base = "video";
- dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
- ret = device_register(&vdev->dev);
- vdev->dev.release = v4l2_device_release; //该接口会调用devnode_clear(vdev)
- }
二、问题解决
最终修改,问题解决:
drivers/media/video/uvc/uvc_driver.c
- static void uvc_disconnect(struct usb_interface *intf){
- uvc_unregister_video(dev);
- }
- static void uvc_unregister_video(struct uvc_device *dev){
- video_unregister_device(stream->vdev); //修改该接口函数
- if (atomic_dec_and_test(&dev->nstreams)){ //这里也有些问题,但不是根本原因
- uvc_delete(dev);
- }
- }
我的修改:
drivers/media/video/v4l2-dev.c
- void video_unregister_device(struct video_device *vdev){
- devnode_clear(vdev);//add by tankai
- device_unregister(&vdev->dev); //该接口本身会调用v4l2_device_release,但却没有
- }
1.这是一个网友在HAL层的解决办法
http://blog.youkuaiyun.com/rachel_rq/article/details/7545332
2.我们在HAL的解决办法
hardware/amlogic/camera/AppCallbackNotifier.cpp
- //All sub-components of Camera HAL call this whenever any error happens
- void AppCallbackNotifier::errorNotify(int error)
- {
- LOG_FUNCTION_NAME;
- CAMHAL_LOGEB("AppCallbackNotifier received error %d", error);
- // If it is a fatal error abort here!
- if((error == CAMERA_ERROR_FATAL) || (error == CAMERA_ERROR_HARD)) {
- //We kill media server if we encounter these errors as there is
- //no point continuing and apps also don't handle errors other
- //than media server death always.
- abort();
- return;
- }
- if ( ( NULL != mCameraHal ) &&
- ( NULL != mNotifyCb ) &&
- ( mCameraHal->msgTypeEnabled(CAMERA_MSG_ERROR) ) )
- {
- CAMHAL_LOGEB("AppCallbackNotifier mNotifyCb %d", error);
- mNotifyCb(CAMERA_MSG_ERROR, CAMERA_ERROR_UNKNOWN, 0, mCallbackCookie);
- mCameraHal->release(); //add by tankai
- }
- LOG_FUNCTION_NAME_EXIT;
- }