97干视频,99国产精品懂色,亚洲精品99久久久久中文字幕,伊人五月丁香综合AⅤ,国产精品成人免费999

  您的位置:華清遠見教育科技集團 >> 新聞動態(tài) >> Android資料 >> Android Camera的HAL接口  
 
Android Camera的HAL接口
分享到:

在Linux系統(tǒng)中,硬件平臺驅(qū)動,以及其他需要商業(yè)保護的部分通常都會通過HAL來封裝,在Aurora中也如此。

目前產(chǎn)業(yè)界的Camera傳感器主要有兩種類型:電荷耦合設備(CCD,Charge Couple Device)和互補金屬氧化物半導體(CMOS,Complementary Metal Oxide Semiconductor)。其中CCD主要應用在高檔的DC、DV和高檔移動終端上,圖像質(zhì)量較好,但驅(qū)動模組比較復雜;而CMOS則門檻較低,工藝更加成熟,成本較低,外圍電路也比較簡單,很多廠商已將驅(qū)動和信號處理的圖像信號處理器(ISP,Image Signal Processor)集成到驅(qū)動模組中。因此CMOS傳感器在移動終端中應用廣泛。如圖5-4所示為Camera進行圖像編碼的底層過程。


圖5-4 圖像編碼過程

與Camera傳感器通信,需涉及I2C驅(qū)動;進行文件保存,需涉及GPIO驅(qū)動和PMIC驅(qū)動;利用aDSP解碼,就需要用到VFE aDSP驅(qū)動。

在這些平臺驅(qū)動之上,在Android的較新版本中,通常會封裝一層HAL,可以為開發(fā)者提供更加抽象的接口,同時也可以保護硬件廠商的利益。

在Android中,為了實現(xiàn)Camera的HAL封裝,必須繼承CameraHardwareInterface.h定義的CameraHardwareInterface接口。

在Android原始代碼中,提供了CameraHardwareStub.cpp和QualcommCamera Hardware.cpp兩種實現(xiàn),CameraHardwareStub提供了基于模擬器的FakeCamera實現(xiàn)。QualcommCameraHardware實現(xiàn)了對真實物理設備的HAL封裝。下面首先介紹CameraHardwareStub的實現(xiàn)。

在CameraHardwareStub中,為了保證系統(tǒng)的流暢運行,在發(fā)起預覽時,會將Camera預覽放置在一個單獨的預覽線程CameraHardwareStub::previewThread()中,并在線程的事件循環(huán)中周期性調(diào)用previewThread,從底層提取數(shù)據(jù)。CameraHardwareStub::previewThread()的實現(xiàn)如下:

代碼5-4 預覽線程的事件循環(huán)處理

int CameraHardwareStub::previewThread()
    {
      mLock.lock();
      int previewFrameRate=mParameters.getPreviewFrameRate(); //幀速率
      ssize_t offset=mCurrentPreviewFrame * mPreviewFrameSize; //偏移量
      sp< MemoryHeapBase> heap=mPreviewHeap;
      FakeCamera* fakeCamera=mFakeCamera;
      sp< MemoryBase> buffer=mBuffers[mCurrentPreviewFrame]; //數(shù)據(jù)緩沖
      mLock.unlock();
      if (buffer != 0) {
      //計算幀延遲
      int delay=(int)(1000000.0f / float(previewFrameRate));
      void *base=heap->base();
      //用假數(shù)據(jù)填充當前幀
      uint8_t *frame=((uint8_t *)base) + offset;
      fakeCamera->getNextFrameAsYuv422(frame); //獲取數(shù)據(jù)緩沖
      //通知客戶端有新幀到來
      if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME)
      mDataCb(CAMERA_MSG_PREVIEW_FRAME, buffer, mCallbackCookie);
      mCurrentPreviewFrame=(mCurrentPreviewFrame + 1) % kBufferCount;
      usleep(delay);
      }
      return NO_ERROR;
    }

在CameraHardwareStub中,目前共有4個緩沖用于Camera數(shù)據(jù)的交替存放,這些數(shù)據(jù)被放置在一個名為mPreviewHeap的預覽內(nèi)存堆中。具體實現(xiàn)如下:

代碼5-5 Camera堆的初始化

void CameraHardwareStub::initHeapLocked()
    {
      int picture_width, picture_height;
      mParameters.getPictureSize(&picture_width, &picture_height);//拍攝大小
      //MMAP映射,存在拍攝時的原始數(shù)據(jù)
      mRawHeap=new MemoryHeapBase(picture_width * 2 * picture_height);
      int preview_width, preview_height;
      mParameters.getPreviewSize(&preview_width, &preview_height);//預覽大小
      LOGD("initHeapLocked: preview size=%dx%d", preview_width, preview_height);
      //強制設置為yuv422
      int how_big=preview_width * preview_height * 2;
      if (how_big==mPreviewFrameSize)
      return;
      mPreviewFrameSize=how_big;
      //構(gòu)建一個新MMAP堆用于進程間共享
      mPreviewHeap=new MemoryHeapBase(mPreviewFrameSize * kBufferCount);
      //為每幀都構(gòu)建一個IMemory
      for (int i=0; i < kBufferCount; i++) {
      mBuffers[i]=new MemoryBase(mPreviewHeap, i * mPreviewFrameSize, mPreviewFrameSize);
      }
      delete mFakeCamera;
      mFakeCamera=new FakeCamera(preview_width, preview_height);
    }

模擬器默認配置下,預覽分辨率為176×144像素,幀速率為15fps,預覽數(shù)據(jù)格式為YUV422 SP(僅支持),照片編碼格式為JPEG(僅支持)。

