当前位置:操作系统 > 安卓/Android >>

android显示相关实现调试手记

 首先来看一下总得初始化接口实现,里面是先打开设备,在打开设备里面会设置输入视频源,查询视频设备驱动能力,紧接着设置视频模式,是V4L2_MODE_VIDEO的,再来设置video的参数,比如宽高、pixel的格式、filed等,然后再申请buffer,绑定匹配buffer地址,最后就是启动视频设备数据流,整个设备就工作起了。代码具体如下:
 
 
 
[cpp] 
status_t CCSIDecoderHardware::v4l2Init(int mOldSystem)  
{  
    F_LOG;  
  
    CHECK_ERROR(openCameraDev());  
          
    // set capture mode  
    struct v4l2_streamparm params;  
        params.parm.capture.timeperframe.numerator = 1;  
    params.parm.capture.timeperframe.denominator = 25;  
    params.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
    params.parm.capture.capturemode = V4L2_MODE_VIDEO;//V4L2_MODE_IMAGE  
  
    v4l2setCaptureParams(¶ms);  
  
    // set v4l2 device parameters  
    CHECK_ERROR(v4l2SetVideoParams(mOldSystem));  
      
    // v4l2 request buffers  
    CHECK_ERROR(v4l2ReqBufs());  
      
    // v4l2 query buffers  
    CHECK_ERROR(v4l2QueryBuf());  
      
    // stream on the v4l2 device  
    CHECK_ERROR(v4l2StartStreaming());  
  
    return OK;  
}  
       笔者移植了tryFmt()这个用来寻找对应的fmt,会有一下参数关联,比如输入CSI的fmt格式,CSI输出数据格式、CSI数据接口类型等,代码示例如下:
 
  
 
[cpp] 
struct v4l2_fmtdesc fmtdesc;  
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
for(int i = 0; i < 12; i++)  
{  
    fmtdesc.index = i;  
    if (-1 == ioctl (mV4l2Handle, VIDIOC_ENUM_FMT, &fmtdesc))  
    {  
        break;  
    }  
    LOGV("format index = %d, name = %s, v4l2 pixel format = %x\n",  
        i, fmtdesc.description, fmtdesc.pixelformat);  
  
    if (fmtdesc.pixelformat == format)  
    {  
        return OK;  
    }  
[cpp]  
}  
要设置video的参数;
 
[cpp] 
struct v4l2_format format;  
  
LOGD("#####################VIDIOC_S_PARM\n");  
memset(&format, 0, sizeof(format));  
       format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;   
       format.fmt.pix.width  = mVideoWidth;   
       format.fmt.pix.height = mVideoHeight;   
       format.fmt.pix.pixelformat = mVideoFormat; //pix_fmt  
format.fmt.pix.field = V4L2_FIELD_NONE;  
  
ret = ioctl(mV4l2Handle, VIDIOC_S_FMT, &format);   
if (ret < 0)   
{   
    LOGE("VIDIOC_S_FMT Failed: %s", strerror(errno));   
    return ret;   
}   
      得起一个线程来负责读数据帧,以及把数据帧数据处理掉。在这个线程中还需要加入实时检测视频信号的有无,以及信号的制式,是NTSC还是PAL,监测代码如下:
 
[cpp] 
 struct v4l2_control ctrl;  
 ctrl.value = 0;  
 ctrl.id = V4L2_CID_BRIGHTNESS;/*just use this channel to read fmt & detect signals*/  
ret = ioctl (mV4l2Handle, VIDIOC_G_CTRL, &ctrl);   
if (ret < 0)    
{   
    LOGE("vidioc_g_ctrl: %s", strerror(errno));   
}   
  
LOGE("get_system ctrl.value 0x%02x", ctrl.value);   
 mDetectcvbsSignal = ((ctrl.value & 0x10) == 0x10)? 0:1 ;/*bit4 1:no signal 0: has signal*/  
      
 fmt = ctrl.value & 0x7;  
 if((0 == fmt) || (1 == fmt))  
     *__system = 0;/*NTSC*/  
else  
   *__system = 1;/*PAL*/  
       笔者在信号制式的处理上稍微做了一下变通,因为这两种制式在大小上是不一样,但是我们可以用大一点的那个buffer,这样我们就不需要重新去设置这些buffer,而只需要控制后面取buffer的数据大小就可以,这样也是简便了一下。同时,笔者在调试发现NTSC的制式上,开始会有是十几个像素高度的脏数据,显示是乱的,这样我用大buffer就可以把N制的整个数据都截下来,起始地址移动一下就可以了,这样确实真实有效,里面使用了native window的操作,直接把数据帧的buffer地址赋给了hwcoposer,也就是到内核里的硬件驱动里,这样就减少了数据拷贝的工作,cpu使用率非常低,这样主芯片可以干很多其他的事情。代码如下:
 
[cpp]  
int hight = 0;  
hight = (mOldSystem == 0)? 480:576;  
LOGV("mOldSystem = %d, hight =%d\n", mOldSystem, hight);  
[cpp] 
        ret = native_window_set_buffers_geometryex(mPreviewWindow ,  
           mVideoWidth,     hight,HWC_FORMAT_YUV422PLANAR_UV_COMBINED, //*/HWC_FORMAT_DEFAULT,HWC_FORMAT_YUV420PLANAR  
               0);                            
        if (ret != NO_ERROR)   
        {  
            LOGE("%s: Error in set_buffers_geometry %d -> %s",__FUNCTION__, -ret, strerror(-ret));  
            return ret;  
        }  
....  
    <p> /*when NTSC shoud shift display buffer*/  
 overlay_para.bProgressiveSrc = 0;  
 overlay_para.bTopFieldFirst = 1;  
 overlay_para.pVideoInfo.frame_rate = 25000;  
 if(1 == mOldSystem) {/*PAL*/  
  overlay_para.top_y   = (unsigned int)buf.m.offset;  
   overlay_para.top_c   = (unsigned int)buf.m.offset +  mVideoWidth * mVideoHeight;  
 } else {/*NTSC*/  
   overlay_para.top_y   = (unsigned int)buf.m.offset+ 1440;/* 720*20 20 point*/  
   overlay_para.top_c   = (unsigned int)buf.m.offset +  mVideoWidth * mVideoHeight+7200;/* 720*20*1/2 20 point*/    
 }  
 overlay_para.bottom_y  = 0;  
 overlay_para.bottom_c  = 0; &
补充:移动开发 , Android ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,