作者: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;
}