出于某種需求,需要將元數(shù)據(jù)格式Y(jié)UV422SP轉(zhuǎn)換為RGB565,yuv420sp2rgb.c文件給出的方法如下:

代碼5-6 YUV422sp轉(zhuǎn)換為RGB565的實現(xiàn)

static public void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {
    final int frameSize=width * height;
    for (int j=0, yp=0; j< height; j++) {
    int uvp=frameSize + (j>>1) * width, u=0, v=0;
    for (int i=0; i< width; i++, yp++) {
      int y=(0xff & ((int) yuv420sp[yp])) - 16;
      if (y< 0) y=0;
      if ((i & 1)==0) {
      v=(0xff & yuv420sp[uvp++]) - 128;
      u=(0xff & yuv420sp[uvp++]) - 128;
      }
      int y1192=1192 * y;
      int r=(y1192+1634 * v);
      int g=(y1192-833 * v-400*u);
      int b=(y1192+2066 * u);       if (r< 0) r=0; else if (r>262143) r=262143;
      if (g< 0) g=0; else if (g>262143) g=262143;
      if (b< 0) b=0; else if (b>262143) b=262143;
      rgb[yp]=0xff000000 | ((r<<6) & 0xff0000) | ((g>>2) & 0xff00) | ((b>>10) & 0xff);
        }
      }
    }

如果希望在預覽時就做這樣的轉(zhuǎn)換,編碼的轉(zhuǎn)換好放置在一個單獨的線程中處理。RGB565向YUV422SP的轉(zhuǎn)換參考FakeCamera.cpp文件。

在進行自動對焦和拍照時,CameraHardwareStub同樣會發(fā)起一個新的線程進行處理,相關(guān)的線程為autoFocusThread、pictureThread。在QualcommCameraHardware中,則沒有發(fā)起新線程進行處理。

在進行拍照時,為了向上層傳遞假圖片,CameraHardwareStub的處理方法如下:

代碼5-7 CameraHardwareStub拍攝照片的過程

int CameraHardwareStub::pictureThread()
    {
        if (mMsgEnabled & CAMERA_MSG_SHUTTER)
        mNotifyCb(CAMERA_MSG_SHUTTER,0,0,mCallbackCookie);
        if (mMsgEnabled & CAMERA_MSG_RAW_IMAGE) {
        int w,h;
        mParameters.getPictureSize(&w, &h);//獲得圖片大小
        sp< MemoryBase> mem=new MemoryBase(mRawHeap,0,w * 2 * h);
        FakeCamera cam(w,h);
        cam.getNextFrameAsYuv422((uint8_t *)mRawHeap->base());//獲取數(shù)據(jù)緩沖
        mDataCb(CAMERA_MSG_RAW_IMAGE, mem, mCallbackCookie);
      }
      if (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) {
        sp< MemoryHeapBase> heap=new MemoryHeapBase(kCannedJpegSize);
        sp< MemoryBase> mem=new MemoryBase(heap,0,kCannedJpegSize);
        memcpy(heap->base(),kCannedJpeg, kCannedJpegSize);//填充假圖片數(shù)據(jù)
        mDataCb(CAMERA_MSG_COMPRESSED_IMAGE,mem,mCallbackCookie);
      }
      return NO_ERROR;
    }

當然在真實終端環(huán)境下,基于CameraHardwareInterface的實現(xiàn)必須通過和Camera驅(qū)動進行通信來獲得真實數(shù)據(jù)。其實現(xiàn)和CameraHardwareStub存在著差異。下面為QualcommCameraHardware公開的JPEG編碼過程:

代碼5-8 QualcommCameraHardware編碼的過程

unsigned char QualcommCameraHardware::native_jpeg_encode (
    void *pDim,
    int pmemThumbnailfd,
    int pmemSnapshotfd,
    unsigned char *thumbnail_buf,
    unsigned char *main_img_buf, //存放拍攝的元數(shù)據(jù)緩沖
    void *pCrop)
    {
      char jpegFileName[256]={0};
      static int snapshotCntr=0;
      cam_ctrl_dimension_t *dimension=(cam_ctrl_dimension_t *)pDim;
      common_crop_t *cropInfo=(common_crop_t *)pCrop;
      sprintf(jpegFileName, "snapshot_%d.jpg", ++snapshotCntr);//獲得文件名
      #ifndef SURF8K
      LOGV("native_jpeg_encode , current jpeg main img quality =%d", mParameters.getJpeg MainimageQuality());
      //設置圖像質(zhì)量
      if (! LINK_jpeg_encoder_setMainImageQuality(mParameters.getJpegMainimageQuality()))
    {
      LOGE("native_jpeg_encode set jpeg main image quality :%d@%s: jpeg_encoder_encode failed.\n",__LINE__, __FILE__);
      return FALSE;
      }
      #endif
      //調(diào)用libmmcamera.so中的jpeg_encoder_encode進行解碼
      if ( !LINK_jpeg_encoder_encode(jpegFileName, dimension,thumbnail_buf, pmemThumbnailfd,main_img_buf, pmemSnapshotfd, cropInfo))
      {
      LOGV("native_jpeg_encode:%d@%s: jpeg_encoder_encode failed.\n", __LINE__, __FILE__);
      return FALSE;
      }
      return TRUE;
    }

在Qualcomm的實現(xiàn)中,底層的細節(jié)被封裝在名為libmmcamera.so和libmmcamera_ target.so的共享庫中,代碼并沒有公開。

 更多相關(guān)文章

·Android中Camera數(shù)據(jù)的處理
·Android Camera拍照源碼分析
·Android Camera原生服務架構(gòu)
·Android Camera錄像過程分析
·Android 原生層媒體播放過程