现在的位置: 首页 > 综合 > 正文

gspca在arm平台上的开发详解

2014年09月05日 ⁄ 综合 ⁄ 共 8122字 ⁄ 字号 评论关闭

gspca在arm平台上的开发详解

在上一篇中笔者介绍了gspca在arm平台上的移植过程,如有不清楚的可以再仔细研究一下:

http://blog.suraid.cn/index.php/2008/09/gspca-arm-compile/

这一篇中,笔者将结合中星微的zc301p芯片摄像头,带你走进gspca的源码世界!

 

 

笔者建议使用Source Insight这款软件来阅读代码,能够提高不少的工作效率。

进入gspca文件夹,我们可以看到目录结构如下:

      
│  changelog
│  cutlog.py
│  gspca.h
│  gspca_build
│  gspca_core.c
│  license
│  Makefile
│  Makefile.kld
│  READ_AND_INSTALL

├─Conexant
│      cx11646.h
│      cxlib.h

├─decoder
│      gspcadecoder-OSX.c
│      gspcadecoder-OSX.h
│      gspcadecoder.c
│      gspcadecoder.h

├─Etoms
│      et61xx51.h

├─Mars-Semi
│      mr97311.h

├─Pixart
│      pac207-OSX.h
│      pac207.h
│      pac7311.h

├─Sonix
│      sn9cxxx.h
│      sonix.h

├─Sunplus
│      spca501.dat
│      spca501_init-OSX.h
│      spca501_init.h
│      spca505.dat
│      spca505_init.h
│      spca506.h
│      spca508.dat
│      spca508_init-OSX.h
│      spca508_init.h
│      spca561-OSX.h
│      spca561.h

├─Sunplus-jpeg
│      jpeg_qtables.h
│      sp5xxfw2.dat
│      sp5xxfw2.h
│      spca500.dat
│      spca500_init.h

├─Transvision
│      tv8532.h

├─utils
│      spcaCompat.h
│      spcagamma.h
│      spcausb.h

└─Vimicro
        cs2102.h
        hdcs2020.h
        hv7131b.h
        hv7131c.h
        icm105a.h
        mc501cb.h
        ov7620.h
        ov7630c.h
        pas106b.h
        pb0330.h
        tas5130c.h
        tas5130c_vf0250.h
        vc032x.h
        vc032x_sensor.h
        zc3xx.h

 

根目录下的源代码文件主要有两个:gspca.h和gspca_core.c。

gspca.h这个头文件主要是基于SPCA50x的,定义了一些图片信息,传感器信息,和主要的结构体信息。

gspca_core.c,看名字就知道这个文件很核心很重要,没错,这个文件就是驱动程序的主要接口,gspca是基于USB摄像头驱动的,所以你会看到usb_register,usb_deregister等字样。最后在这个文件中和我们有点关系的就数带有list字样的结构体了,它们定义了gspca支持的所有的摄像头名称,让我们来找找中星微的这款芯片啊~

