#include <linux/videodev2.h>
#include "linphonec.h"
#include "H264.h"
#define VIDEO_DEV "/dev/fimc0"
#define FRAME_MAX_SIZE 1500 /*buffer size:1500 Bytes */
static bool_t find_start_code(unsigned char*buf)
{
if( (buf[0] == 0)&&
(buf[1] == 0)&&
(buf[2] == 0)&&
(buf[3] == 1))
{
return TRUE;
}
else
return FALSE;
}
static bool_t v4lv2_try_format(int drv_fd, struct v4l2_format *fmt, int fmtid){
fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt->fmt.pix.pixelformat = fmtid;
fmt->fmt.pix.field = V4L2_FIELD_ANY;
if (ioctl (drv_fd, VIDIOC_TRY_FMT, fmt)<0){
printf("VIDIOC_TRY_FMT\n");
return FALSE;
}
if (ioctl (drv_fd, VIDIOC_S_FMT, fmt)<0){
printf("VIDIOC_S_FMT\n");
return FALSE;
}
return TRUE;
}
static int msv4l2_configure(int drv_fd){
struct v4l2_capability cap;
struct v4l2_format fmt;
DEBUG("msv4l2_configure");
if (ioctl (drv_fd, VIDIOC_QUERYCAP, &cap)<0) {
printf("Not a v4lv2 driver.");
return -1;
}
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
printf("not a video capture device\n");
return -1;
}
if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
printf("%s does not support streaming i/o\n");
return -1;
}
printf("Driver is %s",cap.driver);
memset(&fmt,0,sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (drv_fd, VIDIOC_G_FMT, &fmt)<0){
printf("VIDIOC_G_FMT failed: %s",strerror(errno));
}
fmt.fmt.pix.width = WIDTH;
fmt.fmt.pix.height = HEIGHT;
v4lv2_try_format(drv_fd,&fmt,V4L2_PIX_FMT_YUV420);
return 0;
}
static int Video_do_mmap(video_stream_t *video_stream){
struct v4l2_requestbuffers req;
int i;
enum v4l2_buf_type type;
DEBUG("Video_do_mmap");
memset(&req,0,sizeof(req));
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
DEBUG("v4l2 request buf count is %d",req.count);
if (ioctl (video_stream->drv_fd, VIDIOC_REQBUFS, &req)<0) {
printf("Error requesting info on mmap'd buffers: %s",strerror(errno));
return -1;
}
for (i=0; i<req.count; ++i) {
struct v4l2_buffer buf;
void *start;
memset(&buf,0,sizeof(buf));
buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory=V4L2_MEMORY_MMAP;
buf.index=i;
DEBUG("get fram buf info index %d",i);
if (ioctl (video_stream->drv_fd, VIDIOC_QUERYBUF, &buf)<0){
printf("Could not VIDIOC_QUERYBUF : %s",strerror(errno));
return -1;
}
start=mmap (NULL /* start anywhere */,
buf.length,
PROT_READ | PROT_WRITE /* required */,
MAP_SHARED /* recommended */,
video_stream->drv_fd, buf.m.offset);
if (start==NULL){
printf("Could not mmap: %s\n",strerror(errno));
}
video_stream->frames[i].b_rptr=start;
video_stream->frames[i].len=buf.length;
video_stream->frames[i].db_ref=0;
}
video_stream->frame_max=req.count;
for (i = 0; i < video_stream->frame_max; ++i) {
struct v4l2_buffer buf;
memset(&buf,0,sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
DEBUG("put buf to queue index is %d",buf.index);
if (-1==ioctl (video_stream->drv_fd, VIDIOC_QBUF, &buf)){
printf("VIDIOC_QBUF failed: %s",strerror(errno));
}else {
video_stream->frames[i].db_ref++;
video_stream->queued++;
}
}
/*start capture immediately*/
DEBUG("start capture");
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 ==ioctl (video_stream->drv_fd, VIDIOC_STREAMON, &type)){
printf("VIDIOC_STREAMON failed: %s",strerror(errno));
return -1;
}
return 0;
}
static void msv4l2_do_munmap(video_stream_t *video_stream){
int i;
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 ==ioctl (video_stream->drv_fd, VIDIOC_STREAMOFF, &type)){
printf("VIDIOC_STREAMOFF failed: %s",strerror(errno));
}
for(i=0;i<video_stream->frame_max;++i){
if (munmap(video_stream->frames[i].b_rptr,video_stream->frames[i].len)<0){
printf("MSV4l2: Fail to unmap: %s",strerror(errno));
}
video_stream->frames[i].b_rptr = NULL;
video_stream->frames[i].db_ref = 0;
video_stream->frames[i].len= 0;
}
}
static frame_t *v4l2_dequeue_ready_buffer(video_stream_t *video_stream, int poll_timeout_ms){
struct v4l2_buffer buf;
frame_t *ret=NULL;
fd_set fds;
struct timeval tv;
tv.tv_sec = poll_timeout_ms / 1000;
tv.tv_usec = 1000 * (poll_timeout_ms % 1000);
memset(&buf,0,sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
FD_ZERO (&fds);
FD_SET (video_stream->drv_fd, &fds);
if(select (video_stream->drv_fd + 1, &fds, NULL, NULL, &tv)){
if (ioctl(video_stream->drv_fd, VIDIOC_DQBUF, &buf)<0) {
printf("v4l2 do VIDIOC_DQBUF fail to grap image\n");
switch (errno) {
case EAGAIN:
case EIO:
break;
default:
printf("VIDIOC_DQBUF failed: %s\n",strerror(errno));
}
}else{
video_stream->queued--;
ret = &video_stream->frames[buf.index];
if (buf.index >= video_stream->frame_max){
printf("buf.index>=s->max_frames !\n");
return NULL;
}
video_stream->frames[buf.index].db_ref--;
}
}
return ret;
}
static frame_t * Video_grab_image(video_stream_t *video_stream, int poll_timeout_ms){
struct v4l2_buffer buf;
unsigned int k;
memset(&buf,0,sizeof(buf));
frame_t *ret=NULL;
DEBUG("Video_grab_image");
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
for(k=0;k<video_stream->frame_max;++k){
if (video_stream->frames[k].db_ref==0){
buf.index=k;
if (-1==ioctl (video_stream->drv_fd, VIDIOC_QBUF, &buf))
printf("VIDIOC_QBUF %i failed: %s\n",k, strerror(errno));
else {
video_stream->frames[k].db_ref++;
video_stream->queued++;
}
}
}
if (video_stream->queued){
ret=v4l2_dequeue_ready_buffer(video_stream,poll_timeout_ms);
}
return ret;
}
void * Video_snd_thread(void *arg)
{
unsigned char *encoded_buf;
long encoded_size;
int snd_socket,ret;
struct sockaddr_in remote;
video_stream_t *video_stream = (video_stream_t *)arg;
LinphoneCore *lc = (LinphoneCore *)video_stream->lc;
call_t *call = lc->call;
sal_t *sal = &lc->sal;
DEBUG("Video_snd_thread");
if ((video_stream->drv_fd = open(VIDEO_DEV, O_RDWR)) < 0)
{
printf("Could not open %s",VIDEO_DEV);
return;
}
if(msv4l2_configure(video_stream->drv_fd) != 0)
{
printf("Could not configure %s",VIDEO_DEV);
goto end;
}
if (Video_do_mmap(video_stream)!=0)
{
printf("video do mmap fail\n");
goto end;
}
if ((video_stream->enc = mfc_encoder_init(WIDTH,HEIGHT, 25, 1000, 25)) == NULL)
{
printf("Could not open encoders\n");
goto end;
}
video_stream->enc_inbuf= (unsigned char*)SsbSipH264EncodeGetInBuf(video_stream->enc, 0);
snd_socket = socket(PF_INET, SOCK_DGRAM, 0);
if(snd_socket <= 0)
{
printf("Audio_send_thread ::create sal socket fail\n");
goto end;
}
fcntl (snd_socket, F_SETFL, O_NONBLOCK);
remote.sin_family = PF_INET;
remote.sin_port = htons(sal->video_port);
remote.sin_addr.s_addr = call->addr;
while(video_stream->running)
{
frame_t *m;
m=Video_grab_image(video_stream,40);
video_stream->frame_cnt++;
if(video_stream->frame_cnt == 1)
encoded_buf = (unsigned char*)mfc_encoder_exe(video_stream->enc, m->b_rptr, (WIDTH)*(HEIGHT)*3/2, 1, &encoded_size,video_stream->enc_inbuf);
else
encoded_buf = (unsigned char*)mfc_encoder_exe(video_stream->enc, m->b_rptr, (WIDTH)*(HEIGHT)*3/2, 0, &encoded_size,video_stream->enc_inbuf);
while(encoded_size > DEFAULT_MAX_PAYLOAD_SIZE){
ret = sendto(snd_socket, (char *)encoded_buf, DEFAULT_MAX_PAYLOAD_SIZE, 0,
(struct sockaddr *) &remote, sizeof(struct sockaddr_in));
if(ret >