您的位置:首页 > 移动开发 > Android开发

基于avd7181c解决视频输入效果差的问题<四>---android显示相关实现调试手记

2013-03-03 12:24 1016 查看
基于avd7181c解决视频输入效果差的问题<四>---android显示相关实现调试手记
 
         笔者在前几篇文章中提到的都是AVD7181C的信号通过CSI的数据通道,然后给camera APK来显示,就可以看到YPBPR\CVBS的输入信号了。利用camera
apk调试AVD7181C也是为了加快调试进度,笔者在实践中确实感觉很有益。通过它,我们可以先把AVD7181C以及CSI的驱动先调试稳定下来,调试正确,确保数据到应用之前是正确的,但是最终我们是要作产品,总不能用camera的apk来看这种视频输入的图像,从理论上当然也可以通过改造camera
apk来控制ui显示,但是这样也会比较麻烦,因为系统本身还需要camera apk,因为有真正的camera也在系统中。那怎么办呢?

        从HAL layer到应用重新做一套,这个工作量会有一点,主要是在硬件抽象层的代码设计上。还好全志平台提供了TVD的一套东西。笔者就可以模仿这一套东西来做,这样也省了不少事情,当然硬件抽象层是跟硬件打交道的,TVD跟CSI还是不大一样的,设置的参数、fmt这些会很大不同,因为硬件驱动是不一样的,全志TVD驱动做得不是很标准,代码写得比较乱,CSI那边的驱动做得要好一些。

        借鉴TVD的框架是可以的,稍微改动一些可以为我所用。笔者同样也借鉴了Camera硬件抽象层的代码实现,两种合理结合一些,这是就成了,当然还得加入一些里面没有实现的东西。

/*****************************************************************************************************/
声明:本博内容均由http://blog.csdn.net/sundesheng125原创,转载请注明出处,谢谢!
/*****************************************************************************************************/
        首先来看一下总得初始化接口实现,里面是先打开设备,在打开设备里面会设置输入视频源,查询视频设备驱动能力,紧接着设置视频模式,是V4L2_MODE_VIDEO的,再来设置video的参数,比如宽高、pixel的格式、filed等,然后再申请buffer,绑定匹配buffer地址,最后就是启动视频设备数据流,整个设备就工作起了。代码具体如下:

 

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数据接口类型等,代码示例如下:

  

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;
}
}

要设置video的参数;

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,监测代码如下:

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使用率非常低,这样主芯片可以干很多其他的事情。代码如下:

int hight = 0;
hight = (mOldSystem == 0)? 480:576;
LOGV("mOldSystem = %d, hight =%d\n", mOldSystem, hight);
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;
}
....
 /*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;
 overlay_para.number  = 0;
 if (mOverlayFirstFrame)
 {
  LOGD("first frame true");
  overlay_para.first_frame_flg = 1;
  mOverlayFirstFrame = false;
 }
 else
 {
  overlay_para.first_frame_flg = 0;
 }
 ret = mPreviewWindow->perform(mPreviewWindow, NATIVE_WINDOW_SETPARAMETER, HWC_LAYER_SETFRAMEPARA, (uint32_t)&overlay_para);
 if (ret != OK)
 {
  LOGE("NATIVE_WINDOW_SETPARAMETER failed");
  return ret;

        HWC_FORMAT_YUV422PLANAR_UV_COMBINED是笔者自定义的格式,全志平台里没有做这种格式,在hwc的硬件抽象层里需要添加需相应的代码实现,贴一部分如下:

case HWC_FORMAT_YUV422PLANAR_UV_COMBINED:
disp_format = DISP_FORMAT_YUV422;
fb_mode = DISP_MOD_NON_MB_UV_COMBINED;
disp_seq = DISP_SEQ_UYVY;
break;

      当然,以后如果要做录像的话,就需要把数据帧截下来,通过多媒体那边的库来压缩编码存文件,这个工作可以参考camera里面的实现。硬件抽象层的代码就差不多了。JNI以及应用APK,都可以再TVD上稍微改改,难度不大,这里就不再详述。贴一张整个实现后的应用截图吧!



 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