static struct cam_list clist[] = {
    {UnknownCamera, “Unknown”},
    {IntelPCCameraPro, “Intel PC Camera Pro”},
    {IntelCreateAndShare, “Intel Create and Share”},
    {GrandtecVcap, “Grandtec V.cap”},
    {ViewQuestM318B, “ViewQuest M318B”},
    {ViewQuestVQ110, “ViewQuest VQ110″},
    {KodakDVC325, “Kodak DVC-325″},
    {MustekGsmartMini2, “Mustek gSmart mini 2″},
    {MustekGsmartMini3, “Mustek gSmart mini 3″},
    {CreativePCCam300, “Creative PC-CAM 300″},
    {DLinkDSC350, “D-Link DSC-350″},
    {CreativePCCam600, “Creative PC-CAM 600″},
    {IntelPocketPCCamera, “Intel Pocket PC Camera”},
    {IntelEasyPCCamera, “Intel Easy PC Camera”},
    {ThreeComHomeConnectLite, “3Com Home Connect Lite”},
    {KodakEZ200, “Kodak EZ200″},
    {MaxellMaxPocket, “Maxell Max Pocket LEdit. 1.3 MPixels”},
    {AiptekMiniPenCam2, “Aiptek Mini PenCam  2 MPixels”},
    {AiptekPocketDVII, “Aiptek PocketDVII  1.3 MPixels”},
    {AiptekPenCamSD, “Aiptek Pencam SD  2 MPixels”},
    {AiptekMiniPenCam13, “Aiptek mini PenCam 1.3 MPixels”},
    {MustekGsmartLCD3, “Mustek Gsmart LCD 3″},
    {MustekMDC5500Z, “Mustek MDC5500Z”},
    {MegapixV4, “Megapix V4″},
    {AiptekPocketDV, “Aiptek PocketDV “},
    {HamaUSBSightcam, “Hama USB Sightcam 100″},
    {Arowana300KCMOSCamera, “Arowana 300K CMOS Camera”},
    {MystFromOriUnknownCamera, “Unknow Ori Camera”},
    {AiptekPocketDV3100, “Aiptek PocketDV3100+ “},
    {AiptekPocketCam3M, “Aiptek PocketCam  3 M “},
    {GeniusVideoCAMExpressV2, “Genius VideoCAM Express V2″},
    {Flexcam100Camera, “Flexcam 100 Camera”},
    {MustekGsmartLCD2, “Mustek Gsmart LCD 2″},
    {PureDigitalDakota, “Pure Digital Dakota”},
    {PetCam, “PetCam”},
    {BenqDC1500, “Benq DC1500″},
    {LogitechClickSmart420, “Logitech Inc. ClickSmart 420″},
    {LogitechClickSmart510, “Logitech Inc. ClickSmart 510″},
    {BenqDC1300, “Benq DC1300″},
    {HamaUSBSightcam2, “Hama USB Sightcam 100 (2)”},
    {MustekDV3000, “Mustek DV 3000″},
    {CreativePccam750, “Creative PCcam750″},
    {MaxellCompactPM3, “Maxell Compact PC PM3″},
    {BenqDC3410, “Benq DC3410″},
    {BenqDC1016, “Benq DC1016″},
    {MicroInnovationIC200, “Micro Innovation IC200″},
    {LogitechTraveler, “Logitech QuickCam Traveler”},
    {Flycam100Camera, “FlyCam Usb 100″},
    {UsbGrabberPV321c, “Usb Grabber PV321c”},
    {ADSInstantVCD, “ADS Instant VCD”},
    {Gsmartmini, “Mustek Gsmart Mini”},
    {Jenoptikjdc21lcd, “Jenoptik DC 21 LCD”},
    {LogitechClickSmart310, “Logitech ClickSmart 310″},
    {Terratec2move13, “Terratec 2 move 1.3″},
    {MustekDV4000, “Mustek DV4000 Mpeg4″},
    {AiptekDV3500, “Aiptek DV3500 Mpeg4″},
    {LogitechClickSmart820, “Logitech ClickSmart 820″},
    {Enigma13, “Digital Dream Enigma 1.3″},
    {Sonix6025, “Xcam Shanga”},
    {Epsilon13, “Digital Dream Epsilon 1.3″},
    {Nxultra, “Creative Webcam NX ULTRA”},
    {AiptekPocketCam2M, “Aiptek PocketCam 2Mega”},
    {DeMonUSBCapture, “3DeMON USB Capture”},
    {CreativeVista, “Creative Webcam Vista”},
    {PolaroidPDC2030, “Polaroid PDC2030″},
    {CreativeNotebook, “Creative Notebook PD1171″},
    {CreativeMobile, “Creative Mobile PD1090″},
    {LabtecPro, “Labtec Webcam Pro”},
    {MustekWcam300A, “Mustek Wcam300A”},
    {GeniusVideoCamV2, “Genius Videocam V2″},
    {GeniusVideoCamV3, “Genius Videocam V3″},
    {GeniusVideoCamExpressV2b, “Genius Videocam Express V2 Firmware 2″},
    {CreativeNxPro, “Creative Nx Pro”},
    {Sonix6029, “Sonix sn9c10x + Pas106 sensor”},
    {Vimicro, “Z-star Vimicro zc0301p”},……

最后一行,看见了么?这就说明这款芯片是直接能被驱动所支持的。如果读者不幸用了一款没有在这个列表中出现的摄像头怎么办?那就只好自己加进去了,然后参考和你的摄像头相类似的产品。

 

根目录下有很多相应芯片的文件夹,我们自然是进Vimicro了,进去后找到zc3xx.h,和我们的芯片所有相关的设置和操作都在这个文件里了,好了,我们赶紧打开看看吧。打开后,我们发现很多可以设置参数的函数,比如可以设置brightness, contrast, colors, autobright等等,但是这些函数大多数都不需要更改,除非有什么特殊需求,惟一可能需要关心一下的就是jpeg的压缩率。大家都知道zc301p可以直接产生出jpeg流,那么设置压缩率就显得十分重要。gspca中主要由zc3xx_setquality函数来设置压缩率,你可以通过在zc3xx_config函数里设置spca50x->qindex来实现,默认值为1。

接下来我们一起来看看gspca中最重要的解压缩的部分。在根目录下有个decoder文件夹,里面比较重要的文件是gspcadecoder.c,让我们来看一下。

它在开头分别定义了JPEG头的长度:

#define JPEGHEADER_LENGTH 589

JPEG头:

const unsigned char JPEGHeader[JPEGHEADER_LENGTH] = {
    0xff, 0xd8, 0xff, 0xdb, 0×00, 0×84, 0×00, 0×06, 0×04, 0×05, 0×06,
    0×05, 0×04, 0×06, 0×06, 0×05,
    0×06, 0×07, 0×07, 0×06, 0×08, 0×0a, 0×10, 0×0a, 0×0a, 0×09, 0×09,
    0×0a, 0×14, 0×0e, 0×0f, 0×0c,
    0×10, 0×17, 0×14, 0×18, 0×18, 0×17, 0×14, 0×16, 0×16, 0×1a, 0×1d,
    0×25, 0×1f, 0×1a, 0×1b, 0×23,……

哈夫曼表:

#define GSMART_JPG_HUFFMAN_TABLE_LENGTH 0×1A0

const unsigned char GsmartJPEGHuffmanTable[GSMART_JPG_HUFFMAN_TABLE_LENGTH]
    = {
    0×00, 0×00, 0×01, 0×05, 0×01, 0×01, 0×01, 0×01, 0×01, 0×01, 0×00,
    0×00, 0×00, 0×00, 0×00, 0×00,
    0×00, 0×00, 0×01, 0×02, 0×03, 0×04, 0×05, 0×06, 0×07, 0×08, 0×09,
    0×0A, 0×0B, 0×01, 0×00, 0×03,
    0×01, 0×01, 0×01, 0×01, 0×01, 0×01, 0×01, 0×01, 0×01, 0×00, 0×00,
    0×00, 0×00, 0×00, 0×00, 0×01,……

量化表:

const unsigned char GsmartQTable[][64] = {

    //index0,Q40
    {
     20, 14, 15, 18, 15, 13, 20, 18, 16, 18, 23, 21, 20, 24, 30, 50,
     33, 30, 28, 28, 30, 61, 44, 46, 36, 50, 73, 64, 76, 75, 71, 64,
     70, 69, 80, 90, 115, 98, 80, 85, 109, 86, 69, 70, 100, 136, 101,
     109,……

熟悉JPEG编解码的朋友肯定知道这些都是组成一张JPEG图片的必备信息,关于JPEG笔者就不在这里详细阐述了。

int spca50x_outpicture(struct spca50x_frame *myframe)

这个函数是输出图片的接口,它会根据原数据流的格式和你所要求的输出格式来进行相应的处理,比如:

case JPGH:
    width = (myframe->data[10] << 8) | myframe->data[11];
    height = (myframe->data[12] << 8) | myframe->data[13];
    PDEBUG(1, “Decoder find WidthxHeight %dx%d”, width,height);
    /* some camera did not respond with the good height ie:Labtec Pro 240 -> 232 */
    if (myframe->hdrwidth != width)
        done = ERR_CORRUPTFRAME;
    else {
        // reset info.dri
        myframe->decoder->info.dri = 0;
        memcpy(myframe->tmpbuffer, myframe->data + 16,
           myframe->scanlength - 16);
        if (myframe->format == VIDEO_PALETTE_JPEG)
        done = make_jpeg(myframe);
        else
        done = jpeg_decode422(myframe, bgr);
    }
    break;

这就是zc301p要进入的处理分支,myframe->cameratype是原始数据的格式,myframe->format是输出数据的格式。我们可以看到,如果是JPEG的话那么就执行make_jpeg,否则就执行jpeg_decode422。

接下来我们主要来分析一下make_jpeg函数:

static int make_jpeg(struct spca50x_frame *myframe)
{
    __u8 *start;
    int i;
    __u8 value;
    int width = myframe->hdrwidth;
    int height = myframe->hdrheight;
    long inputsize = myframe->scanlength;
    __u8 *buf = myframe->tmpbuffer;
    __u8 *dst = myframe->data;                     //这个是原始数据的地址
    start = dst;
    /* 设置默认的JPEG头 */
    memcpy(dst, JPEGHeader, JPEGHEADER_LENGTH);
    /* 设置量化表 */
    *(dst + 6) = 0;
    memcpy(dst + 7, myframe->decoder->quant[0], 64);
    *(dst + 7 + 64) = 1;
    memcpy(dst + 8 + 64, myframe->decoder->quant[1], 64);

    *(dst + 564) = width & 0xFF;    //图片宽的低字节位
    *(dst + 563) = width >> 8 & 0xFF;    //图片宽的高字节位
    *(dst + 562) = height & 0xFF;    //图片高的低字节位
    *(dst + 561) = height >> 8 & 0xFF;    //图片宽的高字节位
    /* 设置图片格式 */
    if (myframe->cameratype == JPEG) {
    *(dst + 567) = 0×22;
    dst += JPEGHEADER_LENGTH;
    for (i = 0; i < inputsize; i++) {
        value = *(buf + i) & 0xFF;
        *dst = value;
        dst++;
        if (value == 0xFF) {
        *dst = 0;
        dst++;
        }
    }
    } else {
    *(dst + 567) = 0×21;
    dst += JPEGHEADER_LENGTH;
    memcpy(dst, buf, inputsize);
    dst += inputsize;
    }
    /* 增加JPEG结尾标志 */
    *(dst++) = 0xFF;
    *(dst++) = 0xD9;
    myframe->scanlength = (long) (dst - start);
    return 0;
}

好了,这样,一个JPEG文件就可以成功的输出了!

抱歉!评论已关闭.