• 【讨论】为什么我的300W摄像头偶尔会拍照不成功?


      作者:gooogleman 平台:OK2440/TE2440(wince5.0) 日期:2010-12-21

      经过一番折腾,P通道预览,C通道保存拍照图片的功能是实现了,并且采用了飞凌2440 摄像头驱动动态分配DMA的办法,这样大大节省了内存,可是郁闷的是有很多时间拍照不会产生图片,可是采用静态分配DMA的方式却可以每次都保存一个图片,为什么呢?我记得以前没有用C通道保存大分辨率图片的时候都会这样的,只是一直没有理会,现在这个摄像头快收工了却发生了这样的事情,真是太邪乎了,咋办呢?只能老老实实比较代码呗。应用并没有差异,主要是驱动看上去有点玄机。下面贴出来一起瞧瞧。

    拍照正常的


    //=============================================================================
    //  数据处理线程IST
    //
    //=============================================================================
    DWORD CameraCaptureThread(void)
    {
     unsigned char tmp=0;
     static unsigned int time,old_time;
     static unsigned int cam_intr;

     
     RETAILMSG(1, (TEXT("CameraCaptureThread funtion run test!!!\r\n")));
     while(1)
     {
      
            //RETAILMSG(1, (TEXT(" Camera interrupt.....before WaitForSingleObject\r\n")));
      WaitForSingleObject(CameraEvent, DisplayTime);
      
            //RETAILMSG(1, (TEXT(" Camera interrupt.....after WaitForSingleObject\r\n")));
      
      //RETAILMSG(MSG_EN_1,(_T("CameraCaptureThread(%d)++\r\n"), frame_count));

      //RETAILMSG(1,(_T("CameraCaptureThread(%d)++\r\n"), frame_count));

    #if 0
      if (frame_count <= 2) {
       frame_count++;
       // Enable camera interrupt
       s2440INT->rINTSUBMSK &= ~(BIT_SUB_CAM_P|BIT_SUB_CAM_C);
       s2440INT->rINTMSK &= ~BIT_CAM;
       
       continue;
      }
    #endif
      
      //if( DisplayEnable )
      {

       frame_count++;

       if (s2440INT->rINTSUBMSK & BIT_SUB_CAM_C)
       {
        cam_intr = BIT_SUB_CAM_C;
        //RETAILMSG(1,(_T("CAM_C, ts %d\r\n"), GetTickCount()));
       }
       
       if (s2440INT->rINTSUBMSK & BIT_SUB_CAM_P)
       {
        cam_intr = BIT_SUB_CAM_P;
        //RETAILMSG(1,(_T("CAM_P, ts %d\r\n"), GetTickCount()));
       }
       
       
       // EINT20 to measure time
    //   s2440IOP->rGPGDAT |= (1<<12);
    //   time = GetTickCount();
    //   RETAILMSG(1,(TEXT("+time:%d\r\n"),(time - old_time)));

       // delay for capture
       //Sleep(CAPTURE_TIME);   // polling mode

                         //liudiping
       // display the image 
       //if ((DRIVER_PREVIEW_ENABLE == 1) & (cam_intr == BIT_SUB_CAM_P))
       {
        //RETAILMSG(1,(TEXT("-------------------\r\n")));
        //Display_Cam_Image(64, 64, QCIF_XSIZE, QCIF_YSIZE, PORT_A);
        Display_Cam_Image(0,0, 240, 240, PORT_A);
       }

       //else if (DRIVER_PREVIEW_ENABLE == 2) 
       if (cam_intr == BIT_SUB_CAM_C)
       {
        RETAILMSG(1, (TEXT(" Camera interrupt.....BIT_SUB_CAM_C@@@@")));
        Buffer_codec_info_update();
       }

       if (cam_intr == BIT_SUB_CAM_P)//RGB格式使用的是P通道
       {
        RETAILMSG(1, (TEXT(" Camera interrupt.....BIT_SUB_CAM_P@@@@")));
        Buffer_preview_info_update();
       }

       // add by wogo at 2009.04.25
       s2440INT->rSUBSRCPND = INTSUB_CAM_P;
       s2440INT->rSUBSRCPND = INTSUB_CAM_C;
       s2440INT->rSRCPND = BIT_CAM;

       if (s2440INT->rINTPND & BIT_CAM)
       {
        s2440INT->rINTPND = BIT_CAM;
       }
       s2440INT->rINTSUBMSK &= ~(INTSUB_CAM_P | INTSUB_CAM_C);
       s2440INT->rINTMSK &= ~BIT_CAM;
       RETAILMSG(1,(TEXT("::: SYSINTR_CAM    OEMInterruptDone\r\n")));
        
       // Enable camera interrupt
       s2440INT->rINTSUBMSK &= ~(BIT_SUB_CAM_P | BIT_SUB_CAM_C);
       s2440INT->rINTMSK &= ~BIT_CAM;

        //RETAILMSG(1, (TEXT(" Camera interrupt.....Done@@@@")));
    /*
       if (DRIVER_PREVIEW_ENABLE == 1)
        Camif_Capture(CAPTURE_ON, CAPTURE_OFF);
       else if (DRIVER_PREVIEW_ENABLE == 2) 
        Camif_Capture(CAPTURE_OFF, CAPTURE_ON);
    */
       
       // EINT20 to measure time   
    //   s2440IOP->rGPGDAT &= ~(1<<12);
    //   old_time = GetTickCount();
    //   RETAILMSG(1,(TEXT("-time:%d\r\n"),(old_time-time)));
       
      }
     }
    }

    ----------------------------------------------------------------------------------------

    拍照偶尔不能生成图片的

    //摄像头中断线程
    /*
    等待中断事件。

    确认有一个来自 OS 的脉动性事件

    执行任何必要的板级中断处理以完成中断。在该示例中,我们将确认该中断。

    在尽可能短的时间内处理该中断

    创建 CELOGDATA 以供在 Kernel Tracker 中查看。

    检查并确认是否设置了 g_fPRRunning 标志,然后设置 g_hevPRStart 事件。

    调用 InterruptDone()。

    在调用 InterruptDone 之前,OS 不会提供此 IRQ 上的其他中断。

    再次等待中断事件
    */
    DWORD CameraCaptureThread(void)
    {
     unsigned char tmp=0;
     static unsigned int time,old_time;
     static unsigned int cam_intr;
     
     while(1)
     {
      WaitForSingleObject(CameraEvent, dwDisplayTimeout);//等待中断
      
      
     // RETAILMSG(1,(_T("CameraCaptureThread(%d)++\r\n"), frame_count));

    #if 0
      if (frame_count <= 2) {
       frame_count++;
       // Enable camera interrupt 使能摄像头中断
       s2440INT->rINTSUBMSK &= ~(BIT_SUB_CAM_P|BIT_SUB_CAM_C);
       s2440INT->rINTMSK &= ~BIT_CAM;
       
       continue;
      }
    #endif
      

      Lock();// {EnterCriticalSection(&m_Lock);}

      __try
      {

       if (s2440INT->INTSUBMSK & ( 1 << IRQ_SUB_CAM_C )) //决定IRQ_SUB_CAM_C位中断请求是否被处理,若某位被设置为1,则该位相对应的中断产生后将被忽略(CPU不处理该中断请求)
       {
        frame_count++;
        cam_intr |= ( 1 << IRQ_SUB_CAM_C );  //(1<<11)
          
        s2440INT->SUBSRCPND  =  (1<<IRQ_SUB_CAM_C);//IRQ_SUB_CAM_P中断请求  该中断请求将被处理
        s2440INT->INTSUBMSK &= ~(1<<IRQ_SUB_CAM_C);//设置为0则对其进行中断处理
        //RETAILMSG(1,(_T("CAM_C, ts %d\r\n"), GetTickCount()));//GetTickCount()函数,该函数的返回值是DWORD型,表示以毫秒为单位的计算机启动后经历的时间间隔
       }

       if (s2440INT->INTSUBMSK & ( 1 << IRQ_SUB_CAM_P ))//判断是IRQ_SUB_CAM_P中断
       {
        cam_intr |= ( 1 << IRQ_SUB_CAM_P );
        
        s2440INT->SUBSRCPND  =  (1<<IRQ_SUB_CAM_P);//IRQ_SUB_CAM_P中断请求  该中断请求将被处理
        s2440INT->INTSUBMSK &= ~(1<<IRQ_SUB_CAM_P);
         //RETAILMSG(1,(_T("CAM_P, ts %d\r\n"), GetTickCount()));
       }
       
       InterruptDone(g_CamSysIntr);  //标识中断处理完成  
      
       //time = GetTickCount();
       //RETAILMSG(1,(TEXT("+time:%d\r\n"),(time - old_time)));

       // Handle any interrupts on the input source
       if (cam_intr & ( 1 << IRQ_SUB_CAM_P ))
       {
        // display the image 
        if (DisplayEnable== 1)
        Display_Cam_Image(sDISINFO.pos_x,sDISINFO.pos_y,sDISINFO.dis_x, sDISINFO.dis_y, PORT_A);//刷新显示

        Buffer_preview_info_update();//刷新预览 RGB
        cam_intr &= ~( 1 << IRQ_SUB_CAM_P );
       }
        
       if (cam_intr & ( 1 << IRQ_SUB_CAM_C ))
       {
        Buffer_codec_info_update();  //YCbCr
        cam_intr &= ~( 1 << IRQ_SUB_CAM_C );
       }


      }
      __except(EXCEPTION_EXECUTE_HANDLER)
      {
       RETAILMSG(PM_MSG, (TEXT("Camera.DLL:InterruptThread() - EXCEPTION: %d"), GetExceptionCode()));
      }
        
      Unlock();
       
      // Enable camera interrupt
      //s2440INT->rINTSUBMSK &= ~(BIT_SUB_CAM_P|BIT_SUB_CAM_C);
      //s2440INT->rINTMSK &= ~BIT_CAM;

     }
     return 0;
    }

    CRITICAL_SECTION m_Lock;

    void Lock()   {EnterCriticalSection(&m_Lock);}
    void Unlock() {LeaveCriticalSection(&m_Lock);}

      细心的人一定会发现,这两个函数有两个比较大的差别,那就是Lock()和 Unlock()函数这两个函数是临界段相关函数,直觉告诉我,极有可能是这个问题,因为这是最玄乎的OS东西,删掉试试看。

      应用程序拍照函数

    //拍照
    void COV9650Dlg::Onpaizhao()
    {
     // TODO: Add your control notification handler code here
     //PINGPONG_PR image;
     PINGPONG YUVData;
     //
     
     int i;
     
     //WORD width=GetSystemMetrics(SM_CXSCREEN);
     //WORD height=GetSystemMetrics(SM_CYSCREEN);
     int width;
     int height;
     int line, col;
     BOOL ret;
     if(count==2)
     {
       
      width=1024;
      height=768;
     }
     if(count==3)
     {
      width=640;
      height=480; 
      
     }
     if(count==4)
     {
      width=800;
      height=600; 
      
     }
     
     
     
     //BYTE* DDBdata=new BYTE[width*height*2];
     //BYTE* DDBdata=NULL;
     //BYTE*  DDBdata=new BYTE[width*height*2];
     BYTE* DIBdata=NULL;
     U16*  DDBdata=new U16[width*height];

     //U16*  TempDDBdata=new U16[width*height*2];
     //
     //bufferYUV--width*height for Y data;width*height/4 for U and V data
     //
     BYTE* bufferYUV=new BYTE[width*height+width*height/4+width*height/4];
     
     //BYTE* YData=new BYTE[width*height];
     //BYTE* CbData=new BYTE[width*height];
     //BYTE* CrData=new BYTE[width*height];

     //
     //BYTE* RData=new BYTE[width*height*2];
     //BYTE* GData=new BYTE[width*height*2];
     //BYTE* BData=new BYTE[width*height*2];

     //------------2010.10.26--------------
     //
     //U16* RData=new U16[width*height];
     //U16* GData=new U16[width*height];
     //U16* BData=new U16[width*height];
     //
     //unsigned int RData[width*height*2];
     //unsigned int GData[width*height*2];
     //unsigned int BData[width*height*2];

     
     // always uses P port to get pictrue //获得最新1帧的RGB图像
     // ret=DeviceIoControl(m_hled,CAM_IOCTL_SAMSUNG_CAM_PR,NULL,NULL,(PBYTE)&image,NULL,NULL,NULL);
     // now try to use C port to get YUV data then change into RGB data
     ret=DeviceIoControl(m_hled,CAM_IOCTL_SAMSUNG_CAM,NULL,NULL,(PBYTE)&YUVData,NULL,NULL,NULL);
     if(!ret)
      AfxMessageBox(_T("读取图片失败!"));
     else
     {
      SetKMode(TRUE);

      RETAILMSG(1,(_T("test before memcpy(bufferYUV\r\n")));
      //memcpy(DDBdata,(void *)image.rgb_address,width*height*2);
      //2010.09.29
      memcpy(bufferYUV,(void *)YUVData.y_address,width*height);
      // just use Y
      RETAILMSG(1,(_T("test before memcpy((bufferYUV+width*height)\r\n")));
      memcpy((bufferYUV+width*height),(void *)YUVData.cb_address,width*height/4);
      RETAILMSG(1,(_T("test before memcpy((bufferYUV+width*height+width*height/4)\r\n")));
      memcpy((bufferYUV+width*height+width*height/4),(void *)YUVData.cr_address,width*height/4);

      RETAILMSG(1,(_T("test after memcpy\r\n")));
      SetKMode(FALSE);
      
      //
      //-----------Oh,My god!I make wrong thing--------2010.10.12-----------
      //
      // void yuv420_to_rgb565(int width, int height, unsigned char *src, unsigned short *dst)
      RETAILMSG(1,(_T("test before yuv420_to_rgb565\r\n")));
      yuv420_to_rgb565(width,height,bufferYUV, DDBdata);
      RETAILMSG(1,(_T("test after yuv420_to_rgb565\r\n")));

      //DDBdata=(BYTE*)TempDDBdata;
      // 2010.10.25
      //memcpy(DDBdata,(void *)TempDDBdata,width*height*2);

      CBitmap bitmap;//图片
      HBITMAP dstBmp;
      bitmap.CreateBitmap(width,height,1,16,DDBdata);//创建一张位图
      HDC hdcSrc = CreateCompatibleDC(NULL);
      HDC hdcDst = CreateCompatibleDC(NULL);
       BITMAPINFOHEADER   bih   =   {0};//位图信息头  
             bih.biBitCount   =   16;//每个像素字节大小  
             bih.biCompression   =   BI_RGB;  
             bih.biHeight   =   height;//高度  
             bih.biPlanes   =   1;  
             bih.biSize   =   sizeof(BITMAPINFOHEADER);  
             bih.biSizeImage   =  0;// width*height*2;//图像数据大小  
             bih.biWidth   =   width;//宽度  
             BITMAPFILEHEADER   bfh   =   {0};//位图文件头  
             bfh.bfOffBits   =   sizeof(BITMAPFILEHEADER)   +   sizeof(BITMAPINFOHEADER);//到位图数据的偏移量  
             bfh.bfSize   =   bfh.bfOffBits + width*height*2;//文件总的大小  
             bfh.bfType   =   (WORD)0x4d42;   //,0x4d42就是"BM",以这个表示该文件为位图文件
       BITMAPINFO bi={0};
       bi.bmiHeader=bih;
      dstBmp=CreateDIBSection(hdcDst, (BITMAPINFO*)&bi, DIB_RGB_COLORS, (void **)&DIBdata, NULL, 0);
      SelectObject(hdcDst, dstBmp);
      SelectObject(hdcSrc, bitmap);
      BitBlt(hdcDst, 0, 0, width, height, hdcSrc, 0, 0, SRCCOPY);//将位图复制到实际的设备环境中
      CFile file(_T("Image.bmp"),CFile::modeCreate|CFile::modeReadWrite);
      file.Write(&bfh,sizeof(bfh));
      file.Write(&bih,sizeof(bih));
      file.Write(DIBdata,width*height*2);
      file.Close();
     
     }
     delete []DDBdata;
     //2010.10.25
     //delete []TempDDBdata;
     // 2010.11.04 YUV
     delete []bufferYUV;
     
    }

  • 相关阅读:
    转:用十条命令在一分钟内检查Linux服务器性能
    android适配的努力
    转: Android Studio你不知道的调试技巧
    编码处理过滤器
    PageBean分页组件
    BaseServlet方法分发
    SQLHelper、DBUtil终极封装
    JavaEE面试题库
    Servlet、JSP选择题(2)
    Servlet、JSP选择题
  • 原文地址:https://www.cnblogs.com/gooogleman/p/1912412.html
Copyright © 2020-2023  润新知