int EncoderMFC::Initialize(int width, int height,int codec,float rate,int bitrate,int in_bufs,int out_bufs, int stream_b_size){ if(state!=MFC_ST_OPEN) return -1; if(SetFormat(width,height)<0) return -1; if(SetCodec(codec,stream_b_size)<0) return -1; SetRate(rate); if(bitrate>0) SetBitRate(bitrate); if(InitBuffers(DIR_IN,in_bufs)<0) return -1; if(InitBuffers(DIR_OUT,out_bufs)<0) return -1; for (int bi=0;bi<out_bufs;bi++){ struct v4l2_buffer buf; struct v4l2_plane planes[MFC_MAX_PLANES]; buf.type = io_dir_to_type(DIR_OUT); buf.memory = V4L2_MEMORY_MMAP; buf.m.planes = planes; buf.length = NPPBuf[DIR_OUT]; buf.index=bi; for (u_int i = 0; i < NPPBuf[DIR_OUT]; i++){ planes[i].length=PlanesLen[DIR_OUT][i]; planes[i].bytesused=0; planes[i].m.userptr=(u_long)BufAddr[DIR_OUT][bi][i]; } int ret = ioctl(fd, VIDIOC_QBUF, &buf); if (ret != 0) { printf("\nEncoderMFC: Init, Queue buffer %d error! %s\n",buf.index,strerror(errno)); } } BufInx[DIR_OUT]=0; state=MFC_ST_OK; return 0; }
int EncoderMFC::PopFrame(char *stream_buf,int b_size) { struct v4l2_buffer buf; struct v4l2_plane planes[NPPBuf[DIR_OUT]]; int ret; memzero(buf); buf.type = io_dir_to_type(DIR_OUT); buf.memory = V4L2_MEMORY_MMAP; buf.m.planes = planes; buf.length = NPPBuf[DIR_OUT]; buf.index=BufInx[DIR_OUT]; ret = ioctl(fd, VIDIOC_DQBUF, &buf); if (ret != 0) { printf("\nEncoderMFC: Pop, Dequeue buffer %d error, %s!\n",buf.index,strerror(errno)); return -1; } BufInx[DIR_OUT]=buf.index; if(BufInx[DIR_OUT]>=NBufs[DIR_OUT]){ printf("\nEncoderMFC: Pop, Index error!\n"); return -1; } if(buf.m.planes[0].bytesused>b_size){ printf("\nEncoderMFC: Pop, Buffer %d overrun %d error!",buf.index,buf.m.planes[0].bytesused); }else{ b_size=buf.m.planes[0].bytesused; } memcpy(stream_buf,BufAddr[DIR_OUT][buf.index][0],b_size); //printf("\nEncoderMFC: Enc frame %d,%d\n",buf.m.planes[0].bytesused,BufInx[DIR_OUT]); ret = ioctl(fd, VIDIOC_QBUF, &buf); if (ret != 0) { printf("\nEncoderMFC: Pop, Queue buffer %d error! %s\n",BufInx[DIR_OUT],strerror(errno)); return -1; } //BufInx[DIR_OUT]++; return b_size; }
int mfc_set_codec(struct io_dev *dev, enum io_dir dir, int codec) { struct v4l2_format fmt; int ret; memzero(fmt); fmt.type = io_dir_to_type(dir); fmt.fmt.pix_mp.pixelformat = codec; fmt.fmt.pix_mp.plane_fmt[0].sizeimage = MAX_STREAM_SIZE; ret = ioctl(dev->fd, VIDIOC_S_FMT, &fmt); return ret; }
int EncoderMFC::SetFormat(int width, int height) { v4l2_format fmt; int ret; this->width=width; this->height=height; memzero(fmt); fmt.type = io_dir_to_type(DIR_IN); fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M; fmt.fmt.pix_mp.width = width; fmt.fmt.pix_mp.height = height; BytesPerLine=align(width, 128); fmt.fmt.pix_mp.num_planes = 2; fmt.fmt.pix_mp.plane_fmt[0].bytesperline = BytesPerLine; fmt.fmt.pix_mp.plane_fmt[0].sizeimage = align(BytesPerLine * height, 2048); fmt.fmt.pix_mp.plane_fmt[1].bytesperline = BytesPerLine; fmt.fmt.pix_mp.plane_fmt[1].sizeimage = align(BytesPerLine * (height / 2),2048); printf("\nEncoderMFC: bpl = %d,%d \n",BytesPerLine,fmt.fmt.pix_mp.plane_fmt[0].sizeimage); ret = ioctl(fd, VIDIOC_S_FMT, &fmt); if (ret != 0){ printf("\nEncoderMFC: Cannot set format!\n"); state=MFC_ST_ERROR; return -1; } ret = ioctl(fd, VIDIOC_G_FMT, &fmt); if (ret != 0){ printf("\nEncoderMFC: Cannot check format!\n"); state=MFC_ST_ERROR; return -1; } BytesPerLine=fmt.fmt.pix_mp.plane_fmt[0].bytesperline; printf("\nEncoderMFC: get bpl = %d,%d \n",BytesPerLine,fmt.fmt.pix_mp.plane_fmt[1].bytesperline); return ret; }
int EncoderMFC::SetCodec(int codec,int stream_b_size) { v4l2_format fmt; int ret; memzero(fmt); fmt.type = io_dir_to_type(DIR_OUT); fmt.fmt.pix_mp.pixelformat = codec; fmt.fmt.pix_mp.plane_fmt[0].sizeimage = stream_b_size; ret = ioctl(fd, VIDIOC_S_FMT, &fmt); if (ret != 0){ printf("\nEncoderMFC: Cannot set codec!\n"); state=MFC_ST_ERROR; } return ret; }
int EncoderMFC::ReqBufs(MFC_io_dir dir, int nbuf) { int ret; struct v4l2_requestbuffers reqbuf; memzero(reqbuf); reqbuf.count = nbuf; reqbuf.type = io_dir_to_type(dir); reqbuf.memory = V4L2_MEMORY_MMAP; ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuf); if (ret != 0) { printf("\nEncoderMFC: Failed to request %d buffers for %s device\n", nbuf, dir==DIR_IN?"Input":"Output"); state=MFC_ST_ERROR; return -1; } printf("\nEncoderMFC: Succesfully requested %d buffers for %s device\n", nbuf, dir==DIR_IN?"Input":"Output"); return reqbuf.count; }
/* set format with proper alignement */ int mfc_set_fmt(struct io_dev *dev, enum io_dir dir, int width, int height) { struct v4l2_format fmt; int ret; memzero(fmt); fmt.type = io_dir_to_type(dir); fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M; fmt.fmt.pix_mp.width = width; fmt.fmt.pix_mp.height = height; fmt.fmt.pix_mp.num_planes = 2; fmt.fmt.pix_mp.plane_fmt[0].bytesperline = align(width, 128); fmt.fmt.pix_mp.plane_fmt[0].sizeimage = align(width * height, 2048); fmt.fmt.pix_mp.plane_fmt[1].bytesperline = align(width, 128); fmt.fmt.pix_mp.plane_fmt[1].sizeimage = align(width * (height / 2), 2048); ret = ioctl(dev->fd, VIDIOC_S_FMT, &fmt); if (ret != 0) err("Cannot set format on %d:%d", dev->fd, dir); return ret; }
/* enqueue buffer, start stream when needed */ int EncoderMFC::PushFrame(union RGB24Pixel *data) { struct v4l2_buffer buf; struct v4l2_plane planes[MFC_MAX_PLANES]; int ret; memzero(buf); buf.index=(BufInx[DIR_IN]); buf.type = io_dir_to_type(DIR_IN); buf.memory = V4L2_MEMORY_MMAP; buf.m.planes = planes; buf.length = NPPBuf[DIR_IN]; float Y,Cr,Cb; for(int y=0,i=0;y<height;y++,i+=BytesPerLine-width){ for(int x=0;x<width;x++,i++){ Y=(0.299 * (float)data[i].pix.r) + (0.587 * (float)data[i].pix.g) + (0.114 * (float)data[i].pix.b); ((unsigned char *)(BufAddr[DIR_IN][buf.index][0]))[i] = Y; } } planes[0].bytesused=height*BytesPerLine; planes[0].length = PlanesLen[DIR_IN][0]; planes[0].m.userptr = (u_long)BufAddr [DIR_IN][buf.index][0]; for(int y=0,i=0,j=0;y<height/2;y++,i+=width,j+=BytesPerLine-width){ for(int x=0;x<width;x+=2,i+=2,j+=2){ float r,g,b; r=(data[i].pix.r+data[i+1].pix.r+data[i+width].pix.r+data[i+width+1].pix.r)/4.0; g=(data[i].pix.g+data[i+1].pix.g+data[i+width].pix.g+data[i+width+1].pix.g)/4.0; b=(data[i].pix.b+data[i+1].pix.b+data[i+width].pix.b+data[i+width+1].pix.b)/4.0; Cr = (0.5 * r) - (0.4186 * g) - (0.08131 * b); Cb =-(0.1687 * r) - (0.3312 * g) + (0.5 * b); Cr+=128.0; Cb+=128.0; ((unsigned char *)(BufAddr[DIR_IN][buf.index][1]))[j+1] = Cr; ((unsigned char *)(BufAddr[DIR_IN][buf.index][1]))[j] = Cb; } } planes[1].bytesused=height*BytesPerLine/2; planes[1].length = PlanesLen[DIR_IN][1]; planes[1].m.userptr = (u_long)BufAddr [DIR_IN][buf.index][1]; ret = ioctl(fd, VIDIOC_QBUF, &buf); if (ret != 0) { printf("\nEncoderMFC: Push, Queue buffer %d error!\n",BufInx[DIR_IN]); } if(state==MFC_ST_OK) StreamOn(true); if((++(BufInx[DIR_IN]))>=NBufs[DIR_IN]){ BufInx[DIR_IN]=0; } buf.index=(BufInx[DIR_IN]); buf.type = io_dir_to_type(DIR_IN); buf.memory = V4L2_MEMORY_MMAP; buf.m.planes = planes; buf.length = NPPBuf[DIR_IN]; ret = ioctl(fd, VIDIOC_DQBUF, &buf); if (ret != 0) { printf("\nEncoderMFC: Push, Dequeue buffer %d error! %s\n",BufInx[DIR_IN],strerror(errno)); return -1; } return 0; }
int EncoderMFC::InitBuffers(MFC_io_dir dir,int nbuf) { struct v4l2_buffer qbuf; int ret; v4l2_plane planes[MFC_MAX_PLANES]; if (ReqBufs(dir,nbuf) < 0) return -1; NBufs[dir]=nbuf; BufAddr[dir] = new void**[nbuf]; memzero(qbuf); qbuf.type = io_dir_to_type(dir); qbuf.memory = V4L2_MEMORY_MMAP; qbuf.m.planes = planes; qbuf.length = MFC_MAX_PLANES; for (int n = 0; n < nbuf; n++) { qbuf.index = n; ret = ioctl(fd, VIDIOC_QUERYBUF, &qbuf); if (ret != 0) { printf("\nEncoderMFC: QUERYBUF failed\n"); return -1; } if (n == 0) { int i; for (i = 0; i < qbuf.length; ++i) if (qbuf.m.planes[i].length == 0) break; NPPBuf[dir] = i; PlanesLen[dir]=new int[i]; for (i = 0; i < NPPBuf[dir]; ++i) PlanesLen[dir][i] = qbuf.m.planes[i].length; } BufAddr[dir][n] = new void*[NPPBuf[dir]]; for (int i = 0; i < NPPBuf[dir]; ++i) { BufAddr[dir][n][i] = (void *)mmap(NULL,qbuf.m.planes[i].length, PROT_READ | PROT_WRITE, MAP_SHARED, fd,\ qbuf.m.planes[i].m.mem_offset); if (BufAddr[dir][n][i] == MAP_FAILED) { printf("\nEncoderMFC: Failed mmap buffer %d for plane %d!\n", n,i); state=MFC_ST_ERROR; return -1; } } /*ret = in->ops->enq_buf(in, DIR_OUT, n); if (ret < 0) return -1;*/ } printf(" \nMFC Log: Dir = %d NB = %d \n",dir,NBufs[dir]); for(int i=0;i<NBufs[dir];i++){ printf("\nNPP = %d ",NPPBuf[dir]); for(int j=0;j<NPPBuf[dir];j++) printf(" PL = %d A = %lx ",PlanesLen[dir][j],(unsigned long)BufAddr[dir][i][j]); } printf("\n"); BufInx[dir]=0; return 0; }